From nobody Wed Nov 27 12:25:04 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) client-ip=192.237.175.120; envelope-from=xen-devel-bounces@lists.xenproject.org; helo=lists.xenproject.org; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org ARC-Seal: i=1; a=rsa-sha256; t=1699348983; cv=none; d=zohomail.com; s=zohoarc; b=abCnETglyQs+I1t7qYcPYHxDrX6RmB/C4cSgVwkJvExIBYl+kPn1GLHbUX/6jbD60eN86FaLogwFWp8vZu02Hm1iG1C1TrqFU+AItFDOof5739CTqGihqj2zm7vr3DzppNattrfTY2fXc6m9/+0SASrDn8Eedbhwwp8XeSDjqMs= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1699348983; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=IcBaGplpgRkAVCTqBdQEfMN5GwDsnTzqsXSXRTZbkSk=; b=lyevUw9TiVKL8uFBAyxiPFVrgmExl55d4ICM/dlAmxZH2pI8mChOQbJH6HQB/6ab1duJ/iFLZoW2/RSmk8eYz7TbjAkBpKmYgD3SEC9EbFqrgm0FxTJ/8Mp6MS9o4mzPFz8A7G/wQ5YVeQq8/+ZrBNzv1zlKeLWpKYP/6GAMSTo= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org Return-Path: Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) by mx.zohomail.com with SMTPS id 1699348983491520.6130423716726; Tue, 7 Nov 2023 01:23:03 -0800 (PST) Received: from list by lists.xenproject.org with outflank-mailman.628636.980342 (Exim 4.92) (envelope-from ) id 1r0IHx-0003b1-9j; Tue, 07 Nov 2023 09:22:25 +0000 Received: by outflank-mailman (output) from mailman id 628636.980342; Tue, 07 Nov 2023 09:22:25 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1r0IHx-0003Zx-2b; Tue, 07 Nov 2023 09:22:25 +0000 Received: by outflank-mailman (input) for mailman id 628636; Tue, 07 Nov 2023 09:22:23 +0000 Received: from se1-gles-flk1-in.inumbo.com ([94.247.172.50] helo=se1-gles-flk1.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1r0IHu-0001o6-Nm for xen-devel@lists.xenproject.org; Tue, 07 Nov 2023 09:22:22 +0000 Received: from casper.infradead.org (casper.infradead.org [2001:8b0:10b:1236::1]) by se1-gles-flk1.inumbo.com (Halon) with ESMTPS id 248043a1-7d4f-11ee-9b0e-b553b5be7939; Tue, 07 Nov 2023 10:22:16 +0100 (CET) Received: from [2001:8b0:10b:1::ebe] (helo=i7.infradead.org) by casper.infradead.org with esmtpsa (Exim 4.94.2 #2 (Red Hat Linux)) id 1r0IHN-00BPkR-UA; Tue, 07 Nov 2023 09:21:50 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.96.2 #2 (Red Hat Linux)) id 1r0IHO-001hKQ-03; Tue, 07 Nov 2023 09:21:50 +0000 X-Outflank-Mailman: Message body and most headers restored to incoming version X-BeenThere: xen-devel@lists.xenproject.org List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Errors-To: xen-devel-bounces@lists.xenproject.org Precedence: list X-Inumbo-ID: 248043a1-7d4f-11ee-9b0e-b553b5be7939 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=casper.20170209; h=Sender:Content-Transfer-Encoding: MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:Cc:To:From: Reply-To:Content-Type:Content-ID:Content-Description; bh=IcBaGplpgRkAVCTqBdQEfMN5GwDsnTzqsXSXRTZbkSk=; b=IZ1izr3ZEJI9LJhC2RCFdhabhS fl1rtJRxxX0qerXPNI8WnM9YN2J++OKmWKdOmnadq8QzfyI4A9jG3+XjKQJSKiNU5BFwcEuRExSVu bKBoWU51PUI0zL88M1qZSesJYrCnxaPwTKt1///b5nSGxAIMVFWbRqQ8FwHRg0ZZ7lyHXIu4MLktF 0Iz94o7c8PApVnndcOmwiQmIecJhfMcjJVjfdOnM10CoM3zdmzv3Lt0I4d0UIuptTqe0nMaPe/RYJ wAnni8lmqdQky+JjGY5+YWzGbCII6uAsxiYOqOm4X2pOGDyjieR0/rgvM8KieMkfn2++Ap6XjhPpl QkglfyVg==; From: David Woodhouse To: qemu-devel@nongnu.org, Stefan Hajnoczi Cc: Kevin Wolf , Hanna Reitz , Stefano Stabellini , Anthony Perard , Paul Durrant , =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= , Paolo Bonzini , "Michael S. Tsirkin" , Marcel Apfelbaum , Richard Henderson , Eduardo Habkost , Jason Wang , Marcelo Tosatti , qemu-block@nongnu.org, xen-devel@lists.xenproject.org, kvm@vger.kernel.org Subject: [PULL 09/15] hw/xen: update Xen console to XenDevice model Date: Tue, 7 Nov 2023 09:21:41 +0000 Message-ID: <20231107092149.404842-10-dwmw2@infradead.org> X-Mailer: git-send-email 2.41.0 In-Reply-To: <20231107092149.404842-1-dwmw2@infradead.org> References: <20231107092149.404842-1-dwmw2@infradead.org> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: David Woodhouse X-SRS-Rewrite: SMTP reverse-path rewritten from by casper.infradead.org. See http://www.infradead.org/rpr.html X-ZohoMail-DKIM: pass (identity @infradead.org) X-ZM-MESSAGEID: 1699348985515100004 Content-Type: text/plain; charset="utf-8" From: David Woodhouse This allows (non-primary) console devices to be created on the command line and hotplugged. Signed-off-by: David Woodhouse Reviewed-by: Paul Durrant --- hw/char/trace-events | 8 + hw/char/xen_console.c | 532 +++++++++++++++++++++++++++--------- hw/xen/xen-legacy-backend.c | 1 - 3 files changed, 411 insertions(+), 130 deletions(-) diff --git a/hw/char/trace-events b/hw/char/trace-events index babf4d35ea..7a398c82a5 100644 --- a/hw/char/trace-events +++ b/hw/char/trace-events @@ -105,3 +105,11 @@ cadence_uart_baudrate(unsigned baudrate) "baudrate %u" # sh_serial.c sh_serial_read(char *id, unsigned size, uint64_t offs, uint64_t val) " %s = size %d offs 0x%02" PRIx64 " -> 0x%02" PRIx64 sh_serial_write(char *id, unsigned size, uint64_t offs, uint64_t val) "%s = size %d offs 0x%02" PRIx64 " <- 0x%02" PRIx64 + +# xen_console.c +xen_console_connect(unsigned int idx, unsigned int ring_ref, unsigned int = port, unsigned int limit) "idx %u ring_ref %u port %u limit %u" +xen_console_disconnect(unsigned int idx) "idx %u" +xen_console_unrealize(unsigned int idx) "idx %u" +xen_console_realize(unsigned int idx, const char *chrdev) "idx %u chrdev %= s" +xen_console_device_create(unsigned int idx) "idx %u" +xen_console_device_destroy(unsigned int idx) "idx %u" diff --git a/hw/char/xen_console.c b/hw/char/xen_console.c index 810dae3f44..4a419dc287 100644 --- a/hw/char/xen_console.c +++ b/hw/char/xen_console.c @@ -20,15 +20,20 @@ */ =20 #include "qemu/osdep.h" +#include "qemu/cutils.h" #include #include =20 #include "qapi/error.h" #include "sysemu/sysemu.h" #include "chardev/char-fe.h" -#include "hw/xen/xen-legacy-backend.h" - +#include "hw/xen/xen-backend.h" +#include "hw/xen/xen-bus-helper.h" +#include "hw/qdev-properties.h" +#include "hw/qdev-properties-system.h" #include "hw/xen/interface/io/console.h" +#include "hw/xen/interface/io/xs_wire.h" +#include "trace.h" =20 struct buffer { uint8_t *data; @@ -39,16 +44,22 @@ struct buffer { }; =20 struct XenConsole { - struct XenLegacyDevice xendev; /* must be first */ + struct XenDevice xendev; /* must be first */ + XenEventChannel *event_channel; + int dev; struct buffer buffer; - char console[XEN_BUFSIZE]; - int ring_ref; + char *fe_path; + unsigned int ring_ref; void *sring; CharBackend chr; int backlog; }; +typedef struct XenConsole XenConsole; + +#define TYPE_XEN_CONSOLE_DEVICE "xen-console" +OBJECT_DECLARE_SIMPLE_TYPE(XenConsole, XEN_CONSOLE_DEVICE) =20 -static void buffer_append(struct XenConsole *con) +static bool buffer_append(XenConsole *con) { struct buffer *buffer =3D &con->buffer; XENCONS_RING_IDX cons, prod, size; @@ -60,7 +71,7 @@ static void buffer_append(struct XenConsole *con) =20 size =3D prod - cons; if ((size =3D=3D 0) || (size > sizeof(intf->out))) - return; + return false; =20 if ((buffer->capacity - buffer->size) < size) { buffer->capacity +=3D (size + 1024); @@ -73,7 +84,7 @@ static void buffer_append(struct XenConsole *con) =20 xen_mb(); intf->out_cons =3D cons; - xen_pv_send_notify(&con->xendev); + xen_device_notify_event_channel(XEN_DEVICE(con), con->event_channel, N= ULL); =20 if (buffer->max_capacity && buffer->size > buffer->max_capacity) { @@ -89,6 +100,7 @@ static void buffer_append(struct XenConsole *con) if (buffer->consumed > buffer->max_capacity - over) buffer->consumed =3D buffer->max_capacity - over; } + return true; } =20 static void buffer_advance(struct buffer *buffer, size_t len) @@ -100,7 +112,7 @@ static void buffer_advance(struct buffer *buffer, size_= t len) } } =20 -static int ring_free_bytes(struct XenConsole *con) +static int ring_free_bytes(XenConsole *con) { struct xencons_interface *intf =3D con->sring; XENCONS_RING_IDX cons, prod, space; @@ -118,13 +130,13 @@ static int ring_free_bytes(struct XenConsole *con) =20 static int xencons_can_receive(void *opaque) { - struct XenConsole *con =3D opaque; + XenConsole *con =3D opaque; return ring_free_bytes(con); } =20 static void xencons_receive(void *opaque, const uint8_t *buf, int len) { - struct XenConsole *con =3D opaque; + XenConsole *con =3D opaque; struct xencons_interface *intf =3D con->sring; XENCONS_RING_IDX prod; int i, max; @@ -141,10 +153,10 @@ static void xencons_receive(void *opaque, const uint8= _t *buf, int len) } xen_wmb(); intf->in_prod =3D prod; - xen_pv_send_notify(&con->xendev); + xen_device_notify_event_channel(XEN_DEVICE(con), con->event_channel, N= ULL); } =20 -static void xencons_send(struct XenConsole *con) +static bool xencons_send(XenConsole *con) { ssize_t len, size; =20 @@ -159,174 +171,436 @@ static void xencons_send(struct XenConsole *con) if (len < 1) { if (!con->backlog) { con->backlog =3D 1; - xen_pv_printf(&con->xendev, 1, - "backlog piling up, nobody listening?\n"); } } else { buffer_advance(&con->buffer, len); if (con->backlog && len =3D=3D size) { con->backlog =3D 0; - xen_pv_printf(&con->xendev, 1, "backlog is gone\n"); } } + return len > 0; } =20 /* -------------------------------------------------------------------- */ =20 -static int store_con_info(struct XenConsole *con) +static bool con_event(void *_xendev) { - Chardev *cs =3D qemu_chr_fe_get_driver(&con->chr); - char *pts =3D NULL; - char *dom_path; - g_autoptr(GString) path =3D NULL; + XenConsole *con =3D XEN_CONSOLE_DEVICE(_xendev); + bool done_something; + + if (xen_device_backend_get_state(&con->xendev) !=3D XenbusStateConnect= ed) { + return false; + } + + done_something =3D buffer_append(con); + + if (con->buffer.size - con->buffer.consumed) { + done_something |=3D xencons_send(con); + } + return done_something; +} + +/* -------------------------------------------------------------------- */ + +static bool xen_console_connect(XenDevice *xendev, Error **errp) +{ + XenConsole *con =3D XEN_CONSOLE_DEVICE(xendev); + unsigned int port, limit; + + if (xen_device_frontend_scanf(xendev, "ring-ref", "%u", + &con->ring_ref) !=3D 1) { + error_setg(errp, "failed to read ring-ref"); + return false; + } =20 - /* Only continue if we're talking to a pty. */ - if (!CHARDEV_IS_PTY(cs)) { - return 0; + if (xen_device_frontend_scanf(xendev, "port", "%u", &port) !=3D 1) { + error_setg(errp, "failed to read remote port"); + return false; } - pts =3D cs->filename + 4; =20 - dom_path =3D qemu_xen_xs_get_domain_path(xenstore, xen_domid); - if (!dom_path) { - return 0; + if (xen_device_frontend_scanf(xendev, "limit", "%u", &limit) =3D=3D 1)= { + con->buffer.max_capacity =3D limit; } =20 - path =3D g_string_new(dom_path); - free(dom_path); + con->event_channel =3D xen_device_bind_event_channel(xendev, port, + con_event, + con, + errp); + if (!con->event_channel) { + return false; + } =20 - if (con->xendev.dev) { - g_string_append_printf(path, "/device/console/%d", con->xendev.dev= ); + if (!con->dev) { + xen_pfn_t mfn =3D (xen_pfn_t)con->ring_ref; + con->sring =3D qemu_xen_foreignmem_map(xendev->frontend_id, NULL, + PROT_READ | PROT_WRITE, + 1, &mfn, NULL); + if (!con->sring) { + error_setg(errp, "failed to map console page"); + return false; + } } else { - g_string_append(path, "/console"); + con->sring =3D xen_device_map_grant_refs(xendev, + &con->ring_ref, 1, + PROT_READ | PROT_WRITE, + errp); + if (!con->sring) { + error_prepend(errp, "failed to map grant ref: "); + return false; + } } - g_string_append(path, "/tty"); =20 - if (xenstore_write_str(con->console, path->str, pts)) { - fprintf(stderr, "xenstore_write_str for '%s' fail", path->str); - return -1; + trace_xen_console_connect(con->dev, con->ring_ref, port, + con->buffer.max_capacity); + + qemu_chr_fe_set_handlers(&con->chr, xencons_can_receive, + xencons_receive, NULL, NULL, con, NULL, + true); + return true; +} + +static void xen_console_disconnect(XenDevice *xendev, Error **errp) +{ + XenConsole *con =3D XEN_CONSOLE_DEVICE(xendev); + + trace_xen_console_disconnect(con->dev); + + qemu_chr_fe_set_handlers(&con->chr, NULL, NULL, NULL, NULL, + con, NULL, true); + + if (con->event_channel) { + xen_device_unbind_event_channel(xendev, con->event_channel, + errp); + con->event_channel =3D NULL; + } + + if (con->sring) { + if (!con->dev) { + qemu_xen_foreignmem_unmap(con->sring, 1); + } else { + xen_device_unmap_grant_refs(xendev, con->sring, + &con->ring_ref, 1, errp); + } + con->sring =3D NULL; } - return 0; } =20 -static int con_init(struct XenLegacyDevice *xendev) +static void xen_console_frontend_changed(XenDevice *xendev, + enum xenbus_state frontend_state, + Error **errp) { - struct XenConsole *con =3D container_of(xendev, struct XenConsole, xen= dev); - char *type, *dom, label[32]; - int ret =3D 0; - const char *output; - - /* setup */ - dom =3D qemu_xen_xs_get_domain_path(xenstore, con->xendev.dom); - if (!xendev->dev) { - snprintf(con->console, sizeof(con->console), "%s/console", dom); - } else { - snprintf(con->console, sizeof(con->console), "%s/device/console/%d= ", dom, xendev->dev); + ERRP_GUARD(); + enum xenbus_state backend_state =3D xen_device_backend_get_state(xende= v); + + switch (frontend_state) { + case XenbusStateInitialised: + case XenbusStateConnected: + if (backend_state =3D=3D XenbusStateConnected) { + break; + } + + xen_console_disconnect(xendev, errp); + if (*errp) { + break; + } + + if (!xen_console_connect(xendev, errp)) { + xen_device_backend_set_state(xendev, XenbusStateClosing); + break; + } + + xen_device_backend_set_state(xendev, XenbusStateConnected); + break; + + case XenbusStateClosing: + xen_device_backend_set_state(xendev, XenbusStateClosing); + break; + + case XenbusStateClosed: + case XenbusStateUnknown: + xen_console_disconnect(xendev, errp); + if (*errp) { + break; + } + + xen_device_backend_set_state(xendev, XenbusStateClosed); + break; + + default: + break; } - free(dom); +} =20 - type =3D xenstore_read_str(con->console, "type"); - if (!type || strcmp(type, "ioemu") !=3D 0) { - xen_pv_printf(xendev, 1, "not for me (type=3D%s)\n", type); - ret =3D -1; - goto out; +static char *xen_console_get_name(XenDevice *xendev, Error **errp) +{ + XenConsole *con =3D XEN_CONSOLE_DEVICE(xendev); + + if (con->dev =3D=3D -1) { + XenBus *xenbus =3D XEN_BUS(qdev_get_parent_bus(DEVICE(xendev))); + char fe_path[XENSTORE_ABS_PATH_MAX + 1]; + char *value; + int idx =3D 1; + + /* Theoretically we could go up to INT_MAX here but that's overkil= l */ + while (idx < 100) { + snprintf(fe_path, sizeof(fe_path), + "/local/domain/%u/device/console/%u", + xendev->frontend_id, idx); + value =3D qemu_xen_xs_read(xenbus->xsh, XBT_NULL, fe_path, NUL= L); + if (!value) { + if (errno =3D=3D ENOENT) { + con->dev =3D idx; + goto found; + } + error_setg(errp, "cannot read %s: %s", fe_path, + strerror(errno)); + return NULL; + } + free(value); + idx++; + } + error_setg(errp, "cannot find device index for console device"); + return NULL; } + found: + return g_strdup_printf("%u", con->dev); +} + +static void xen_console_unrealize(XenDevice *xendev) +{ + XenConsole *con =3D XEN_CONSOLE_DEVICE(xendev); + + trace_xen_console_unrealize(con->dev); =20 - output =3D xenstore_read_str(con->console, "output"); + /* Disconnect from the frontend in case this has not already happened = */ + xen_console_disconnect(xendev, NULL); =20 - /* no Xen override, use qemu output device */ - if (output =3D=3D NULL) { - if (con->xendev.dev) { - qemu_chr_fe_init(&con->chr, serial_hd(con->xendev.dev), - &error_abort); + qemu_chr_fe_deinit(&con->chr, false); +} + +static void xen_console_realize(XenDevice *xendev, Error **errp) +{ + ERRP_GUARD(); + XenConsole *con =3D XEN_CONSOLE_DEVICE(xendev); + Chardev *cs =3D qemu_chr_fe_get_driver(&con->chr); + unsigned int u; + + if (!cs) { + error_setg(errp, "no backing character device"); + return; + } + + if (con->dev =3D=3D -1) { + error_setg(errp, "no device index provided"); + return; + } + + /* + * The Xen primary console is special. The ring-ref is actually a GFN = to + * be mapped directly as foreignmem (not a grant ref), and the guest p= ort + * was allocated *for* the guest by the toolstack. The guest gets these + * through HVMOP_get_param and can use the console long before it's got + * XenStore up and running. We cannot create those for a Xen guest. + */ + if (!con->dev) { + if (xen_device_frontend_scanf(xendev, "ring-ref", "%u", &u) !=3D 1= || + xen_device_frontend_scanf(xendev, "port", "%u", &u) !=3D 1) { + error_setg(errp, "cannot create primary Xen console"); + return; } + } + + trace_xen_console_realize(con->dev, object_get_typename(OBJECT(cs))); + + if (CHARDEV_IS_PTY(cs)) { + /* Strip the leading 'pty:' */ + xen_device_frontend_printf(xendev, "tty", "%s", cs->filename + 4); + } + + /* No normal PV driver initialization for the primary console */ + if (!con->dev) { + xen_console_connect(xendev, errp); + } +} + +static char *console_frontend_path(struct qemu_xs_handle *xenstore, + unsigned int dom_id, unsigned int dev) +{ + if (!dev) { + return g_strdup_printf("/local/domain/%u/console", dom_id); } else { - snprintf(label, sizeof(label), "xencons%d", con->xendev.dev); - qemu_chr_fe_init(&con->chr, - /* - * FIXME: sure we want to support implicit - * muxed monitors here? - */ - qemu_chr_new_mux_mon(label, output, NULL), - &error_abort); + return g_strdup_printf("/local/domain/%u/device/console/%u", dom_i= d, + dev); } +} =20 - store_con_info(con); +static char *xen_console_get_frontend_path(XenDevice *xendev, Error **errp) +{ + XenConsole *con =3D XEN_CONSOLE_DEVICE(xendev); + XenBus *xenbus =3D XEN_BUS(qdev_get_parent_bus(DEVICE(xendev))); + char *ret =3D console_frontend_path(xenbus->xsh, xendev->frontend_id, + con->dev); =20 -out: - g_free(type); + if (!ret) { + error_setg(errp, "failed to create frontend path"); + } return ret; } =20 -static int con_initialise(struct XenLegacyDevice *xendev) + +static Property xen_console_properties[] =3D { + DEFINE_PROP_CHR("chardev", XenConsole, chr), + DEFINE_PROP_INT32("idx", XenConsole, dev, -1), + DEFINE_PROP_END_OF_LIST(), +}; + +static void xen_console_class_init(ObjectClass *class, void *data) { - struct XenConsole *con =3D container_of(xendev, struct XenConsole, xen= dev); - int limit; - - if (xenstore_read_int(con->console, "ring-ref", &con->ring_ref) =3D=3D= -1) - return -1; - if (xenstore_read_int(con->console, "port", &con->xendev.remote_port) = =3D=3D -1) - return -1; - if (xenstore_read_int(con->console, "limit", &limit) =3D=3D 0) - con->buffer.max_capacity =3D limit; + DeviceClass *dev_class =3D DEVICE_CLASS(class); + XenDeviceClass *xendev_class =3D XEN_DEVICE_CLASS(class); + + xendev_class->backend =3D "console"; + xendev_class->device =3D "console"; + xendev_class->get_name =3D xen_console_get_name; + xendev_class->realize =3D xen_console_realize; + xendev_class->frontend_changed =3D xen_console_frontend_changed; + xendev_class->unrealize =3D xen_console_unrealize; + xendev_class->get_frontend_path =3D xen_console_get_frontend_path; + + device_class_set_props(dev_class, xen_console_properties); +} =20 - if (!xendev->dev) { - xen_pfn_t mfn =3D con->ring_ref; - con->sring =3D qemu_xen_foreignmem_map(con->xendev.dom, NULL, - PROT_READ | PROT_WRITE, - 1, &mfn, NULL); - } else { - con->sring =3D xen_be_map_grant_ref(xendev, con->ring_ref, - PROT_READ | PROT_WRITE); - } - if (!con->sring) - return -1; +static const TypeInfo xen_console_type_info =3D { + .name =3D TYPE_XEN_CONSOLE_DEVICE, + .parent =3D TYPE_XEN_DEVICE, + .instance_size =3D sizeof(XenConsole), + .class_init =3D xen_console_class_init, +}; =20 - xen_be_bind_evtchn(&con->xendev); - qemu_chr_fe_set_handlers(&con->chr, xencons_can_receive, - xencons_receive, NULL, NULL, con, NULL, true); - - xen_pv_printf(xendev, 1, - "ring mfn %d, remote port %d, local port %d, limit %zd\n= ", - con->ring_ref, - con->xendev.remote_port, - con->xendev.local_port, - con->buffer.max_capacity); - return 0; +static void xen_console_register_types(void) +{ + type_register_static(&xen_console_type_info); } =20 -static void con_disconnect(struct XenLegacyDevice *xendev) +type_init(xen_console_register_types) + +/* Called to instantiate a XenConsole when the backend is detected. */ +static void xen_console_device_create(XenBackendInstance *backend, + QDict *opts, Error **errp) { - struct XenConsole *con =3D container_of(xendev, struct XenConsole, xen= dev); + ERRP_GUARD(); + XenBus *xenbus =3D xen_backend_get_bus(backend); + const char *name =3D xen_backend_get_name(backend); + unsigned long number; + char *fe =3D NULL, *type =3D NULL, *output =3D NULL; + char label[32]; + XenDevice *xendev =3D NULL; + XenConsole *con; + Chardev *cd =3D NULL; + struct qemu_xs_handle *xsh =3D xenbus->xsh; + + if (qemu_strtoul(name, NULL, 10, &number) || number > INT_MAX) { + error_setg(errp, "failed to parse name '%s'", name); + goto fail; + } =20 - qemu_chr_fe_deinit(&con->chr, false); - xen_pv_unbind_evtchn(&con->xendev); + trace_xen_console_device_create(number); =20 - if (con->sring) { - if (!xendev->dev) { - qemu_xen_foreignmem_unmap(con->sring, 1); - } else { - xen_be_unmap_grant_ref(xendev, con->sring, con->ring_ref); + fe =3D console_frontend_path(xsh, xen_domid, number); + if (fe =3D=3D NULL) { + error_setg(errp, "failed to generate frontend path"); + goto fail; + } + + if (xs_node_scanf(xsh, XBT_NULL, fe, "type", errp, "%ms", &type) !=3D = 1) { + error_prepend(errp, "failed to read console device type: "); + goto fail; + } + + if (strcmp(type, "ioemu")) { + error_setg(errp, "declining to handle console type '%s'", + type); + goto fail; + } + + xendev =3D XEN_DEVICE(qdev_new(TYPE_XEN_CONSOLE_DEVICE)); + con =3D XEN_CONSOLE_DEVICE(xendev); + + con->dev =3D number; + + snprintf(label, sizeof(label), "xencons%ld", number); + + if (xs_node_scanf(xsh, XBT_NULL, fe, "output", NULL, "%ms", &output) = =3D=3D 1) { + /* + * FIXME: sure we want to support implicit + * muxed monitors here? + */ + cd =3D qemu_chr_new_mux_mon(label, output, NULL); + if (!cd) { + error_setg(errp, "console: No valid chardev found at '%s': ", + output); + goto fail; } - con->sring =3D NULL; + } else if (number) { + cd =3D serial_hd(number); + if (!cd) { + error_prepend(errp, "console: No serial device #%ld found: ", + number); + goto fail; + } + } else { + /* No 'output' node on primary console: use null. */ + cd =3D qemu_chr_new(label, "null", NULL); + if (!cd) { + error_setg(errp, "console: failed to create null device"); + goto fail; + } + } + + if (!qemu_chr_fe_init(&con->chr, cd, errp)) { + error_prepend(errp, "console: failed to initialize backing chardev= : "); + goto fail; + } + + if (qdev_realize_and_unref(DEVICE(xendev), BUS(xenbus), errp)) { + xen_backend_set_device(backend, xendev); + goto done; + } + + error_prepend(errp, "realization of console device %lu failed: ", + number); + + fail: + if (xendev) { + object_unparent(OBJECT(xendev)); } + done: + g_free(fe); + free(type); + free(output); } =20 -static void con_event(struct XenLegacyDevice *xendev) +static void xen_console_device_destroy(XenBackendInstance *backend, + Error **errp) { - struct XenConsole *con =3D container_of(xendev, struct XenConsole, xen= dev); + ERRP_GUARD(); + XenDevice *xendev =3D xen_backend_get_device(backend); + XenConsole *con =3D XEN_CONSOLE_DEVICE(xendev); =20 - buffer_append(con); - if (con->buffer.size - con->buffer.consumed) - xencons_send(con); -} + trace_xen_console_device_destroy(con->dev); =20 -/* -------------------------------------------------------------------- */ + object_unparent(OBJECT(xendev)); +} =20 -struct XenDevOps xen_console_ops =3D { - .size =3D sizeof(struct XenConsole), - .flags =3D DEVOPS_FLAG_IGNORE_STATE|DEVOPS_FLAG_NEED_GNTDEV, - .init =3D con_init, - .initialise =3D con_initialise, - .event =3D con_event, - .disconnect =3D con_disconnect, +static const XenBackendInfo xen_console_backend_info =3D { + .type =3D "console", + .create =3D xen_console_device_create, + .destroy =3D xen_console_device_destroy, }; + +static void xen_console_register_backend(void) +{ + xen_backend_register(&xen_console_backend_info); +} + +xen_backend_init(xen_console_register_backend); diff --git a/hw/xen/xen-legacy-backend.c b/hw/xen/xen-legacy-backend.c index 4ded3cec23..124dd5f3d6 100644 --- a/hw/xen/xen-legacy-backend.c +++ b/hw/xen/xen-legacy-backend.c @@ -623,7 +623,6 @@ void xen_be_init(void) =20 xen_set_dynamic_sysbus(); =20 - xen_be_register("console", &xen_console_ops); xen_be_register("vkbd", &xen_kbdmouse_ops); #ifdef CONFIG_VIRTFS xen_be_register("9pfs", &xen_9pfs_ops); --=20 2.41.0