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

[PATCH v8 10/26] emul/ns16x50: implement RBR register


  • To: xen-devel@xxxxxxxxxxxxxxxxxxxx
  • From: dmukhin@xxxxxxxx
  • Date: Wed, 11 Nov 2026 11:47:44 -0800
  • Arc-authentication-results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 205.220.161.53) smtp.rcpttodomain=lists.xenproject.org smtp.mailfrom=ford.com; dmarc=pass (p=reject sp=reject pct=100) action=none header.from=ford.com; dkim=pass (signature was verified) header.d=saarlouis.ford.com; dkim=pass (signature was verified) header.d=ford.com; arc=none (0)
  • Arc-message-signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=tpH/jn4+M7frt8tAasI2ACt3HCQdkODdjuyx7wToXhE=; b=N5IcnK2y03+mKiU4kLTZlCERl6rYzJ5YN4N0eZVaIGhESvdiX8VLeFfkChWIBzjJ+3iUB/60PThYzfEtCIoA0d5NAAPjtprNp7Wx6OO3lxgAUtfO3ajadLFIDwhsuqI0tAdwruMH452ERjAvQBkLPBjk63cJ/V3HQL56nF812RA1Xa+NzdVGwo1jSaXufZBRpTgjH70x5HFP3z5yjechx3QfmLd4//9yOxpvvqoPcxn6ksaNZz0sI4rP01PSDmhw/snS98BgH/gOsGsAFQiRbDSdLpcrxLv8f3F8YKOfQgwdjTKz9bB+zQrnASWDR2H4zy6xiDNbdcjNAVZh69cziw==
  • Arc-seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=sHmTJGac4+Ij80SGlZNKvIjnABCDOhwAJgxhuX8WvJVuE9+/hv4HUDcuGf5baPWJJBEMXQWcCzrlSUuXj/ytjCXIOmN8CFEV/AmJc8i/cEVpRRNDD6+aJCbSjiV7s6N3IslCTDkNw9pLcsqDI6gb8bfxM747d2UrrvBAz2ow3HzIHXDjbPdirY2nR/9YKtHupPt7GUAFNvdzyH5xb51n46djgZfAtu//GQuE24OlrxwBTIVnuAaPX4SjPiVVjY1fG+mi5piffsc0iMAF915JAxJpo28Qr/mfkhYwMJAHFOLUSaKfYSyj7aIh36KJMaOyPldSSXSaTInN2+AOc/zgdw==
  • Authentication-results: eu.smtp.expurgate.cloud; dkim=pass header.s=ppford header.d=ford.com header.i="@ford.com" header.h="Cc:Content-Transfer-Encoding:Content-Type:Date:From:In-Reply-To:Message-ID:MIME-Version:References:Subject:To"; dkim=pass header.s=selector2-azureford-onmicrosoft-com header.d=azureford.onmicrosoft.com header.i="@azureford.onmicrosoft.com" header.h="From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck"; dkim=pass header.s=ppserprodsaar header.d=saarlouis.ford.com header.i="@saarlouis.ford.com" header.h="Cc:Content-Transfer-Encoding:Date:From:In-Reply-To:Message-ID:MIME-Version:References:Subject:To"; dkim=pass header.s=ppfserpocford header.d=ford.com header.i="@ford.com" header.h="Cc:Content-Transfer-Encoding:Date:From:In-Reply-To:Message-ID:MIME-Version:References:Subject:To"
  • Cc: andrew.cooper3@xxxxxxxxxx, anthony.perard@xxxxxxxxxx, jbeulich@xxxxxxxx, julien@xxxxxxx, michal.orzel@xxxxxxx, roger@xxxxxxxxxxxxxx, sstabellini@xxxxxxxxxx, xakep.amatop@xxxxxxxxx, dmukhin@xxxxxxx, Denis Mukhin <dmukhin@xxxxxxxx>
  • Delivery-date: Wed, 11 Nov 2026 19:48:49 +0000
  • List-id: Xen developer discussion <xen-devel.lists.xenproject.org>
  • Pser-m365-app: SER-APP

