|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [XTF PATCH v1 5/6] common: add simplistic NS16550-compatible UART driver
From: Denis Mukhin <dmukhin@xxxxxxxx>
Add a miniature NS16550-compatible driver for hypervisor validation.
Implement polling mode and putchar only.
Place the code in a common place since NS16550 hardware is not limited to
x86 systems (although the current driver uses few x86-ishms like I/O ports).
Signed-off-by: Denis Mukhin <dmukhin@xxxxxxxx>
---
build/files.mk | 1 +
common/console.c | 3 +-
common/ns16550.c | 153 ++++++++++++++++++++++++++++++++++++++++++
include/xtf/console.h | 15 +++--
include/xtf/ns16550.h | 117 ++++++++++++++++++++++++++++++++
5 files changed, 284 insertions(+), 5 deletions(-)
create mode 100644 common/ns16550.c
create mode 100644 include/xtf/ns16550.h
diff --git a/build/files.mk b/build/files.mk
index 11624a89a21c..841ea9ebc70a 100644
--- a/build/files.mk
+++ b/build/files.mk
@@ -34,6 +34,7 @@ obj-hvm += $(ROOT)/arch/x86/hvm/head.o
obj-hvm += $(ROOT)/arch/x86/hvm/pagetables.o
obj-hvm += $(ROOT)/arch/x86/hvm/traps.o
obj-hvm += $(ROOT)/arch/x86/io-apic.o
+obj-hvm += $(ROOT)/common/ns16550.o
# Arguably common objects, but PV guests will have no interest in them.
obj-hvm += $(ROOT)/arch/x86/vmx.o
diff --git a/common/console.c b/common/console.c
index b3e89473a7b4..02ff90c5428d 100644
--- a/common/console.c
+++ b/common/console.c
@@ -13,8 +13,9 @@
* - Xen hypervisor console
* - PV console
* - Qemu debug console
+ * - NS16550-compatible emulator
*/
-static cons_output_cb output_fns[3];
+static cons_output_cb output_fns[4];
static unsigned int nr_cons_cb;
/* Guest PV console details. */
diff --git a/common/ns16550.c b/common/ns16550.c
new file mode 100644
index 000000000000..fa2bae5ebf98
--- /dev/null
+++ b/common/ns16550.c
@@ -0,0 +1,153 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/**
+ * Simple NS16550-compatible device driver.
+ */
+
+#include <arch/config.h>
+#include <arch/traps.h>
+
+#include <xtf/console.h>
+#include <xtf/ns16550.h>
+#include <xtf/types.h>
+
+static const struct ns16550 *ns16550;
+
+static inline unsigned long
+ns16550_reg(const struct ns16550 *uart, unsigned int reg)
+{
+ return uart->base + (reg << uart->reg_shift);
+}
+
+uint8_t ns16550_inb(const struct ns16550 *uart, unsigned int reg)
+{
+ unsigned long addr = ns16550_reg(uart, reg);
+
+ return inb(addr);
+}
+
+void ns16550_outb(const struct ns16550 *uart, unsigned int reg,
+ unsigned char val)
+{
+ unsigned long addr = ns16550_reg(uart, reg);
+
+ outb(val, addr);
+}
+
+void ns16550_wait_tx(const struct ns16550 *uart)
+{
+ while ( !(ns16550_inb(uart, UART_LSR) & UART_LSR_THRE) )
+ cpu_relax();
+}
+
+void ns16550_drain_rx(const struct ns16550 *uart)
+{
+ unsigned int i;
+
+ for ( i = 0; i < 128 && (ns16550_inb(uart, UART_LSR) & UART_LSR_DR); i++ )
+ (void)ns16550_inb(uart, UART_RBR);
+}
+
+void ns16550_putc(const struct ns16550 *uart, char c)
+{
+ ns16550_wait_tx(uart);
+
+ /* Inject carriage return. */
+ if ( c == '\n' )
+ {
+ ns16550_outb(uart, UART_THR, '\r');
+ ns16550_wait_tx(uart);
+ }
+
+ ns16550_outb(uart, UART_THR, c);
+}
+
+static void ns16550_write(const struct ns16550 *uart, const char *buf,
+ size_t len)
+{
+ size_t i;
+
+ for ( i = 0; i < len; i++ )
+ ns16550_putc(uart, buf[i]);
+}
+
+void ns16550_puts(const struct ns16550 *uart, const char *buf)
+{
+ ns16550_write(uart, buf, strlen(buf));
+}
+
+int ns16550_init(const struct ns16550 *uart)
+{
+ unsigned int divisor = uart->clk_freq / (16 * uart->baud);
+
+ if ( !divisor )
+ divisor = 1;
+
+ /* Disable interrupts. */
+ ns16550_outb(uart, UART_IER, 0x00);
+
+ /* Set baud rate. */
+ ns16550_outb(uart, UART_LCR, UART_LCR_DLAB);
+ ns16550_outb(uart, UART_DLL, divisor & 0xff);
+ ns16550_outb(uart, UART_DLM, (divisor >> 8) & 0xff);
+
+ /* Support only 8 data bits, no parity, 1 stop bit. */
+ ns16550_outb(uart, UART_LCR, UART_LCR_8N1); /* DLAB=0 */
+
+ /* Reset FIFOs. */
+ ns16550_outb(uart, UART_FCR,
+ UART_FCR_ENABLE | UART_FCR_CLRX |
+ UART_FCR_CLTX | UART_FCR_TRG14);
+
+ /* Assert modem control lines. */
+ ns16550_outb(uart, UART_MCR,
+ UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2);
+
+ /* Drain any pending status/data to avoid stale state. */
+ (void)ns16550_inb(uart, UART_LSR);
+ (void)ns16550_inb(uart, UART_RBR);
+ (void)ns16550_inb(uart, UART_IIR);
+ (void)ns16550_inb(uart, UART_MSR);
+
+ return 0;
+}
+
+/*
+ * Console driver.
+ */
+
+static void ns16550_console_write(const char *buf, size_t len)
+{
+ if (ns16550)
+ ns16550_write(ns16550, buf, len);
+}
+
+void ns16550_console_puts(const char *buf)
+{
+ ns16550_console_write(buf, strlen(buf));
+}
+
+int ns16550_console_register(const struct ns16550 *uart)
+{
+ if ( ns16550_init(uart) )
+ return -1;
+
+ register_console_callback(ns16550_console_write);
+ ns16550 = uart;
+
+ return 0;
+}
+
+void ns16550_console_unregister(void)
+{
+ ns16550 = NULL;
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/include/xtf/console.h b/include/xtf/console.h
index 16a6a23e3f56..4830e511b080 100644
--- a/include/xtf/console.h
+++ b/include/xtf/console.h
@@ -3,6 +3,7 @@
#include <xtf/libc.h>
#include <xtf/compiler.h>
+#include <xtf/ns16550.h>
#include <xen/event_channel.h>
#include <xen/io/console.h>
@@ -16,17 +17,23 @@ typedef void (*cons_output_cb)(const char *buf, size_t len);
*/
void register_console_callback(cons_output_cb cb);
+void vprintk(const char *fmt, va_list args) __printf(1, 0);
+void printk(const char *fmt, ...) __printf(1, 2);
+
/*
* Initialise the PV console. Will register a callback.
*/
void init_pv_console(xencons_interface_t *ring,
evtchn_port_t port);
-
-void vprintk(const char *fmt, va_list args) __printf(1, 0);
-void printk(const char *fmt, ...) __printf(1, 2);
-
size_t pv_console_read_some(char *buf, size_t len);
+/*
+ * NS16550-backed console.
+ */
+int ns16550_console_register(const struct ns16550 *uart);
+void ns16550_console_unregister(void);
+void ns16550_console_puts(const char *buf);
+
#endif /* XTF_CONSOLE_H */
/*
diff --git a/include/xtf/ns16550.h b/include/xtf/ns16550.h
new file mode 100644
index 000000000000..5db515b7fb91
--- /dev/null
+++ b/include/xtf/ns16550.h
@@ -0,0 +1,117 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/**
+ * Simple console driver for NS16550-compatible UART.
+ */
+
+#ifndef XTF_NS16550_H
+#define XTF_NS16550_H
+
+#define UART_RBR 0x00
+#define UART_THR 0x00
+#define UART_DLL 0x00
+#define UART_IER 0x01
+#define UART_IER_ERDAI 0x01
+#define UART_IER_ETHREI 0x02
+#define UART_IER_ELSI 0x04
+#define UART_IER_EMSI 0x08
+#define UART_IER_MASK 0x0f
+#define UART_IER_RSRVD 0xf0
+#define UART_DLM 0x01
+#define UART_IIR 0x02
+#define UART_IIR_NOINT 0x01
+#define UART_IIR_IMA 0x06
+#define UART_IIR_LSI 0x06
+#define UART_IIR_RDA 0x04
+#define UART_IIR_THR 0x02
+#define UART_IIR_MSI 0x00
+#define UART_IIR_BSY 0x07
+#define UART_IIR_FE 0xc0
+#define UART_IIR_MASK 0x0f
+#define UART_FCR 0x02
+#define UART_FCR_ENABLE 0x01
+#define UART_FCR_CLRX 0x02
+#define UART_FCR_CLTX 0x04
+#define UART_FCR_DMA 0x08
+#define UART_FCR_TRG1 0x00
+#define UART_FCR_TRG4 0x40
+#define UART_FCR_TRG8 0x80
+#define UART_FCR_TRG14 0xc0
+#define UART_LCR 0x03
+#define UART_LCR_WLEN5 0x00
+#define UART_LCR_WLEN6 0x01
+#define UART_LCR_WLEN7 0x02
+#define UART_LCR_WLEN8 0x03
+#define UART_LCR_STB 0x04
+#define UART_LCR_PE 0x08
+#define UART_LCR_EP 0x10
+#define UART_LCR_SP 0x20
+#define UART_LCR_SB 0x40
+#define UART_LCR_DLAB 0x80
+#define UART_LCR_7N2 (UART_LCR_WLEN7 | UART_LCR_STB)
+#define UART_LCR_8N1 (UART_LCR_WLEN8)
+#define UART_LSR_ERRORS (UART_LSR_OE | UART_LSR_PE | \
+ UART_LSR_FE | UART_LSR_BI)
+#define UART_MCR 0x04
+#define UART_MCR_DTR 0x01
+#define UART_MCR_RTS 0x02
+#define UART_MCR_OUT1 0x04
+#define UART_MCR_OUT2 0x08
+#define UART_MCR_LOOP 0x10
+#define UART_MCR_RSRVD0 0x20
+#define UART_MCR_TCRTLR 0x40
+#define UART_MCR_RSRVD1 0x80
+#define UART_MCR_MASK (UART_MCR_DTR | UART_MCR_RTS | \
+ UART_MCR_OUT1 | UART_MCR_OUT2 | \
+ UART_MCR_LOOP)
+#define UART_LSR 0x05
+#define UART_LSR_DR 0x01
+#define UART_LSR_OE 0x02
+#define UART_LSR_PE 0x04
+#define UART_LSR_FE 0x08
+#define UART_LSR_BI 0x10
+#define UART_LSR_THRE 0x20
+#define UART_LSR_TEMT 0x40
+#define UART_LSR_ERR 0x80
+#define UART_MSR 0x06
+#define UART_MSR_DCTS 0x01
+#define UART_MSR_DDSR 0x02
+#define UART_MSR_TERI 0x04
+#define UART_MSR_DDCD 0x08
+#define UART_MSR_CTS 0x10
+#define UART_MSR_DSR 0x20
+#define UART_MSR_RI 0x40
+#define UART_MSR_DCD 0x80
+#define UART_SCR 0x07
+
+struct ns16550 {
+ const char *name;
+ unsigned long base;
+ unsigned int reg_shift;
+ unsigned int reg_width;
+ unsigned int clk_freq;
+ unsigned int baud;
+};
+
+uint8_t ns16550_inb(const struct ns16550 *uart, unsigned int reg);
+void ns16550_outb(const struct ns16550 *uart, unsigned int reg,
+ unsigned char val);
+
+void ns16550_wait_tx(const struct ns16550 *uart);
+void ns16550_drain_rx(const struct ns16550 *uart);
+
+void ns16550_putc(const struct ns16550 *uart, char c);
+void ns16550_puts(const struct ns16550 *uart, const char *buf);
+
+int ns16550_init(const struct ns16550 *uart);
+
+#endif /* XTF_NS16550_H */
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
--
2.56.0
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |