[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH v4 2/8] emul/vuart: introduce framework for UART emulators



From: Denis Mukhin <dmukhin@xxxxxxxx> 

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_HAS_VUART, which will be automatically
enabled once the user enables any UART emulator.

Current implementation supports maximum of one vUART of each kind per domain.

Use new domain_has_vuart() in the console driver code to check whether to
forward console input to the domain using vUART.

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.

Signed-off-by: Denis Mukhin <dmukhin@xxxxxxxx>
---
Changes since v3:
- new patch
- original patch from ML: 
https://lore.kernel.org/xen-devel/20250624035443.344099-16-dmukhin@xxxxxxxx/
---
 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  | 112 +++++++++++++++++++++++++++++++++
 xen/common/keyhandler.c        |   3 +
 xen/drivers/char/console.c     |   4 ++
 xen/include/xen/vuart.h        |  84 +++++++++++++++++++++++++
 xen/include/xen/xen.lds.h      |  10 +++
 15 files changed, 234 insertions(+)
 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 9f30c3a13ed1..bdba7eaa4f65 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.*)
 
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.*)
 
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.*)
 
diff --git a/xen/arch/x86/xen.lds.S b/xen/arch/x86/xen.lds.S
index 8e9cac75b09e..43426df33092 100644
--- a/xen/arch/x86/xen.lds.S
+++ b/xen/arch/x86/xen.lds.S
@@ -136,6 +136,7 @@ SECTIONS
        *(.rodata)
        *(.rodata.*)
        VPCI_ARRAY
+       VUART_ARRAY
        *(.data.rel.ro)
        *(.data.rel.ro.*)
 
diff --git a/xen/common/Kconfig b/xen/common/Kconfig
index 16936418a6e6..4e0bd524dc43 100644
--- a/xen/common/Kconfig
+++ b/xen/common/Kconfig
@@ -1,6 +1,8 @@
 
 menu "Common Features"
 
+source "common/emul/Kconfig"
+
 config COMPAT
        bool
        help
diff --git a/xen/common/Makefile b/xen/common/Makefile
index c316957fcb36..c0734480ee4b 100644
--- a/xen/common/Makefile
+++ b/xen/common/Makefile
@@ -11,6 +11,7 @@ obj-$(filter-out $(CONFIG_X86),$(CONFIG_ACPI)) += device.o
 obj-$(CONFIG_DEVICE_TREE_PARSE) += device-tree/
 obj-$(CONFIG_IOREQ_SERVER) += dm.o
 obj-y += domain.o
+obj-y += emul/
 obj-y += event_2l.o
 obj-y += event_channel.o
 obj-$(CONFIG_EVTCHN_FIFO) += 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..670682102c13
--- /dev/null
+++ b/xen/common/emul/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_HAS_VUART) += vuart/
diff --git a/xen/common/emul/vuart/Kconfig b/xen/common/emul/vuart/Kconfig
new file mode 100644
index 000000000000..02f7dd6dc1a1
--- /dev/null
+++ b/xen/common/emul/vuart/Kconfig
@@ -0,0 +1,6 @@
+config HAS_VUART
+       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..c6400b001e85
--- /dev/null
+++ b/xen/common/emul/vuart/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_HAS_VUART) += vuart.o
diff --git a/xen/common/emul/vuart/vuart.c b/xen/common/emul/vuart/vuart.c
new file mode 100644
index 000000000000..14a7f8bd8b79
--- /dev/null
+++ b/xen/common/emul/vuart/vuart.c
@@ -0,0 +1,112 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * UART emulator framework.
+ *
+ * Copyright 2025 Ford Motor Company
+ */
+
+#include <xen/errno.h>
+#include <xen/sched.h>
+#include <xen/vuart.h>
+
+#define VUART_ARRAY_SIZE    (__start_vuart_end - __start_vuart_array)
+
+#define for_each_vuart(vdev) \
+    for (unsigned __i = 0; \
+         __i < VUART_ARRAY_SIZE && (vdev = __start_vuart_array[__i], 1); \
+         __i++)
+
+extern const struct vuart_ops *const __start_vuart_array[];
+extern const struct vuart_ops *const __start_vuart_end[];
+
+int vuart_add_node(struct domain *d, const void *node)
+{
+    const struct vuart_ops *vdev;
+    int rc;
+
+    for_each_vuart(vdev)
+    {
+        if ( !vdev->add_node )
+            continue;
+
+        rc = vdev->add_node(d, node);
+        if ( rc )
+            return rc;
+    }
+
+    return 0;
+}
+
+int vuart_init(struct domain *d, struct vuart_params *params)
+{
+    const struct vuart_ops *vdev;
+    int rc;
+
+    if ( !domain_has_vuart(d) )
+        return 0;
+
+    for_each_vuart(vdev)
+    {
+        rc = vdev->init(d, params);
+        if ( rc )
+            return rc;
+    }
+
+    d->console.input_allowed = true;
+
+    return 0;
+}
+
+/*
+ * 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)
+{
+    const struct vuart_ops *vdev;
+
+    for_each_vuart(vdev)
+        vdev->deinit(d);
+}
+
+void vuart_dump_state(const struct domain *d)
+{
+    const struct vuart_ops *vdev;
+
+    for_each_vuart(vdev)
+        vdev->dump_state(d);
+}
+
+/*
+ * Put character to the first suitable emulated UART's FIFO.
+ */
+int vuart_put_rx(struct domain *d, char c)
+{
+    const struct vuart_ops *vdev = NULL;
+
+    ASSERT(domain_has_vuart(d));
+
+    for_each_vuart(vdev)
+        if ( vdev->put_rx )
+            break;
+
+    return vdev ? vdev->put_rx(d, c) : -ENODEV;
+}
+
+bool domain_has_vuart(const struct domain *d)
+{
+    uint32_t mask = 0;
+
+    return !!(d->emulation_flags & mask);
+}
+
+/*
+ * 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 eccd97c565c6..af427d25dc0d 100644
--- a/xen/common/keyhandler.c
+++ b/xen/common/keyhandler.c
@@ -22,6 +22,7 @@
 #include <xen/mm.h>
 #include <xen/watchdog.h>
 #include <xen/init.h>
+#include <xen/vuart.h>
 #include <asm/div64.h>
 
 static unsigned char keypress_key;
@@ -354,6 +355,8 @@ static void cf_check dump_domains(unsigned char key)
                            v->periodic_period / 1000000);
             }
         }
+
+        vuart_dump_state(d);
     }
 
     for_each_domain ( d )
diff --git a/xen/drivers/char/console.c b/xen/drivers/char/console.c
index 963c7b043cd8..93254979817b 100644
--- a/xen/drivers/char/console.c
+++ b/xen/drivers/char/console.c
@@ -33,6 +33,7 @@
 #include <asm/setup.h>
 #include <xen/sections.h>
 #include <xen/consoled.h>
+#include <xen/vuart.h>
 
 #ifdef CONFIG_X86
 #include <asm/guest.h>
@@ -601,6 +602,7 @@ static void __serial_rx(char c)
         /*
          * 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) != SERIAL_RX_SIZE )
             serial_rx_ring[SERIAL_RX_MASK(serial_rx_prod++)] = c;
@@ -611,6 +613,8 @@ static void __serial_rx(char c)
          */
         send_global_virq(VIRQ_CONSOLE);
     }
