On Thu, Feb 5, 2026 at 9:30 PM Daniel P. Berrangé <[email protected]> wrote:
>
> On Thu, Feb 05, 2026 at 08:58:04PM +0100, Ruslan Ruslichenko wrote:
> > From: Ruslan Ruslichenko <[email protected]>
> >
> > Introduce main execution loop for the Remote Port protocol.
> > Creates a dedicated thread to manage the communication lifecycle.
> > This includes logic to read packets and manage RX queue.
> >
> > Patch also implements handshake logic to verify protocol
> > versions and negotiate capabilities with remote peer.
> >
> > Signed-off-by: Edgar E. Iglesias <[email protected]>
> > Signed-off-by: Takahiro Nakata <[email protected]>
> > Signed-off-by: Ruslan Ruslichenko <[email protected]>
> > ---
> >  hw/core/remote-port.c         | 190 ++++++++++++++++++++++++++++++++++
> >  include/hw/core/remote-port.h |  22 ++++
> >  2 files changed, 212 insertions(+)
> >
> > diff --git a/hw/core/remote-port.c b/hw/core/remote-port.c
> > index 5154c1bc2a..91b0682884 100644
> > --- a/hw/core/remote-port.c
> > +++ b/hw/core/remote-port.c
> > @@ -52,6 +52,88 @@
> >  #define REMOTE_PORT_CLASS(klass)    \
> >       OBJECT_CLASS_CHECK(RemotePortClass, (klass), TYPE_REMOTE_PORT)
> >
> > +static void rp_pkt_dump(const char *prefix, const char *buf, size_t len)
> > +{
> > +    qemu_hexdump(stdout, prefix, buf, len);
> > +}
> > +
> > +static void rp_fatal_error(RemotePort *s, const char *reason)
> > +{
> > +    error_report("%s: %s", s->prefix, reason);
> > +    exit(EXIT_FAILURE);
> > +}
> > +
> > +static ssize_t rp_recv(RemotePort *s, void *buf, size_t count)
> > +{
> > +    ssize_t r;
> > +
> > +    r = qemu_chr_fe_read_all(&s->chr, buf, count);
> > +    if (r <= 0) {
> > +        return r;
> > +    }
> > +    if (r != count) {
> > +        error_report("%s: Bad read, expected %zd but got %zd",
> > +                     s->prefix, count, r);
> > +        rp_fatal_error(s, "Bad read");
> > +    }
> > +
> > +    return r;
> > +}
> > +
> > +ssize_t rp_write(RemotePort *s, const void *buf, size_t count)
> > +{
> > +    ssize_t r;
> > +
> > +    qemu_mutex_lock(&s->write_mutex);
> > +    r = qemu_chr_fe_write_all(&s->chr, buf, count);
> > +    qemu_mutex_unlock(&s->write_mutex);
> > +    assert(r == count);
> > +    if (r <= 0) {
> > +        error_report("%s: Disconnected r=%zd buf=%p count=%zd",
> > +                     s->prefix, r, buf, count);
> > +        rp_fatal_error(s, "Bad write");
> > +    }
> > +    return r;
> > +}
> > +
> > +static void rp_cmd_hello(RemotePort *s, struct rp_pkt *pkt)
> > +{
> > +    s->peer.version = pkt->hello.version;
> > +    if (pkt->hello.version.major != RP_VERSION_MAJOR) {
> > +        error_report("remote-port version missmatch remote=%d.%d 
> > local=%d.%d",
> > +                      pkt->hello.version.major, pkt->hello.version.minor,
> > +                      RP_VERSION_MAJOR, RP_VERSION_MINOR);
> > +        rp_fatal_error(s, "Bad version");
> > +    }
> > +
> > +    if (pkt->hello.caps.len) {
> > +        void *caps = (char *) pkt + pkt->hello.caps.offset;
> > +
> > +        rp_process_caps(&s->peer, caps, pkt->hello.caps.len);
> > +    }
> > +}
> > +
> > +static void rp_say_hello(RemotePort *s)
> > +{
> > +    struct rp_pkt_hello pkt;
> > +    uint32_t caps[] = {
> > +        CAP_BUSACCESS_EXT_BASE,
> > +        CAP_BUSACCESS_EXT_BYTE_EN,
> > +        CAP_WIRE_POSTED_UPDATES,
> > +        CAP_ATS,
> > +    };
> > +    size_t len;
> > +
> > +    len = rp_encode_hello_caps(s->current_id++, 0, &pkt, RP_VERSION_MAJOR,
> > +                               RP_VERSION_MINOR,
> > +                               caps, caps, sizeof caps / sizeof caps[0]);
> > +    rp_write(s, (void *) &pkt, len);
> > +
> > +    if (sizeof caps) {
> > +        rp_write(s, caps, sizeof caps);
> > +    }
> > +}
> > +
> >  static char *rp_sanitize_prefix(RemotePort *s)
> >  {
> >      char *sanitized_name;
> > @@ -105,6 +187,108 @@ static Chardev *rp_autocreate_chardev(RemotePort *s, 
> > char *name)
> >      return chr;
> >  }
> >
> > +static bool rp_pt_process_pkt(RemotePort *s, RemotePortDynPkt *dpkt)
> > +{
> > +    struct rp_pkt *pkt = dpkt->pkt;
> > +
> > +    D(qemu_log("%s: cmd=%x id=%d dev=%d\n", __func__, pkt->hdr.cmd,
> > +             pkt->hdr.id, pkt->hdr.dev));
>
> This kind of thing feels better suited to being implement with
> QEMU tracepoints.
>

Agreed. I will replace the manual debug logging with standard QEMU
tracepoints in v2.

> > +
> > +    if (pkt->hdr.dev >= ARRAY_SIZE(s->devs)) {
> > +        /* FIXME: Respond with an error.  */
> > +        return true;
> > +    }
> > +
> > +    switch (pkt->hdr.cmd) {
> > +    case RP_CMD_hello:
> > +        rp_cmd_hello(s, pkt);
> > +        break;
> > +    case RP_CMD_read:
> > +    case RP_CMD_write:
> > +    case RP_CMD_interrupt:
> > +    case RP_CMD_ats_req:
> > +    case RP_CMD_ats_inv:
> > +        /* TBD */;
> > +        break;
> > +    default:
> > +        g_assert_not_reached();
> > +        break;
> > +    }
> > +    return false;
> > +}
>
> With regards,
> Daniel
> --
> |: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
> |: https://libvirt.org         -o-            https://fstop138.berrange.com :|
> |: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|
>

--
BR,
Ruslan

Reply via email to