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