All of lore.kernel.org
 help / color / mirror / Atom feed
From: dmkhn@proton.me
To: Jan Beulich <jbeulich@suse.com>
Cc: andrew.cooper3@citrix.com, anthony.perard@vates.tech,
	julien@xen.org, michal.orzel@amd.com, roger.pau@citrix.com,
	sstabellini@kernel.org, dmukhin@ford.com,
	xen-devel@lists.xenproject.org
Subject: Re: [PATCH v4 5/8] emul/vuart-ns16550: introduce NS16550-compatible UART emulator (x86)
Date: Sat, 09 Aug 2025 18:37:07 +0000	[thread overview]
Message-ID: <aJeVTIG2nU3bqGwO@starscream> (raw)
In-Reply-To: <5c0589a2-91fe-484d-bded-5a68a1626355@suse.com>

On Mon, Aug 04, 2025 at 12:53:36PM +0200, Jan Beulich wrote:
> On 31.07.2025 21:22, dmkhn@proton.me wrote:
> > From: Denis Mukhin <dmukhin@ford.com>
> >
> > Add initial in-hypervisor emulator for NS8250/NS16x50-compatible UARTs under
> > CONFIG_VUART_NS16550 for x86 port of Xen.
> >
> > x86 port of Xen lacks vUART facility similar to Arm's SBSA emulator to support
> > x86 guest OS bring up in the embedded setups.
> >
> > In parallel domain creation scenario (hyperlaunch), NS16550 emulator helps
> > early guest firmware and/or OS bringup debugging, because it eliminates
> > dependency on the external emulator (qemu) being operational by the time
> > domains are created.
> >
> > The emulator also allows to forward the physical console input to the x86
> > domain which is useful when a system has only one physical UART for early
> > debugging and this UART is owned by Xen. Such functionality is limited to dom0
> > use currently.
> >
> > By default, CONFIG_VUART_NS16550 enables emulation of NS16550 at I/O port
> > 0x3f8, IRQ#4 in guest OS (legacy COM1).
> >
> > Legacy COM resources can be selected at built-time and cannot be configured
> > per-domain via .cfg or DT yet.
> >
> > Introduce new emulation flag for virtual UART on x86 and plumb it through
> > domain creation code so NS16550 emulator can be instantiated properly.
> >
> > Please refer to the NS16550 emulator code for full list of limitations.
> >
> > Signed-off-by: Denis Mukhin <dmukhin@ford.com>
> > ---
> > Changes since v3:
> > - feedback addressed
> > - adjusted to new vUART framework APIs
> > - Link to v3: https://lore.kernel.org/xen-devel/20250103-vuart-ns8250-v3-v1-21-c5d36b31d66c@ford.com/
> > ---
> >  xen/arch/x86/hvm/hvm.c                |    9 +
> >  xen/arch/x86/include/asm/domain.h     |    4 +-
> >  xen/arch/x86/include/asm/hvm/domain.h |    4 +
> >  xen/common/emul/vuart/Kconfig         |   48 ++
> >  xen/common/emul/vuart/Makefile        |    1 +
> >  xen/common/emul/vuart/vuart-ns16550.c | 1009 +++++++++++++++++++++++++
> >  xen/common/emul/vuart/vuart.c         |    4 +
> >  xen/include/public/arch-x86/xen.h     |    4 +-
> >  xen/include/xen/resource.h            |    3 +
> >  9 files changed, 1084 insertions(+), 2 deletions(-)
> >  create mode 100644 xen/common/emul/vuart/vuart-ns16550.c
> 
> Overall I think this patch is too large to sensibly review. Surely base structure
> and then (incrementally) fleshing out of the hooks can be separated from one
> another?

I'll do a split.

