@@ -25,6 +25,7 @@
/* Development debugging */
#define NS8250_LOG_LEVEL 0
+#undef NS8250_DEBUG
#include <xen/types.h>
#include <xen/event.h>
@@ -35,6 +36,9 @@
#include <xen/resource.h>
#include <xen/ctype.h>
#include <xen/param.h>
+#if defined(NS8250_DEBUG)
+#include <xen/keyhandler.h>
+#endif
#include <xen/console.h> /* console_input_domid() */
#include <asm/setup.h> /* max_init_domid */
#include <asm/iocap.h>
@@ -625,6 +629,121 @@ static const char *ns8250_regname(
return reg_names[reg][dir];
}
+#if defined(NS8250_DEBUG)
+static void ns8250_dump(struct vuart_ns8250 *vdev)
+{
+ struct xencons_interface *cons = vdev->cons;
+ uint8_t val;
+
+ printk("I/O port %02"PRIx64" IRQ %d flags %"PRIx32" owner %d\n",
+ vdev->io_addr, vdev->irq,
+ vdev->flags, vdev->owner->domain_id);
+
+ printk("RX size %ld in_prod %d in_cons %d used %d\n",
+ sizeof(cons->in),
+ cons->in_prod, cons->in_cons,
+ cons->in_prod - cons->in_cons);
+
+ printk("TX size %ld out_prod %d out_cons %d used %d\n",
+ sizeof(cons->out),
+ cons->out_prod, cons->out_cons,
+ cons->out_prod - cons->out_cons);
+
+ printk("%02x RBR [ %c ] THR [ %c ] DLL %02x DLM %02x\n",
+ UART_RBR,
+ cons->in[MASK_XENCONS_IDX(cons->in_prod, cons)],
+ cons->out[MASK_XENCONS_IDX(cons->out_prod, cons)],
+ vdev->dl & 0xFFU, vdev->dl >> 8);
+
+ printk("%02"PRIx8" IER %02"PRIx8"\n", UART_IER, vdev->regs[UART_IER]);
+
+ val = (vdev->regs[UART_FCR] & UART_FCR_ENABLE) ? UART_IIR_FE_MASK : 0;
+ val |= ns8250_irq_reason(vdev);
+ printk("%02"PRIx8" FCR %02"PRIx8" IIR %02"PRIx8"\n",
+ UART_FCR, vdev->regs[UART_FCR], val);
+
+ printk("%02"PRIx8" LCR %02"PRIx8"\n", UART_LCR, vdev->regs[UART_LCR]);
+ printk("%02"PRIx8" MCR %02"PRIx8"\n", UART_MCR, vdev->regs[UART_MCR]);
+ printk("%02"PRIx8" LSR %02"PRIx8"\n", UART_LSR, vdev->regs[UART_LSR]);
+ printk("%02"PRIx8" MSR %02"PRIx8"\n", UART_MSR, vdev->regs[UART_MSR]);
+}
+
+static struct domain *rcu_find_first_domain_with_vuart(void)
+{
+ struct domain *d = NULL;
+ domid_t i;
+
+ for ( i = 0; i < max_init_domid + 1; i++ )
+ {
+ d = rcu_lock_domain_by_id(i);
+ if ( d == NULL )
+ continue;
+
+ if ( domain_has_vuart(d) )
+ break;
+
+ rcu_unlock_domain(d);
+ }
+
+ return d;
+}
+
+static void cf_check ns8250_keyhandler_show(unsigned char key)
+{
+ struct vuart_ns8250 *vdev;
+ struct domain *d;
+
+ d = rcu_find_first_domain_with_vuart();
+ if ( d == NULL )
+ return;
+
+ printk("'%c' pressed -> dumping virtual NS8250 state (d%d)\n",
+ key, d->domain_id);
+
+ vdev = &d->arch.hvm.vuart;
+ spin_lock(&vdev->lock);
+ ns8250_dump(vdev);
+ spin_unlock(&vdev->lock);
+
+ rcu_unlock_domain(d);
+}
+
+static void cf_check ns8250_keyhandler_irq(unsigned char key)
+{
+ struct vuart_ns8250 *vdev;
+ struct domain *d;
+
+ d = rcu_find_first_domain_with_vuart();
+ if ( d == NULL )
+ return;
+
+ printk("'%c' pressed -> triggering IRQ on virtual NS8250 (d%d)\n",
+ key, d->domain_id);
+
+ vdev = &d->arch.hvm.vuart;
+ spin_lock(&vdev->lock);
+ ns8250_irq_assert(vdev);
+ spin_unlock(&vdev->lock);
+
+ rcu_unlock_domain(d);
+}
+
+static void ns8250_keyhandler_init(void)
+{
+ register_keyhandler('1', ns8250_keyhandler_show,
+ "dump virtual NS8250 state", 0);
+ register_keyhandler('2', ns8250_keyhandler_irq,
+ "trigger IRQ from virtual NS8250", 0);
+}
+#else
+static inline void ns8250_keyhandler_init(void)
+{
+}
+static inline void ns8250_dump(struct vuart_ns8250 *vdev)
+{
+}
+#endif /* #if defined(NS8250_DEBUG) */
+
/*
* Emulate I/O access to NS8250 register.
*/
@@ -688,6 +807,7 @@ static int cf_check ns8250_io_handle(
rc = X86EMUL_OKAY;
out:
+ ns8250_dump(vdev);
spin_unlock(&vdev->lock);
return rc;
@@ -786,6 +906,7 @@ static int ns8250_init(struct domain *d, const struct resource *r)
}
spin_lock_init(&vdev->lock);
+ ns8250_keyhandler_init();
hvm_irq_lower(d, vdev->irq);
vdev->dl = (UART_CLOCK_HZ / 115200) >> 4; /* Report 115200 baud rate */
@@ -852,6 +973,7 @@ int vuart_putchar(struct vuart_ns8250 *vdev, char ch)
ns8250_irq_assert(vdev);
out:
+ ns8250_dump(vdev);
spin_unlock(&vdev->lock);
return rc;