From nobody Wed Nov 27 11:40:09 2024 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1699281416412448.1729346481967; Mon, 6 Nov 2023 06:36:56 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1r00hy-0007tK-Ns; Mon, 06 Nov 2023 09:36:06 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1r00hw-0007rN-Gu; Mon, 06 Nov 2023 09:36:04 -0500 Received: from smtp-fw-9105.amazon.com ([207.171.188.204]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1r00ht-0000YY-NE; Mon, 06 Nov 2023 09:36:04 -0500 Received: from pdx4-co-svc-p1-lb2-vlan2.amazon.com (HELO email-inbound-relay-pdx-2a-m6i4x-d47337e0.us-west-2.amazon.com) ([10.25.36.210]) by smtp-border-fw-9105.sea19.amazon.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 06 Nov 2023 14:36:00 +0000 Received: from smtpout.prod.us-west-2.prod.farcaster.email.amazon.dev (pdx2-ws-svc-p26-lb5-vlan3.pdx.amazon.com [10.39.38.70]) by email-inbound-relay-pdx-2a-m6i4x-d47337e0.us-west-2.amazon.com (Postfix) with ESMTPS id 5555D60EB9; Mon, 6 Nov 2023 14:35:52 +0000 (UTC) Received: from EX19MTAUWA002.ant.amazon.com [10.0.38.20:5172] by smtpin.naws.us-west-2.prod.farcaster.email.amazon.dev [10.0.28.94:2525] with esmtp (Farcaster) id a6ca9ea9-34d5-42d7-b4c4-6cc6a7da776d; Mon, 6 Nov 2023 14:35:52 +0000 (UTC) Received: from EX19MTAUWB001.ant.amazon.com (10.250.64.248) by EX19MTAUWA002.ant.amazon.com (10.250.64.202) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1118.39; Mon, 6 Nov 2023 14:35:41 +0000 Received: from u3832b3a9db3152.ant.amazon.com (10.106.83.6) by mail-relay.amazon.com (10.250.64.254) with Microsoft SMTP Server id 15.2.1118.39 via Frontend Transport; Mon, 6 Nov 2023 14:35:39 +0000 X-IronPort-AV: E=Sophos;i="6.03,281,1694736000"; d="scan'208";a="683074520" X-Farcaster-Flow-ID: a6ca9ea9-34d5-42d7-b4c4-6cc6a7da776d From: David Woodhouse To: CC: Kevin Wolf , Hanna Reitz , Peter Maydell , Stefano Stabellini , Anthony Perard , Paul Durrant , =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= , Paolo Bonzini , Richard Henderson , Eduardo Habkost , "Michael S. Tsirkin" , Marcel Apfelbaum , Jason Wang , Marcelo Tosatti , , , Subject: [PATCH v4 09/17] hw/xen: update Xen console to XenDevice model Date: Mon, 6 Nov 2023 14:34:59 +0000 Message-ID: <20231106143507.1060610-10-dwmw2@infradead.org> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20231106143507.1060610-1-dwmw2@infradead.org> References: <20231106143507.1060610-1-dwmw2@infradead.org> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: Bulk Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: none client-ip=207.171.188.204; envelope-from=prvs=667a8cc2a=dwmw2@infradead.org; helo=smtp-fw-9105.amazon.com X-Spam_score_int: -41 X-Spam_score: -4.2 X-Spam_bar: ---- X-Spam_report: (-4.2 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_DNSWL_MED=-2.3, RCVD_IN_MSPIKE_H4=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_NONE=0.001, SPF_NONE=0.001, T_SCC_BODY_TEXT_LINE=-0.01, UNPARSEABLE_RELAY=0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZM-MESSAGEID: 1699281590437100009 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.34.1