From nobody Tue Sep 9 21:41:05 2025 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=1757114864; cv=none; d=zohomail.com; s=zohoarc; b=aBc0Oy6EChJnRMIJ8F55EaBP3fjVMBEjePjFotx28/CWvY2dCiYAd5BoOmIJkc1FENYyqfmcTt09PcSCKiziib6gh9bSIxDNQeCzbq5Q/18hlD9LLDuOLFIYkXvJbVIL+1iPATGQv/gLyCPreWRbUShfiRzwJmepv1DZtdphruE= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1757114864; 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=MYkyC6HYAaTUnjoaK5ptXN+ThND9+Vyev3ekOb2IdWs=; b=GvbUIDWvTKfvMQy7415DYOlDJC11vg83xcnbpyNy0em8iJK1osZl3FKtN6SuxctZE+mB74TxIu5Bz2Jh+emEk72VNQ8hxdcl0vmpx9Fuv2BSRepGRz53z0zAg2lc0mhvLlq9z3ABPsrJqsjjp4/CVx6uAFE2G2asY1fMNfjJHzo= 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 1757114864409979.5550121323216; Fri, 5 Sep 2025 16:27:44 -0700 (PDT) Received: from list by lists.xenproject.org with outflank-mailman.1112629.1460833 (Exim 4.92) (envelope-from ) id 1uufpy-0001RU-Pq; Fri, 05 Sep 2025 23:27:22 +0000 Received: by outflank-mailman (output) from mailman id 1112629.1460833; Fri, 05 Sep 2025 23:27:22 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1uufpy-0001RN-N2; Fri, 05 Sep 2025 23:27:22 +0000 Received: by outflank-mailman (input) for mailman id 1112629; Fri, 05 Sep 2025 23:27:20 +0000 Received: from mail.xenproject.org ([104.130.215.37]) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1uufpw-0001D3-5F for xen-devel@lists.xenproject.org; Fri, 05 Sep 2025 23:27:20 +0000 Received: from xenbits.xenproject.org ([104.239.192.120]) by mail.xenproject.org with esmtp (Exim 4.96) (envelope-from ) id 1uufpv-008AAR-1f; Fri, 05 Sep 2025 23:27:19 +0000 Received: from [19.12.91.86] (helo=localhost) by xenbits.xenproject.org with esmtpsa (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1uufpv-0005Cq-1W; Fri, 05 Sep 2025 23:27:19 +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 Sender: "Xen-devel" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org; s=20200302mail; h=Content-Transfer-Encoding:MIME-Version:References: In-Reply-To:Message-ID:Date:Subject:Cc:To:From; bh=MYkyC6HYAaTUnjoaK5ptXN+ThND9+Vyev3ekOb2IdWs=; b=xvoeLoJZGZHuCKx2sFifB+DACp 3ZajkUZdufXzQrU1RtfyA3KBzWWw3frwXnuaByOFGCNivT0ozEAHgDS3Q/DjX/jL7Brs9Kmh+1MO9 KmDrkBg2qzULo5xzGEGV8kGeruFJFZYR82vHZHvydO8j1kh2oLl4aM3rDrUlOlFknrmI=; From: dmukhin@xen.org To: xen-devel@lists.xenproject.org Cc: andrew.cooper3@citrix.com, anthony.perard@vates.tech, jbeulich@suse.com, julien@xen.org, michal.orzel@amd.com, roger.pau@citrix.com, sstabellini@kernel.org, dmukhin@ford.com Subject: [PATCH v6 01/15] emul/vuart: introduce framework for UART emulators Date: Fri, 5 Sep 2025 16:27:00 -0700 Message-ID: <20250905232715.440758-2-dmukhin@ford.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20250905232715.440758-1-dmukhin@ford.com> References: <20250905232715.440758-1-dmukhin@ford.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-ZohoMail-DKIM: pass (identity @xen.org) X-ZM-MESSAGEID: 1757114866603116600 Content-Type: text/plain; charset="utf-8" From: Denis Mukhin =20 Introduce a driver framework to abstract UART emulators in the hypervisor. That allows for architecture-independent handling of virtual UARTs in the console driver and simplifies enabling new UART emulators. The framework is built under CONFIG_VUART_FRAMEWORK, which will be automatically enabled once the user enables any UART emulator. Current implementation supports maximum of one vUART of each kind per domai= n. Use new domain_has_vuart() in the console driver code to check whether to forward console input to the domain using vUART. Enable console forwarding over vUART for hardware domains with a vUART. That enables console forwarding to dom0 on x86, since console can be forwarded o= nly to Xen, dom0 and pvshim on x86 as of now. Note: existing vUARTs are deliberately *not* hooked to the new framework to minimize the scope of the patch: vpl011 (i.e. SBSA) emulator and "vuart" (i= .e. minimalistic MMIO-mapped dtuart for hwdoms on Arm) are kept unmodified. No functional changes for non-x86 architectures. Signed-off-by: Denis Mukhin Reviewed-by: Stefano Stabellini --- Changes since v5: - addressed v5 feedback - Link to v5: https://lore.kernel.org/xen-devel/20250828235409.2835815-2-dm= ukhin@ford.com/ --- xen/arch/arm/xen.lds.S | 1 + xen/arch/ppc/xen.lds.S | 1 + xen/arch/riscv/xen.lds.S | 1 + xen/arch/x86/xen.lds.S | 1 + xen/common/Kconfig | 2 + xen/common/Makefile | 1 + xen/common/emul/Kconfig | 6 ++ xen/common/emul/Makefile | 1 + xen/common/emul/vuart/Kconfig | 6 ++ xen/common/emul/vuart/Makefile | 1 + xen/common/emul/vuart/vuart.c | 157 +++++++++++++++++++++++++++++++++ xen/common/keyhandler.c | 3 + xen/drivers/char/console.c | 6 +- xen/include/xen/sched.h | 4 + xen/include/xen/serial.h | 3 + xen/include/xen/vuart.h | 116 ++++++++++++++++++++++++ xen/include/xen/xen.lds.h | 10 +++ 17 files changed, 319 insertions(+), 1 deletion(-) create mode 100644 xen/common/emul/Kconfig create mode 100644 xen/common/emul/Makefile create mode 100644 xen/common/emul/vuart/Kconfig create mode 100644 xen/common/emul/vuart/Makefile create mode 100644 xen/common/emul/vuart/vuart.c create mode 100644 xen/include/xen/vuart.h diff --git a/xen/arch/arm/xen.lds.S b/xen/arch/arm/xen.lds.S index db17ff1efa98..cd05b18770f4 100644 --- a/xen/arch/arm/xen.lds.S +++ b/xen/arch/arm/xen.lds.S @@ -58,6 +58,7 @@ SECTIONS *(.rodata) *(.rodata.*) VPCI_ARRAY + VUART_ARRAY *(.data.rel.ro) *(.data.rel.ro.*) =20 diff --git a/xen/arch/ppc/xen.lds.S b/xen/arch/ppc/xen.lds.S index 1de0b77fc6b9..f9d4e5b0dcd8 100644 --- a/xen/arch/ppc/xen.lds.S +++ b/xen/arch/ppc/xen.lds.S @@ -52,6 +52,7 @@ SECTIONS *(.rodata) *(.rodata.*) VPCI_ARRAY + VUART_ARRAY *(.data.rel.ro) *(.data.rel.ro.*) =20 diff --git a/xen/arch/riscv/xen.lds.S b/xen/arch/riscv/xen.lds.S index edcadff90bfe..59dcaa5fef9a 100644 --- a/xen/arch/riscv/xen.lds.S +++ b/xen/arch/riscv/xen.lds.S @@ -47,6 +47,7 @@ SECTIONS *(.rodata) *(.rodata.*) VPCI_ARRAY + VUART_ARRAY *(.data.rel.ro) *(.data.rel.ro.*) =20 diff --git a/xen/arch/x86/xen.lds.S b/xen/arch/x86/xen.lds.S index 966e514f2034..d877b93a6964 100644 --- a/xen/arch/x86/xen.lds.S +++ b/xen/arch/x86/xen.lds.S @@ -132,6 +132,7 @@ SECTIONS *(.rodata) *(.rodata.*) VPCI_ARRAY + VUART_ARRAY *(.data.rel.ro) *(.data.rel.ro.*) =20 diff --git a/xen/common/Kconfig b/xen/common/Kconfig index 76f9ce705f7a..78a32b69e2b2 100644 --- a/xen/common/Kconfig +++ b/xen/common/Kconfig @@ -676,4 +676,6 @@ config PM_STATS Enable collection of performance management statistics to aid in analyzing and tuning power/performance characteristics of the system =20 +source "common/emul/Kconfig" + endmenu diff --git a/xen/common/Makefile b/xen/common/Makefile index 0c7d0f5d46e1..8c8462565050 100644 --- a/xen/common/Makefile +++ b/xen/common/Makefile @@ -12,6 +12,7 @@ obj-$(CONFIG_DEVICE_TREE_PARSE) +=3D device-tree/ obj-$(CONFIG_IOREQ_SERVER) +=3D dm.o obj-y +=3D domain.o obj-y +=3D domid.o +obj-y +=3D emul/ obj-y +=3D event_2l.o obj-y +=3D event_channel.o obj-$(CONFIG_EVTCHN_FIFO) +=3D event_fifo.o diff --git a/xen/common/emul/Kconfig b/xen/common/emul/Kconfig new file mode 100644 index 000000000000..7c6764d1756b --- /dev/null +++ b/xen/common/emul/Kconfig @@ -0,0 +1,6 @@ +menu "Domain Emulation Features" + visible if EXPERT + +source "common/emul/vuart/Kconfig" + +endmenu diff --git a/xen/common/emul/Makefile b/xen/common/emul/Makefile new file mode 100644 index 000000000000..ae0b575c3901 --- /dev/null +++ b/xen/common/emul/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_VUART_FRAMEWORK) +=3D vuart/ diff --git a/xen/common/emul/vuart/Kconfig b/xen/common/emul/vuart/Kconfig new file mode 100644 index 000000000000..ce1b976b7da7 --- /dev/null +++ b/xen/common/emul/vuart/Kconfig @@ -0,0 +1,6 @@ +config VUART_FRAMEWORK + bool + +menu "UART Emulation" + +endmenu diff --git a/xen/common/emul/vuart/Makefile b/xen/common/emul/vuart/Makefile new file mode 100644 index 000000000000..97f792dc6641 --- /dev/null +++ b/xen/common/emul/vuart/Makefile @@ -0,0 +1 @@ +obj-y +=3D vuart.o diff --git a/xen/common/emul/vuart/vuart.c b/xen/common/emul/vuart/vuart.c new file mode 100644 index 000000000000..3dfcba217248 --- /dev/null +++ b/xen/common/emul/vuart/vuart.c @@ -0,0 +1,157 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * UART emulator framework. + * + * Copyright 2025 Ford Motor Company + */ + +#include +#include +#include +#include + +#define for_each_emulator(e) \ + for ( e =3D vuart_array_start; e < vuart_array_end; e++ ) + +extern const struct vuart_emulator vuart_array_start[]; +extern const struct vuart_emulator vuart_array_end[]; + +static const struct vuart_emulator * +vuart_match_by_compatible(const struct domain *d, const char *compat) +{ + const struct vuart_emulator *emulator; + + for_each_emulator(emulator) + if ( emulator->compatible && + !strncmp(compat, emulator->compatible, + strlen(emulator->compatible)) ) + return emulator; + + return NULL; +} + +const static struct vuart * +vuart_find_by_console_permission(const struct domain *d) +{ + const struct vuart *vuart =3D d->console.vuart; + + if ( !vuart || !vuart->emulator || !vuart->emulator->put_rx || + !(vuart->flags & VUART_CONSOLE_INPUT)) + return NULL; + + return vuart; +} + +struct vuart *vuart_find_by_io_range(struct domain *d, unsigned long addr, + unsigned long size) +{ + struct vuart *vuart =3D d->console.vuart; + + if ( !vuart || !vuart->info ) + return NULL; + + if ( addr >=3D vuart->info->base_addr && + addr + size - 1 <=3D vuart->info->base_addr + vuart->info->size -= 1 ) + return vuart; + + return NULL; +} + +int vuart_init(struct domain *d, struct vuart_info *info) +{ + const struct vuart_emulator *emulator; + struct vuart *vuart; + int rc; + + if ( d->console.vuart ) + return -EBUSY; + + emulator =3D vuart_match_by_compatible(d, info->compatible); + if ( !emulator ) + return -ENODEV; + + vuart =3D xzalloc(typeof(*vuart)); + if ( !vuart ) + return -ENOMEM; + + vuart->info =3D xvzalloc(typeof(*info)); + if ( !vuart->info ) + { + rc =3D -ENOMEM; + goto err_out; + } + memcpy(vuart->info, info, sizeof(*info)); + + vuart->vdev =3D emulator->alloc(d, vuart->info); + if ( IS_ERR(vuart->vdev) ) + { + rc =3D PTR_ERR(vuart->vdev); + goto err_out; + } + + vuart->emulator =3D emulator; + vuart->owner =3D d; + vuart->flags |=3D VUART_CONSOLE_INPUT; + + d->console.input_allowed =3D true; + d->console.vuart =3D vuart; + + return 0; + + err_out: + if ( vuart ) + xvfree(vuart->info); + xvfree(vuart); + + return rc; +} + +/* + * Release any resources taken by UART emulators. + * + * NB: no flags are cleared, since currently exit() is called only during + * domain destroy. + */ +void vuart_deinit(struct domain *d) +{ + struct vuart *vuart =3D d->console.vuart; + + if ( vuart ) + { + vuart->emulator->free(vuart->vdev); + xvfree(vuart->info); + } + XVFREE(d->console.vuart); +} + +void vuart_dump_state(const struct domain *d) +{ + struct vuart *vuart =3D d->console.vuart; + + if ( vuart ) + vuart->emulator->dump_state(vuart->vdev); +} + +/* + * Put character to the *first* suitable emulated UART's FIFO. + */ +int vuart_put_rx(struct domain *d, char c) +{ + const struct vuart *vuart =3D vuart_find_by_console_permission(d); + + return vuart ? vuart->emulator->put_rx(vuart->vdev, c) : -ENODEV; +} + +bool domain_has_vuart(const struct domain *d) +{ + return vuart_find_by_console_permission(d); +} + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/common/keyhandler.c b/xen/common/keyhandler.c index cb6df2823b00..156e64d9eb58 100644 --- a/xen/common/keyhandler.c +++ b/xen/common/keyhandler.c @@ -22,6 +22,7 @@ #include #include #include +#include #include =20 static unsigned char keypress_key; @@ -352,6 +353,8 @@ static void cf_check dump_domains(unsigned char key) v->periodic_period / 1000000); } } + + vuart_dump_state(d); } =20 for_each_domain ( d ) diff --git a/xen/drivers/char/console.c b/xen/drivers/char/console.c index 9bd5b4825da6..d5164897a776 100644 --- a/xen/drivers/char/console.c +++ b/xen/drivers/char/console.c @@ -33,6 +33,7 @@ #include #include #include +#include =20 #ifdef CONFIG_X86 #include @@ -596,11 +597,12 @@ static void __serial_rx(char c) if ( !d ) return; =20 - if ( is_hardware_domain(d) ) + if ( is_hardware_domain(d) && !domain_has_vuart(d) ) { /* * Deliver input to the hardware domain buffer, unless it is * already full. + * NB: must be the first check: hardware domain may have emulated = UART. */ if ( (serial_rx_prod - serial_rx_cons) !=3D SERIAL_RX_SIZE ) serial_rx_ring[SERIAL_RX_MASK(serial_rx_prod++)] =3D c; @@ -611,6 +613,8 @@ static void __serial_rx(char c) */ send_global_virq(VIRQ_CONSOLE); } + else if ( domain_has_vuart(d) ) + rc =3D vuart_put_rx(d, c); #ifdef CONFIG_SBSA_VUART_CONSOLE else /* Deliver input to the emulated UART. */ diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h index 02bdc256ce37..613f4596e33d 100644 --- a/xen/include/xen/sched.h +++ b/xen/include/xen/sched.h @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -660,6 +661,9 @@ struct domain struct { /* Permission to take ownership of the physical console input. */ bool input_allowed; +#ifdef CONFIG_VUART_FRAMEWORK + struct vuart *vuart; +#endif } console; } __aligned(PAGE_SIZE); =20 diff --git a/xen/include/xen/serial.h b/xen/include/xen/serial.h index 8e1844555208..123eee67df35 100644 --- a/xen/include/xen/serial.h +++ b/xen/include/xen/serial.h @@ -36,6 +36,9 @@ struct vuart_info { unsigned long data_off; /* Data register offset */ unsigned long status_off; /* Status register offset */ unsigned long status; /* Ready status value */ + unsigned int irq; /* Interrupt */ + char compatible[16]; /* Compatible string */ + char name[16]; /* User-friendly name */ }; =20 struct serial_port { diff --git a/xen/include/xen/vuart.h b/xen/include/xen/vuart.h new file mode 100644 index 000000000000..54f2f29f3f4a --- /dev/null +++ b/xen/include/xen/vuart.h @@ -0,0 +1,116 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * UART emulator framework. + * + * Copyright 2025 Ford Motor Company + */ + +#ifndef XEN_VUART_H +#define XEN_VUART_H + +#include +#include + +struct vuart_emulator; + +enum { + VUART_CONSOLE_INPUT =3D BIT(0, U), /* Physical console input forwardin= g. */ +}; + + +/* + * FIXME: #ifdef is temporary to avoid clash with + * arch/arm/include/asm/domain.h + */ +#ifdef CONFIG_VUART_FRAMEWORK +struct vuart { + const struct vuart_emulator *emulator; + struct vuart_info *info; + struct domain *owner; + uint32_t flags; + void *vdev; +}; +#endif + +struct vuart_emulator { + /* UART compatible string. Cannot be NULL or empty. */ + const char *compatible; + + /* + * Allocate emulated UART state (RX/TX FIFOs, locks, initialize regist= ers, + * hook I/O handlers, etc.) + * Cannot be NULL. + */ + void *(*alloc)(struct domain *d, const struct vuart_info *info); + + /* + * Release resources used to emulate UART state (flush RX/TX FIFOs, un= hook + * I/O handlers, etc.). + * Cannot be NULL. + */ + void (*free)(void *arg); + + /* + * Print emulated UART state, including registers, on the console. + * Can be NULL. + */ + void (*dump_state)(void *arg); + + /* + * Place character to the emulated RX FIFO. + * Used to forward physical console input to the guest OS. + * Can be NULL. + */ + int (*put_rx)(void *arg, char c); +}; + +#define VUART_REGISTER(name, x) \ + static const struct vuart_emulator name##_entry \ + __used_section(".data.rel.ro.vuart") =3D x + +struct vuart *vuart_find_by_io_range(struct domain *d, + unsigned long base_addr, + unsigned long size); + +int vuart_put_rx(struct domain *d, char c); + +#ifdef CONFIG_VUART_FRAMEWORK + +int vuart_init(struct domain *d, struct vuart_info *info); +void vuart_deinit(struct domain *d); +void vuart_dump_state(const struct domain *d); +bool domain_has_vuart(const struct domain *d); + +#else + +static inline int vuart_init(struct domain *d, struct vuart_info *info) +{ + return 0; +} + +static inline void vuart_deinit(struct domain *d) +{ +} + +static inline void vuart_dump_state(const struct domain *d) +{ +} + +static inline bool domain_has_vuart(const struct domain *d) +{ + return false; +} + +#endif /* CONFIG_VUART_FRAMEWORK */ + +#endif /* XEN_VUART_H */ + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + */ + diff --git a/xen/include/xen/xen.lds.h b/xen/include/xen/xen.lds.h index b126dfe88792..2d65f32ddad3 100644 --- a/xen/include/xen/xen.lds.h +++ b/xen/include/xen/xen.lds.h @@ -194,4 +194,14 @@ #define VPCI_ARRAY #endif =20 +#ifdef CONFIG_VUART_FRAMEWORK +#define VUART_ARRAY \ + . =3D ALIGN(POINTER_ALIGN); \ + vuart_array_start =3D .; \ + *(.data.rel.ro.vuart) \ + vuart_array_end =3D .; +#else +#define VUART_ARRAY +#endif + #endif /* __XEN_LDS_H__ */ --=20 2.51.0