+    else if ( domain_has_vuart(d) )
+        rc = vuart_put_rx(d, c);
 #ifdef CONFIG_SBSA_VUART_CONSOLE
     else
         /* Deliver input to the emulated UART. */
diff --git a/xen/include/xen/vuart.h b/xen/include/xen/vuart.h
new file mode 100644
index 000000000000..e843026df4b1
--- /dev/null
+++ b/xen/include/xen/vuart.h
@@ -0,0 +1,84 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * UART emulator framework.
+ *
+ * Copyright 2025 Ford Motor Company
+ */
+
+#ifndef XEN_VUART_H
+#define XEN_VUART_H
+
+#include <public/xen.h>
+#include <public/event_channel.h>
+#include <xen/types.h>
+
+struct vuart_params {
+    domid_t console_domid;
+    gfn_t gfn;
+    evtchn_port_t evtchn;
+};
+
+struct vuart_ops {
+    int (*add_node)(struct domain *d, const void *node);
+    int (*init)(struct domain *d, struct vuart_params *params);
+    void (*deinit)(struct domain *d);
+    void (*dump_state)(const struct domain *d);
+    int (*put_rx)(struct domain *d, char c);
+};
+
+#define VUART_REGISTER(name, x) \
+    static const struct vuart_ops *const __name##_entry \
+        __used_section(".data.vuart." #name) = (x);
+
+#ifdef CONFIG_HAS_VUART
+
+int vuart_add_node(struct domain *d, const void *node);
+int vuart_init(struct domain *d, struct vuart_params *params);
+void vuart_deinit(struct domain *d);
+void vuart_dump_state(const struct domain *d);
+int vuart_put_rx(struct domain *d, char c);
+bool domain_has_vuart(const struct domain *d);
+
+#else
+
+static inline int vuart_add_node(struct domain *d, const void *node)
+{
+    return 0;
+}
+
+static inline int vuart_init(struct domain *d, struct vuart_params *params)
+{
+    return 0;
+}
+
+static inline void vuart_deinit(struct domain *d)
+{
+}
+
+static inline void vuart_dump_state(const struct domain *d)
+{
+}
+
+static inline int vuart_put_rx(struct domain *d, char c)
+{
+    ASSERT_UNREACHABLE();
+    return -ENODEV;
+}
+
+static inline bool domain_has_vuart(const struct domain *d)
+{
+    return false;
+}
+
+#endif /* CONFIG_HAS_VUART */
+
+#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..c2da180948ca 100644
--- a/xen/include/xen/xen.lds.h
+++ b/xen/include/xen/xen.lds.h
@@ -194,4 +194,14 @@
 #define VPCI_ARRAY
 #endif
 
+#ifdef CONFIG_HAS_VUART
+#define VUART_ARRAY     \
+       . = ALIGN(POINTER_ALIGN); \
+       __start_vuart_array = .;  \
+       *(SORT(.data.vuart.*))    \
+       __start_vuart_end = .;
+#else
+#define VUART_ARRAY
+#endif
+
 #endif /* __XEN_LDS_H__ */
-- 
2.34.1





 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.