From: Denis Mukhin <dmukhin@xxxxxxxx>

Add RBR register emulation to the I/O port handlder.

Add RX FIFO management code since RBR depends on RX FIFO.

Emulator does not emulate NS8250 (no FIFO), NS16550a (16 bytes)
or NS16750 (64 bytes) precisely for simplicity. No baud rate
emulation either.

RX FIFO is emulated by means of using xencons_interface which
conveniently provides primitives for buffer management and later can be
used for inter-domain communication similarly to vpl011.

Account for DLL == 0: in this case, disable receiver.

Add UART_LSR_DR handling since it depends on RBR register access.

Implement put_rx() vUART hook for placing a character into the
emulated RX FIFO from console driver. That implements physical console
forwarding to the guest OS over emulated NS16550.

Signed-off-by: Denis Mukhin <dmukhin@xxxxxxxx>
---
 xen/common/emul/vuart/ns16x50.c | 132 +++++++++++++++++++++++++++++++-
 1 file changed, 130 insertions(+), 2 deletions(-)

diff --git a/xen/common/emul/vuart/ns16x50.c b/xen/common/emul/vuart/ns16x50.c
index 9f530e589495..d04caf2baf2c 100644
--- a/xen/common/emul/vuart/ns16x50.c
+++ b/xen/common/emul/vuart/ns16x50.c
@@ -123,6 +123,76 @@ static inline void ns16x50_unlock(struct vuart_ns16x50 
*vdev,
     spin_unlock(&vdev->lock);
 }
 
+static bool ns16x50_fifo_rx_empty(const struct vuart_ns16x50 *vdev)
+{
+    const struct xencons_interface *cons = &vdev->cons;
+
+    return cons->in_prod == cons->in_cons;
+}
+
+static bool ns16x50_fifo_rx_full(const struct vuart_ns16x50 *vdev)
+{
+    const struct xencons_interface *cons = &vdev->cons;
+
+    return cons->in_prod - cons->in_cons == ARRAY_SIZE(cons->in);
+}
+
+static void ns16x50_fifo_rx_reset(struct vuart_ns16x50 *vdev)
+{
+    struct xencons_interface *cons = &vdev->cons;
+
+    cons->in_cons = cons->in_prod;
+}
+
+/*
+ * Transfer character from RX FIFO and return the RX FIFO status after the
+ * transfer.
+ */
+static int ns16x50_fifo_rx_getchar(struct vuart_ns16x50 *vdev, uint8_t *ptr)
+{
+    struct xencons_interface *cons = &vdev->cons;
+
+    if ( ns16x50_fifo_rx_empty(vdev) )
+        return -ENODATA;
+
+    *ptr = cons->in[MASK_XENCONS_IDX(cons->in_cons, cons->in)];
+    cons->in_cons++;
+
+    return ns16x50_fifo_rx_empty(vdev) ? -ENODATA : 0;
+}
+
+static int ns16x50_fifo_rx_putchar(struct vuart_ns16x50 *vdev, char c)
+{
+    struct xencons_interface *cons = &vdev->cons;
+    int rc;
+
+    /*
+     * FIFO-less 8250/16450 UARTs: newly arrived word overwrites the contents
+     * of the THR.
+     */
+    if ( ns16x50_fifo_rx_full(vdev) )
+    {
+        ns16x50_debug(vdev, "RX FIFO full; resetting\n");
+        ns16x50_fifo_rx_reset(vdev);
+        rc = -ENOSPC;
+    }
+    else
+        rc = 0;
+
+    cons->in[MASK_XENCONS_IDX(cons->in_prod, cons->in)] = c;
+    cons->in_prod++;
+
+    return rc;
+}
+
+static bool ns16x50_is_tranceiver_enabled(const struct vuart_ns16x50 *vdev)
+{
+    BUG_ON(vdev->regs[UART_LCR] & UART_LCR_DLAB);
+
+    /* DLL set to 0 disables serial communication. */
+    return vdev->regs[NS16X50_REGS_NUM + UART_DLL];
+}
+
 static bool cf_check ns16x50_iir_check_lsi(const struct vuart_ns16x50 *vdev)
 {
     return vdev->regs[UART_LSR] & UART_LSR_MASK;
@@ -130,7 +200,7 @@ static bool cf_check ns16x50_iir_check_lsi(const struct 
vuart_ns16x50 *vdev)
 
 static bool cf_check ns16x50_iir_check_rda(const struct vuart_ns16x50 *vdev)
 {
-    return false;
+    return !ns16x50_fifo_rx_empty(vdev);
 }
 
 static bool cf_check ns16x50_iir_check_thr(const struct vuart_ns16x50 *vdev)
@@ -400,6 +470,17 @@ static int ns16x50_io_read8(
         }
 
         /* DLAB=0 */
+        if ( !ns16x50_is_tranceiver_enabled(vdev) )
+            break;
+
+        /* NB: do not forget to clear overrun condition */
+        regs[UART_LSR] &= ~UART_LSR_OE;
+
+        if ( ns16x50_fifo_rx_getchar(vdev, &val) )
+            regs[UART_LSR] &= ~UART_LSR_DR;
+        else
+            regs[UART_LSR] |= UART_LSR_DR;
+
         break;
 
     case UART_IER: /* DLAB=0 --> UART_IER, DLAB=1 --> UART_DLM */
@@ -694,13 +775,60 @@ static void cf_check ns16x50_free(void *arg)
     xvfree(arg);
 }
 
+static int cf_check ns16x50_put_rx(void *arg, char ch)
+{
+    struct vuart_ns16x50 *vdev = arg;
+    unsigned long flags;
+    uint8_t *regs;
+    int rc = -EBUSY;
+
+    ASSERT(vdev);
+
+    ns16x50_lock(vdev, &flags);
+
+    regs = vdev->regs;
+
+    if ( vdev->regs[UART_LCR] & UART_LCR_DLAB )
+        ns16x50_debug(vdev, "THR/RBR access disabled: DLAB=1\n");
+    else if ( !ns16x50_is_tranceiver_enabled(vdev) )
+        ns16x50_debug(vdev, "THR/RBR access disabled: DLAB=0 DLL=0\n");
+    else if ( regs[UART_MCR] & UART_MCR_LOOP )
+        ns16x50_debug(vdev, "THR/RBR access disabled: DLAB=0 loopback mode\n");
+    else
+    {
+        const struct domain *d = vdev->owner;
+
+        /*
+         * Echo the user input on Xen console iff Xen console input is owned
+         * by ns16x50 domain.
+         * NB: use 'console_timestamps=none' to disable Xen timestamps.
+         */
+        if ( is_console_printable(ch) )
+            guest_printk(d, "%c", ch);
+
+        if ( ns16x50_fifo_rx_putchar(vdev, ch) )
+            regs[UART_LSR] |= UART_LSR_OE;
+
+        regs[UART_LSR] |= UART_LSR_DR;
+
+        /* TODO: check FCR when to fire an interrupt */
+        ns16x50_irq_check(vdev);
+
+        rc = 0;
+    }
+
+    ns16x50_unlock(vdev, &flags);
+
+    return rc;
+}
+
 #define ns16x50_emulator                \
 {                                       \
     .compatible = "ns16550",            \
     .alloc      = ns16x50_alloc,        \
     .free       = ns16x50_free,         \
     .dump_state = NULL,                 \
-    .put_rx     = NULL,                 \
+    .put_rx     = ns16x50_put_rx,       \
 }
 
 VUART_REGISTER(ns16x50, ns16x50_emulator);
-- 
2.56.0




 


Rackspace

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