> 
> > --- a/xen/arch/x86/hvm/hvm.c
> > +++ b/xen/arch/x86/hvm/hvm.c
> > @@ -31,6 +31,7 @@
> >  #include <xen/nospec.h>
> >  #include <xen/vm_event.h>
> >  #include <xen/console.h>
> > +#include <xen/vuart.h>
> >  #include <asm/shadow.h>
> >  #include <asm/hap.h>
> >  #include <asm/current.h>
> > @@ -702,6 +703,10 @@ int hvm_domain_initialise(struct domain *d,
> >      if ( rc != 0 )
> >          goto fail1;
> >
> > +    rc = vuart_init(d, NULL);
> > +    if ( rc != 0 )
> > +        goto out_vioapic_deinit;
> > +
> >      stdvga_init(d);
> >
> >      rtc_init(d);
> > @@ -725,6 +730,8 @@ int hvm_domain_initialise(struct domain *d,
> >      return 0;
> >
> >   fail2:
> > +    vuart_deinit(d);
> > + out_vioapic_deinit:
> >      vioapic_deinit(d);
> >   fail1:
> >      if ( is_hardware_domain(d) )
> 
> Would be better if vuart_deinit() was idempotent, and hence could be called
> unconditionally here.

Agree, vuart_deinit() is idempotent even in this submisson.
Will update.

> 
> > @@ -787,6 +794,8 @@ void hvm_domain_destroy(struct domain *d)
> >      if ( hvm_funcs.domain_destroy )
> >          alternative_vcall(hvm_funcs.domain_destroy, d);
> >
> > +    vuart_deinit(d);
> 
> You require a fair level of idempotency already anyway, as a domain may not
> have any vUART, so this call already needs to be "capabale" of doing nothing.
> 
> > --- a/xen/arch/x86/include/asm/hvm/domain.h
> > +++ b/xen/arch/x86/include/asm/hvm/domain.h
> > @@ -149,6 +149,10 @@ struct hvm_domain {
> >  #ifdef CONFIG_MEM_SHARING
> >      struct mem_sharing_domain mem_sharing;
> >  #endif
> > +
> > +#ifdef CONFIG_VUART_NS16550
> > +    void *vuart; /* Virtual UART handle. */
> > +#endif
> >  };
> 
> With your framework you allow for multiple vUART drivers. Either the field
> looks misnamed or the CONFIG_* option checked is the wrong one.

Agree; will update.

> 
> Also, why's this x86-specific? NS16550s can exist anywhere, can't they?
> (The present, but presumably temporary tying to x86 looks to be the use of
> I/O ports.)

struct hvm_domain is arch-specific.

I do not think I need to add NS16550 to, say RISC-V's, hvm_domain without
implementing MMIO part and guest DT-binding generation.

> 
> > --- a/xen/common/emul/vuart/Kconfig
> > +++ b/xen/common/emul/vuart/Kconfig
> > @@ -3,4 +3,52 @@ config HAS_VUART
> >
> >  menu "UART Emulation"
> >
> > +config VUART_NS16550
> > +	bool "NS16550-compatible UART Emulation" if EXPERT
> > +	depends on X86 && HVM
> > +	select HAS_VUART
> > +	help
> > +	  In-hypervisor NS16550/NS16x50 UART emulation.
> > +
> > +	  Only legacy PC I/O ports are emulated.
> > +
> > +	  This is strictly for testing purposes (such as early HVM guest console),
> > +	  and not appropriate for use in production.
> > +
> > +choice VUART_NS16550_PC
> > +	prompt "IBM PC COM resources"
> > +	depends on VUART_NS16550
> > +	default VUART_NS16550_PC_COM1
> > +	help
> > +	  Default emulated NS16550 resources.
> > +
> > +config VUART_NS16550_PC_COM1
> > +	bool "COM1 (I/O port 0x3f8, IRQ#4)"
> > +
> > +config VUART_NS16550_PC_COM2
> > +	bool "COM2 (I/O port 0x2f8, IRQ#3)"
> > +
> > +config VUART_NS16550_PC_COM3
> > +	bool "COM3 (I/O port 0x3e8, IRQ#4)"
> > +
> > +config VUART_NS16550_PC_COM4
> > +	bool "COM4 (I/O port 0x2e8, IRQ#3)"
> > +
> > +endchoice
> > +
> > +config VUART_NS16550_LOG_LEVEL
> > +	int "UART emulator verbosity level"
> > +	range 0 3
> > +	default "1"
> > +	depends on VUART_NS16550
> > +	help
> > +	  Set the default log level of UART emulator.
> > +	  See include/xen/config.h for more details.
> 
> For someone merely running kconfig but not otherwise knowing the sources,
> this isn't an overly helful pointer. But I question the need for such a
> control anyway, and I think I did say so already before.

I'll drop that Kconfig setting.

> 
> > +config VUART_NS16550_DEBUG
> > +	bool "UART emulator development debugging"
> > +	depends on VUART_NS16550
> 
> && DEBUG ?

I will drop that Kconfig.

> 
> > --- a/xen/common/emul/vuart/Makefile
> > +++ b/xen/common/emul/vuart/Makefile
> > @@ -1 +1,2 @@
> >  obj-$(CONFIG_HAS_VUART) += vuart.o
> > +obj-$(CONFIG_VUART_NS16550) += vuart-ns16550.o
> 
> I don't think files in this directory need a vuart- name prefix.

Ack.

Hmm, there's already ns16550.c which is UART driver, so it may be confusing to
have two ns16550s (although in different directories).

I do not have a strong preference on the naming here.

> 
> > --- /dev/null
> > +++ b/xen/common/emul/vuart/vuart-ns16550.c
> > @@ -0,0 +1,1009 @@
> > +/* SPDX-License-Identifier: GPL-2.0-only */
> > +/*
> > + * NS16550-compatible UART Emulator.
> > + *
> > + * See:
> > + * - Serial and UART Tutorial:
> > + *     https://download.freebsd.org/doc/en/articles/serial-uart/serial-uart_en.pdf
> > + * - UART w/ 16 byte FIFO:
> > + *     https://www.ti.com/lit/ds/symlink/tl16c550c.pdf
> > + * - UART w/ 64 byte FIFO:
> > + *     https://www.ti.com/lit/ds/symlink/tl16c750.pdf
> > + *
> > + * Limitations:
> > + * - Only x86;
> > + * - Only HVM domains support (build-time), PVH domains are not supported yet;
> > + * - Only legacy COM{1,2,3,4} resources via Kconfig, custom I/O ports/IRQs
> > + *   are not supported;
> > + * - Only Xen console as a backend, no inter-domain communication (similar to
> > + *   vpl011 on Arm);
> > + * - Only 8n1 emulation (8-bit data, no parity, 1 stop bit);
> > + * - No toolstack integration;
> > + * - No baud rate emulation (reports 115200 baud to the guest OS);
> > + * - No FIFO-less mode emulation;
> > + * - No RX FIFO interrupt moderation (FCR) emulation;
> > + * - No integration w/ VM snapshotting (HVM_REGISTER_SAVE_RESTORE() and
> > + *   friends);
> > + * - No ISA IRQ sharing allowed;
> > + * - No MMIO-based UART emulation.
> > + */
> > +
> > +#define pr_prefix               "ns16550"
> > +#define pr_fmt(fmt)             pr_prefix ": " fmt
> > +#define pr_log_level            CONFIG_VUART_NS16550_LOG_LEVEL
> > +
> > +#include <xen/8250-uart.h>
> > +#include <xen/console.h>
> > +#include <xen/iocap.h>
> > +#include <xen/ioreq.h>
> > +#include <xen/resource.h>
> > +#include <xen/vuart.h>
> > +#include <xen/xvmalloc.h>
> > +
> > +#include <public/io/console.h>
> 
> Except for cases where Xen itself runs as a guest, I don't think any of these
> headers should be used in Xen sources. If I'm not mistaken, ...

I'll double check, thanks.

> 
> > +/*
> > + * Virtual NS16550 device state.
> > + */
> > +struct vuart_ns16550 {
> > +    struct xencons_interface cons;      /* Emulated RX/TX FIFOs */
> 
> ... this also isn't to communicate with some remote, but merely to use some
> of the fields conveniently.

The plan is to add peer-to-peer connection over vUART similarly to existing
vpl011.

> 
> > +    uint8_t regs[NS16550_EMU_REGS_NUM]; /* Emulated registers */
> > +    unsigned int irq;                   /* Emulated IRQ# */
> > +    uint64_t io_addr;                   /* Emulated I/O region base address */
> > +    uint64_t io_size;                   /* Emulated I/O region size */
> 
> These are huge; for the size that's true even if considering future MMIO-
> based emulation.

Ack.

> 
> > +    const char *name;                   /* Device name */
> > +    struct domain *owner;               /* Owner domain */
> > +    spinlock_t lock;                    /* Protection */
> > +};
> > +
> > +/*
> > + * Virtual device description.
> > + */
> > +struct virtdev_desc {
> > +    const char *name;
> > +    const struct resource *res;
> > +};
> > +
> > +/*
> > + * Legacy IBM PC NS16550 resources.
> > + * There are only 4 I/O port ranges, hardcoding all of them here.
> > + */
> > +static const struct virtdev_desc x86_pc_uarts[4] = {
> > +    [0] = {
> > +        .name = "COM1",
> > +        .res = (const struct resource[]){
> > +            { .type = IORESOURCE_IO,  .addr = 0x3f8, .size = NS16550_REGS_NUM },
> > +            { .type = IORESOURCE_IRQ, .addr = 4,     .size = 1 },
> > +            { .type = IORESOURCE_UNKNOWN },
> > +        },
> > +    },
> > +    [1] = {
> > +        .name = "COM2",
> > +        .res = (const struct resource[]){
> > +            { .type = IORESOURCE_IO,  .addr = 0x2f8, .size = NS16550_REGS_NUM },
> > +            { .type = IORESOURCE_IRQ, .addr = 3,     .size = 1 },
> > +            { .type = IORESOURCE_UNKNOWN },
> > +        },
> > +    },
> > +    [2] = {
> > +        .name = "COM3",
> > +        .res = (const struct resource[]){
> > +            { .type = IORESOURCE_IO,  .addr = 0x3e8, .size = NS16550_REGS_NUM },
> > +            { .type = IORESOURCE_IRQ, .addr = 4,     .size = 1 },
> > +            { .type = IORESOURCE_UNKNOWN },
> > +        },
> > +    },
> > +    [3] = {
> > +        .name = "COM4",
> > +        .res = (const struct resource[]){
> > +            { .type = IORESOURCE_IO,  .addr = 0x2e8, .size = NS16550_REGS_NUM },
> > +            { .type = IORESOURCE_IRQ, .addr = 3,     .size = 1 },
> > +            { .type = IORESOURCE_UNKNOWN },
> > +        },
> > +    },
> > +};
> 
> The choice of COMn is at build time. Why do we need all four configurations
> resident not only in the binary, but even at (post-init) runtime? Also, the
> way you do initialization of .res, I think adding __initconst to the main
> array wouldn't have the effect of pulling all those inti .init.* as well.
> For the time being I simply don't see the need for the extra level of
> indirection: All instances have two entries (plus the then likely not
> necessary sentinel).

Will rework that.

> 
> > +static bool cf_check ns16550_iir_check_lsi(const struct vuart_ns16550 *vdev)
> > +{
> > +    return !!(vdev->regs[UART_LSR] & UART_LSR_MASK);
> 
> No need for !! (also elsewhere).

Ack.

> 
> > --- a/xen/include/xen/resource.h
> > +++ b/xen/include/xen/resource.h
> > @@ -31,4 +31,7 @@ struct resource {
> >
> >  #define resource_size(res)      ((res)->size)
> >
> > +#define for_each_resource(res) \
> > +    for ( ; (res) && (res)->type != IORESOURCE_UNKNOWN; (res)++ )
> 
> I'm not sure this is a good generic #define; imo it wants keeping local to
> the one file that uses it.

Ack.

> 
> Jan
> 



  reply	other threads:[~2025-08-09 18:37 UTC|newest]

Thread overview: 61+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-07-31 19:21 [PATCH v4 0/8] x86: introduce NS16550-compatible UART emulator dmkhn
2025-07-31 19:21 ` [PATCH v4 1/8] xen/domain: introduce common emulation flags dmkhn
2025-08-04  9:46   ` Jan Beulich
2025-08-05  0:54     ` dmkhn
2025-08-06 13:56       ` Roger Pau Monné
2025-08-07 17:54         ` dmkhn
2025-08-07 14:28       ` Oleksii Kurochko
2025-08-07 17:43         ` dmkhn
2025-07-31 19:21 ` [PATCH v4 2/8] emul/vuart: introduce framework for UART emulators dmkhn
2025-08-01  0:08   ` Stefano Stabellini
2025-08-01  2:54     ` dmkhn
2025-08-04 10:11   ` Jan Beulich
2025-08-09 18:55     ` dmkhn
2025-08-11  7:34       ` Jan Beulich
2025-08-11 23:55         ` dmkhn
2025-08-12  6:52           ` Jan Beulich
2025-08-14  6:32             ` dmkhn
2025-08-06 14:24   ` Roger Pau Monné
2025-08-07 19:12     ` dmkhn
2025-07-31 19:21 ` [PATCH v4 3/8] x86/domain: allocate d->{iomem,irq}_caps before arch-specific initialization dmkhn
2025-07-31 19:52   ` Grygorii Strashko
2025-07-31 20:21     ` dmkhn
2025-08-01  2:57       ` dmkhn
2025-07-31 23:20   ` Stefano Stabellini
2025-08-04 10:20   ` Jan Beulich
2025-08-07 18:59     ` dmkhn
2025-08-06 14:37   ` Roger Pau Monné
2025-08-07 18:57     ` dmkhn
2025-07-31 19:22 ` [PATCH v4 4/8] xen/8250-uart: update definitions dmkhn
2025-07-31 23:23   ` Stefano Stabellini
2025-08-04 10:23   ` Jan Beulich
2025-08-07 19:41     ` dmkhn
2025-07-31 19:22 ` [PATCH v4 5/8] emul/vuart-ns16550: introduce NS16550-compatible UART emulator (x86) dmkhn
2025-07-31 23:57   ` Stefano Stabellini
2025-08-01  3:28     ` dmkhn
2025-08-04 10:53   ` Jan Beulich
2025-08-09 18:37     ` dmkhn [this message]
2025-08-11  7:39       ` Jan Beulich
2025-08-12  0:06         ` dmkhn
2025-08-06 15:06   ` Roger Pau Monné
2025-08-06 17:24     ` Roger Pau Monné
2025-08-07 18:49     ` dmkhn
2025-07-31 19:22 ` [PATCH v4 6/8] tools/xl: enable NS16550-compatible UART emulator for HVM (x86) dmkhn
2025-08-04 10:54   ` Jan Beulich
2025-08-06 15:21   ` Roger Pau Monné
2025-08-25 14:49   ` Anthony PERARD
2025-08-25 15:03     ` Jan Beulich
2025-08-25 15:13       ` Anthony PERARD
2025-08-25 15:27         ` Jan Beulich
2025-08-25 15:39           ` Anthony PERARD
2025-08-25 15:45             ` Jan Beulich
2025-08-26  9:26     ` dmkhn
2025-07-31 19:22 ` [PATCH v4 7/8] tools/xl: enable NS16550-compatible UART emulator for PVH (x86) dmkhn
2025-08-01  0:46   ` Stefano Stabellini
2025-08-01  1:53     ` dmkhn
2025-08-04 11:06   ` Jan Beulich
2025-08-07 19:38     ` dmkhn
2025-07-31 19:22 ` [PATCH v4 8/8] emul/vuart: introduce console forwarding enforcement via vUART dmkhn
2025-08-01  0:10   ` Stefano Stabellini
2025-08-01  1:51     ` dmkhn
2025-08-06 13:48 ` [PATCH v4 0/8] x86: introduce NS16550-compatible UART emulator Roger Pau Monné

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=aJeVTIG2nU3bqGwO@starscream \
    --to=dmkhn@proton.me \
    --cc=andrew.cooper3@citrix.com \
    --cc=anthony.perard@vates.tech \
    --cc=dmukhin@ford.com \
    --cc=jbeulich@suse.com \
    --cc=julien@xen.org \
    --cc=michal.orzel@amd.com \
    --cc=roger.pau@citrix.com \
    --cc=sstabellini@kernel.org \
    --cc=xen-devel@lists.xenproject.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.