From nobody Wed Nov 27 17:52:39 2024 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; 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 1697730139311924.36915430572; Thu, 19 Oct 2023 08:42:19 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1qtV93-0002YH-3h; Thu, 19 Oct 2023 11:41:09 -0400 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 1qtV8v-0002TF-GD; Thu, 19 Oct 2023 11:41:02 -0400 Received: from desiato.infradead.org ([2001:8b0:10b:1:d65d:64ff:fe57:4e05]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1qtV8r-0001m2-15; Thu, 19 Oct 2023 11:41:01 -0400 Received: from [2001:8b0:10b:1::ebe] (helo=i7.infradead.org) by desiato.infradead.org with esmtpsa (Exim 4.96 #2 (Red Hat Linux)) id 1qtV8O-009yCt-0Q; Thu, 19 Oct 2023 15:40:28 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.96 #2 (Red Hat Linux)) id 1qtV8M-000Pub-2G; Thu, 19 Oct 2023 16:40:26 +0100 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=desiato.20200630; 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=QuCU5QcXms7wszQodB9qpu2o64rddhbI7UNM0sYshFY=; b=DvJY9tUlPJmX/25c9m+Tvd99uP JzddgymEh1I1Dv6gpVQ5LV/S/XbgbYYk6CN13PMz7jjGipM0lnO1xDF4RUebg6QShjdY7qzNA8swG T8LjzOrw/4c+shdbobyolxbHs+MNjYG73Mofjt2U4SvIl5ZNCDhOlEaJx5xC2Jfqq1JTmgodR+wgD Af5cZuMreaoVDxQsR9v0/8UmdTv3I7PnrkZkGCp5oVOlK8DvcN9IaBAa5IBsRlFjp+c8l2OfBIJX2 1wzl+IiMV6vkmISEPxJtuWqgHilomW0XqCSNwHKHBSwmxjhwZ+PLFfntKrLv1nGaErD02sgaEmcqL yNPYomlw==; From: David Woodhouse To: qemu-devel@nongnu.org Cc: Kevin Wolf , Hanna Reitz , 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 , Cleber Rosa , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , Wainer dos Santos Moschetta , Beraldo Leal , qemu-block@nongnu.org, xen-devel@lists.xenproject.org, kvm@vger.kernel.org, Bernhard Beschow , Joel Upham Subject: [PATCH v2 14/24] hw/xen: update Xen console to XenDevice model Date: Thu, 19 Oct 2023 16:40:10 +0100 Message-Id: <20231019154020.99080-15-dwmw2@infradead.org> X-Mailer: git-send-email 2.40.1 In-Reply-To: <20231019154020.99080-1-dwmw2@infradead.org> References: <20231019154020.99080-1-dwmw2@infradead.org> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-SRS-Rewrite: SMTP reverse-path rewritten from by desiato.infradead.org. See http://www.infradead.org/rpr.html 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=2001:8b0:10b:1:d65d:64ff:fe57:4e05; envelope-from=BATV+298c059cf2aa39b7dc34+7361+infradead.org+dwmw2@desiato.srs.infradead.org; helo=desiato.infradead.org X-Spam_score_int: -43 X-Spam_score: -4.4 X-Spam_bar: ---- X-Spam_report: (-4.4 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_MED=-2.3, SPF_HELO_NONE=0.001, SPF_NONE=0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list 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-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1697730141445100003 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 --- hw/char/trace-events | 8 + hw/char/xen_console.c | 529 +++++++++++++++++++++++++++--------- hw/xen/xen-legacy-backend.c | 1 - 3 files changed, 408 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..f4c70709c7 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,433 @@ 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; + + done_something =3D buffer_append(con); + + if (con->buffer.size - con->buffer.consumed) { + done_something |=3D xencons_send(con); + } + return done_something; +} =20 - /* Only continue if we're talking to a pty. */ - if (!CHARDEV_IS_PTY(cs)) { - return 0; +/* -------------------------------------------------------------------- */ + +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; } - 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, "port", "%u", &port) !=3D 1) { + error_setg(errp, "failed to read remote port"); + return false; } =20 - path =3D g_string_new(dom_path); - free(dom_path); + if (xen_device_frontend_scanf(xendev, "limit", "%u", &limit) =3D=3D 1)= { + con->buffer.max_capacity =3D limit; + } =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; + con->event_channel =3D xen_device_bind_event_channel(xendev, port, + con_event, + con, + errp); + if (!con->event_channel) { + return false; } - return 0; + + 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; } =20 -static int con_init(struct XenLegacyDevice *xendev) +static void xen_console_disconnect(XenDevice *xendev, 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); + 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; } - 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; + 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; } +} =20 - output =3D xenstore_read_str(con->console, "output"); +static void xen_console_frontend_changed(XenDevice *xendev, + enum xenbus_state frontend_state, + Error **errp) +{ + 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; + } =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); + xen_console_disconnect(xendev, errp); + if (*errp) { + break; } - } 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); + + 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; } +} =20 - store_con_info(con); +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); +} =20 -out: - g_free(type); - return ret; +static void xen_console_unrealize(XenDevice *xendev) +{ + XenConsole *con =3D XEN_CONSOLE_DEVICE(xendev); + + trace_xen_console_unrealize(con->dev); + + /* Disconnect from the frontend in case this has not already happened = */ + xen_console_disconnect(xendev, NULL); + + qemu_chr_fe_deinit(&con->chr, false); } =20 -static int con_initialise(struct XenLegacyDevice *xendev) +static void xen_console_realize(XenDevice *xendev, Error **errp) { - 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; + ERRP_GUARD(); + XenConsole *con =3D XEN_CONSOLE_DEVICE(xendev); + Chardev *cs =3D qemu_chr_fe_get_driver(&con->chr); + unsigned int u; =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); + 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 { - con->sring =3D xen_be_map_grant_ref(xendev, con->ring_ref, - PROT_READ | PROT_WRITE); + return g_strdup_printf("/local/domain/%u/device/console/%u", dom_i= d, + dev); } - if (!con->sring) - return -1; +} =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 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); + + if (!ret) { + error_setg(errp, "failed to create frontend path"); + } + return ret; } =20 -static void con_disconnect(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); + 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 - qemu_chr_fe_deinit(&con->chr, false); - xen_pv_unbind_evtchn(&con->xendev); +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 - 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); +static void xen_console_register_types(void) +{ + type_register_static(&xen_console_type_info); +} + +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) +{ + 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; + } + + trace_xen_console_device_create(number); + + 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.40.1