From: Denis Mukhin <dmukhin@ford.com>
Implement dump_state() vUART hook for debugging UART state machine over Xen
console. dump_state() prints state of all emulated registers (including
state-less IIR) and state of RX/TX FIFOs.
Signed-off-by: Denis Mukhin <dmukhin@ford.com>
---
Changes since v5:
- Fixed printouts formatters
- Link to v5: https://lore.kernel.org/xen-devel/20250828235409.2835815-13-dmukhin@ford.com/
---
xen/common/emul/vuart/ns16x50.c | 59 ++++++++++++++++++++++++++++++++-
1 file changed, 58 insertions(+), 1 deletion(-)
diff --git a/xen/common/emul/vuart/ns16x50.c b/xen/common/emul/vuart/ns16x50.c
index 3fc1112709df..a4fa3a9be713 100644
--- a/xen/common/emul/vuart/ns16x50.c
+++ b/xen/common/emul/vuart/ns16x50.c
@@ -648,6 +648,58 @@ static int ns16x50_io_read(
return rc;
}
+static void cf_check ns16x50_dump_state(void *arg)
+{
+#ifdef CONFIG_VUART_NS16X50_DEBUG
+ struct vuart_ns16x50 *vdev = arg;
+ const struct domain *d = vdev->owner;
+ const struct vuart_info *info = vdev->info;
+ const struct xencons_interface *cons;
+ const uint8_t *regs;
+
+ if ( !vdev )
+ return;
+
+ /* Allow printing state in case of a deadlock. */
+ if ( !spin_trylock(&vdev->lock) )
+ return;
+
+ cons = &vdev->cons;
+ regs = &vdev->regs[0];
+
+ printk("Virtual " pr_prefix " (%s) I/O port 0x%04x IRQ#%d owner %pd\n",
+ vdev->name, info->base_addr, info->irq, d);
+
+ printk(" RX FIFO size %ld in_prod %d in_cons %d used %d\n",
+ ARRAY_SIZE(cons->in), cons->in_prod, cons->in_cons,
+ cons->in_prod - cons->in_cons);
+
+ printk(" TX FIFO size %ld out_prod %d out_cons %d used %d\n",
+ ARRAY_SIZE(cons->out), cons->out_prod, cons->out_cons,
+ cons->out_prod - cons->out_cons);
+
+ printk(" %02"PRIx8" RBR %02"PRIx8" THR %02"PRIx8" DLL %02"PRIx8" DLM %02"PRIx8"\n",
+ UART_RBR,
+ cons->in[MASK_XENCONS_IDX(cons->in_prod, cons)],
+ cons->out[MASK_XENCONS_IDX(cons->out_prod, cons)],
+ regs[NS16X50_REGS_NUM + UART_DLL],
+ regs[NS16X50_REGS_NUM + UART_DLM]);
+
+ printk(" %02"PRIx8" IER %02"PRIx8"\n", UART_IER, regs[UART_IER]);
+
+ printk(" %02"PRIx8" FCR %02"PRIx8" IIR %02"PRIx8"\n",
+ UART_FCR, regs[UART_FCR], ns16x50_iir_get(vdev));
+
+ printk(" %02"PRIx8" LCR %02"PRIx8"\n", UART_LCR, regs[UART_LCR]);
+ printk(" %02"PRIx8" MCR %02"PRIx8"\n", UART_MCR, regs[UART_MCR]);
+ printk(" %02"PRIx8" LSR %02"PRIx8"\n", UART_LSR, regs[UART_LSR]);
+ printk(" %02"PRIx8" MSR %02"PRIx8"\n", UART_MSR, regs[UART_MSR]);
+ printk(" %02"PRIx8" SCR %02"PRIx8"\n", UART_SCR, regs[UART_SCR]);
+
+ spin_unlock(&vdev->lock);
+#endif /* CONFIG_VUART_NS16X50_DEBUG */
+}
+
/*
* Emulate I/O access to ns16x50 register.
* Note, emulation always returns X86EMUL_OKAY, once I/O port trap is enabled.
@@ -724,6 +776,9 @@ static int cf_check ns16x50_io_handle(
spin_unlock(&vdev->lock);
+ if ( ns16x50_log_level >= 3 )
+ ns16x50_dump_state(vdev);
+
out:
rcu_unlock_domain(d);
@@ -854,6 +909,8 @@ static int cf_check ns16x50_put_rx(void *arg, char ch)
}
spin_unlock(&vdev->lock);
+ if ( ns16x50_log_level >= 3 )
+ ns16x50_dump_state(vdev);
return rc;
}
@@ -863,7 +920,7 @@ static int cf_check ns16x50_put_rx(void *arg, char ch)
.compatible = "ns16550", \
.alloc = ns16x50_alloc, \
.free = ns16x50_free, \
- .dump_state = NULL, \
+ .dump_state = ns16x50_dump_state, \
.put_rx = ns16x50_put_rx, \
}
--
2.51.0