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.

> +
> +    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 :|


Reply via email to