diff --git a/hypervisor/arch/x86/Kconfig b/hypervisor/arch/x86/Kconfig index 497a84fea..396659636 100644 --- a/hypervisor/arch/x86/Kconfig +++ b/hypervisor/arch/x86/Kconfig @@ -126,6 +126,11 @@ config SERIAL_LEGACY Select this if the serial port shall be accessed via legacy port in/out instructions. +config SERIAL_MMIO + bool "MMIO" + help + Select this if the serial port shall be accessed via MMIO registers. + endchoice config SERIAL_PCI_BDF @@ -144,6 +149,13 @@ config SERIAL_PIO_BASE The base address of the serial ports. This is logically 16-bit but used as a 64-bit integer. +config SERIAL_MMIO_BASE + hex "Base address of MMIO UART" + depends on SERIAL_MMIO + default 0xfe040000 + help + The base address of the MMIO serial port. + config CONSOLE_LOGLEVEL_DEFAULT int "Default loglevel on the serial console" depends on !RELEASE diff --git a/hypervisor/debug/dbg_cmd.c b/hypervisor/debug/dbg_cmd.c index 8e859c1f5..b8a5ffc8a 100644 --- a/hypervisor/debug/dbg_cmd.c +++ b/hypervisor/debug/dbg_cmd.c @@ -15,57 +15,49 @@ #define MAX_CMD_LEN 64 -static const char * const cmd_list[] = { - "uart=disabled", /* to disable uart */ - "uart=port@", /* like uart=port@0x3F8 */ - "uart=bdf@", /*like: uart=bdf@0:18.2, it is for ttyS2 */ -}; - -enum IDX_CMD_DBG { - IDX_DISABLE_UART, - IDX_PORT_UART, - IDX_PCI_UART, - - IDX_MAX_CMD, +static struct uart_cmd { + const char *const str; + int type; +} cmd_list[] = { + { "uart=port@", PIO }, /* uart=port@0x3F8 */ + { "uart=bdf@", PCI }, /* uart=bdf@0:18.2 */ + { "uart=mmio@", MMIO }, /* uart=mmio@0xfe040000 */ + { "uart=disabled", INVALID } }; bool handle_dbg_cmd(const char *cmd, int32_t len) { - int32_t i; - bool handled = false; + uint32_t i; - for (i = 0; i < IDX_MAX_CMD; i++) { - int32_t tmp = strnlen_s(cmd_list[i], MAX_CMD_LEN); + for (i = 0; i < ARRAY_SIZE(cmd_list); i++) { + int32_t tmp = strnlen_s(cmd_list[i].str, MAX_CMD_LEN); + int type = cmd_list[i].type; - /*cmd prefix should be same with one in cmd_list */ + /* cmd prefix should be same with one in cmd_list */ if (len < tmp) continue; - if (strncmp(cmd_list[i], cmd, tmp) != 0) + if (strncmp(cmd_list[i].str, cmd, tmp) != 0) continue; - if (i == IDX_DISABLE_UART) { + if (type == INVALID) { /* set uart disabled*/ - uart16550_set_property(false, false, 0UL); - } else if (i == IDX_PORT_UART) { + uart16550_set_property(false, type, 0UL); + } else if (type == PIO) { uint64_t addr = strtoul_hex(cmd + tmp); if (addr > MAX_PORT) { addr = DEFAULT_UART_PORT; } - uart16550_set_property(true, true, addr); - - } else if (i == IDX_PCI_UART) { - uart16550_set_property(true, false, (uint64_t)(cmd+tmp)); + uart16550_set_property(true, type, addr); + } else if (type == PCI) { + uart16550_set_property(true, type, (uint64_t)(cmd+tmp)); } else { - /* No other state currently, do nothing */ + uint64_t addr = strtoul_hex(cmd + tmp); + uart16550_set_property(true, type, addr); } } - if (i < IDX_MAX_CMD) { - handled = true; - } - - return handled; + return i < ARRAY_SIZE(cmd_list)? true : false; } diff --git a/hypervisor/debug/uart16550.c b/hypervisor/debug/uart16550.c index 672fcd63e..d80343952 100644 --- a/hypervisor/debug/uart16550.c +++ b/hypervisor/debug/uart16550.c @@ -16,29 +16,41 @@ struct console_uart { bool enabled; - bool serial_port_mapped; + + enum serial_dev_type type; union { uint16_t port_address; void *mmio_base_vaddr; }; + spinlock_t rx_lock; spinlock_t tx_lock; + + uint32_t reg_width; }; #if defined(CONFIG_SERIAL_PIO_BASE) static struct console_uart uart = { .enabled = true, - .serial_port_mapped = true, + .type = PIO, .port_address = CONFIG_SERIAL_PIO_BASE, + .reg_width = 1, }; static char pci_bdf_info[MAX_BDF_LEN + 1U]; #elif defined(CONFIG_SERIAL_PCI_BDF) static struct console_uart uart = { .enabled = true, + .type = PCI, + .reg_width = 4, }; static char pci_bdf_info[MAX_BDF_LEN + 1U] = CONFIG_SERIAL_PCI_BDF; -#else -static struct console_uart uart; +#elif defined(CONFIG_SERIAL_MMIO_BASE) +static struct console_uart uart = { + .enabled = true, + .type = MMIO, + .mmio_base_vaddr = (void *)CONFIG_SERIAL_MMIO_BASE, + .reg_width = 1, +}; static char pci_bdf_info[MAX_BDF_LEN + 1U]; #endif @@ -77,10 +89,12 @@ static uint16_t get_pci_bdf_value(char *bdf) */ static inline uint32_t uart16550_read_reg(struct console_uart uart, uint16_t reg_idx) { - if (uart.serial_port_mapped) { - return pio_read8(uart.port_address + reg_idx); + if (uart.type == PIO) { + return pio_read8(uart.port_address + (reg_idx * uart.reg_width)); + } else if (uart.type == PCI) { + return mmio_read32(uart.mmio_base_vaddr + (reg_idx * uart.reg_width)); } else { - return mmio_read32((uint32_t *)uart.mmio_base_vaddr + reg_idx); + return mmio_read8(uart.mmio_base_vaddr + (reg_idx * uart.reg_width)); } } @@ -89,10 +103,12 @@ static inline uint32_t uart16550_read_reg(struct console_uart uart, uint16_t reg */ static inline void uart16550_write_reg(struct console_uart uart, uint32_t val, uint16_t reg_idx) { - if (uart.serial_port_mapped) { - pio_write8(val, uart.port_address + reg_idx); + if (uart.type == PIO) { + pio_write8(val, uart.port_address + (reg_idx * uart.reg_width)); + } else if (uart.type == PCI) { + mmio_write32(val, uart.mmio_base_vaddr + (reg_idx * uart.reg_width)); } else { - mmio_write32(val, (uint32_t *)uart.mmio_base_vaddr + reg_idx); + mmio_write8(val, uart.mmio_base_vaddr + (reg_idx * uart.reg_width)); } } @@ -138,19 +154,18 @@ void uart16550_init(bool early_boot) return; } - if (!early_boot && !uart.serial_port_mapped) { + if (!early_boot && (uart.type != PIO)) { uart.mmio_base_vaddr = hpa2hva(hva2hpa_early(uart.mmio_base_vaddr)); hv_access_memory_region_update((uint64_t)uart.mmio_base_vaddr, PDE_SIZE); return; } /* if configure serial PCI BDF, get its base MMIO address */ - if (!uart.serial_port_mapped) { + if (uart.type == PCI) { serial_pci_bdf.value = get_pci_bdf_value(pci_bdf_info); uart.mmio_base_vaddr = hpa2hva_early(pci_pdev_read_cfg(serial_pci_bdf, pci_bar_offset(0), 4U) & PCIM_BAR_MEM_BASE); } - spinlock_init(&uart.rx_lock); spinlock_init(&uart.tx_lock); /* Enable TX and RX FIFOs */ @@ -230,16 +245,20 @@ size_t uart16550_puts(const char *buf, uint32_t len) return len; } -void uart16550_set_property(bool enabled, bool port_mapped, uint64_t base_addr) +void uart16550_set_property(bool enabled, enum serial_dev_type uart_type, uint64_t base_addr) { uart.enabled = enabled; - uart.serial_port_mapped = port_mapped; + uart.type = uart_type; - if (port_mapped) { + if (uart_type == PIO) { uart.port_address = base_addr; - } else { + } else if (uart_type == PCI) { const char *bdf = (const char *)base_addr; strncpy_s(pci_bdf_info, MAX_BDF_LEN + 1U, bdf, MAX_BDF_LEN); + uart.reg_width = 4; + } else if (uart_type == MMIO) { + uart.mmio_base_vaddr = (void *)base_addr; + uart.reg_width = 1; } } @@ -247,7 +266,7 @@ bool is_pci_dbg_uart(union pci_bdf bdf_value) { bool ret = false; - if (uart.enabled && !uart.serial_port_mapped) { + if (uart.enabled && (uart.type == PCI)) { if (bdf_value.value == serial_pci_bdf.value) { ret = true; } diff --git a/hypervisor/include/debug/uart16550.h b/hypervisor/include/debug/uart16550.h index 5181fb2c5..15ae7e966 100644 --- a/hypervisor/include/debug/uart16550.h +++ b/hypervisor/include/debug/uart16550.h @@ -127,10 +127,17 @@ /* UART oscillator clock */ #define UART_CLOCK_RATE 1843200U /* 1.8432 MHz */ +enum serial_dev_type { + INVALID, + PIO, + PCI, + MMIO, +}; + void uart16550_init(bool early_boot); char uart16550_getc(void); size_t uart16550_puts(const char *buf, uint32_t len); -void uart16550_set_property(bool enabled, bool port_mapped, uint64_t base_addr); +void uart16550_set_property(bool enabled, enum serial_dev_type uart_type, uint64_t base_addr); bool is_pci_dbg_uart(union pci_bdf bdf_value); #endif /* !UART16550_H */