This adds optional UART1 to RiscV virt board if required at runtime to simplify multicore development.
Note that UART0 remains default serial_hd(0) and it is: - the lowest address UART - first serial in DTB - behind /aliases/serial0 in DTB - the /chosen/stdout-path in DTB Note that UART1 is placed at different page from UART0 to support page level isolation. Signed-off-by: Yanfeng Liu <[email protected]> --- docs/system/riscv/virt.rst | 5 ++++- hw/riscv/virt-acpi-build.c | 12 ++++++++---- hw/riscv/virt.c | 40 ++++++++++++++++++++++++++++---------- include/hw/riscv/virt.h | 3 +++ 4 files changed, 45 insertions(+), 15 deletions(-) diff --git a/docs/system/riscv/virt.rst b/docs/system/riscv/virt.rst index 60850970ce..45ac63ac77 100644 --- a/docs/system/riscv/virt.rst +++ b/docs/system/riscv/virt.rst @@ -16,7 +16,7 @@ The ``virt`` machine supports the following devices: * Core Local Interruptor (CLINT) * Platform-Level Interrupt Controller (PLIC) * CFI parallel NOR flash memory -* 1 NS16550 compatible UART +* Either 1 or 2 NS16550 compatible UARTs * 1 Google Goldfish RTC * 1 SiFive Test device * 8 virtio-mmio transport devices @@ -27,6 +27,9 @@ The hypervisor extension has been enabled for the default CPU, so virtual machines with hypervisor extension can simply be used without explicitly declaring. +The second UART only exists if a backend is configured explicitly (e.g. +with a second `-serial` command line option). + Hardware configuration information ---------------------------------- diff --git a/hw/riscv/virt-acpi-build.c b/hw/riscv/virt-acpi-build.c index 413d47d70e..597751c84a 100644 --- a/hw/riscv/virt-acpi-build.c +++ b/hw/riscv/virt-acpi-build.c @@ -169,11 +169,11 @@ static void acpi_dsdt_add_plic_aplic(Aml *scope, uint8_t socket_count, static void acpi_dsdt_add_uart(Aml *scope, const MemMapEntry *uart_memmap, - uint32_t uart_irq) + uint32_t uart_irq, int uartidx) { - Aml *dev = aml_device("COM0"); + Aml *dev = aml_device("COM%d", uartidx); aml_append(dev, aml_name_decl("_HID", aml_string("RSCV0003"))); - aml_append(dev, aml_name_decl("_UID", aml_int(0))); + aml_append(dev, aml_name_decl("_UID", aml_int(uartidx))); Aml *crs = aml_resource_template(); aml_append(crs, aml_memory32_fixed(uart_memmap->base, @@ -479,7 +479,11 @@ static void build_dsdt(GArray *table_data, memmap[VIRT_APLIC_S].size, "RSCV0002"); } - acpi_dsdt_add_uart(scope, &memmap[VIRT_UART0], UART0_IRQ); + acpi_dsdt_add_uart(scope, &memmap[VIRT_UART0], UART0_IRQ, 0); + if (s->uart1_present) { + acpi_dsdt_add_uart(scope, &memmap[VIRT_UART1], UART1_IRQ, 1); + } + if (virt_is_iommu_sys_enabled(s)) { acpi_dsdt_add_iommu_sys(scope, &memmap[VIRT_IOMMU_SYS], IOMMU_SYS_IRQ); } diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index 33775a61fd..4703ac58f8 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -96,6 +96,8 @@ static const MemMapEntry virt_memmap[] = { [VIRT_APLIC_S] = { 0xd000000, APLIC_SIZE(VIRT_CPUS_MAX) }, [VIRT_UART0] = { 0x10000000, 0x100 }, [VIRT_VIRTIO] = { 0x10001000, 0x1000 }, + /* UART1 supports page isolation from UART0 */ + [VIRT_UART1] = { 0x1000a000, 0x100 }, [VIRT_FW_CFG] = { 0x10100000, 0x18 }, [VIRT_FLASH] = { 0x20000000, 0x4000000 }, [VIRT_IMSIC_M] = { 0x24000000, VIRT_IMSIC_MAX_SIZE }, @@ -186,7 +188,8 @@ static void create_pcie_irq_map(RISCVVirtState *s, void *fdt, char *nodename, FDT_MAX_INT_MAP_WIDTH] = {}; uint32_t *irq_map = full_irq_map; - /* This code creates a standard swizzle of interrupts such that + /* + * This code creates a standard swizzle of interrupts such that * each device's first interrupt is based on it's PCI_SLOT number. * (See pci_swizzle_map_irq_fn()) * @@ -832,28 +835,38 @@ static void create_fdt_reset(RISCVVirtState *s, uint32_t *phandle) } static void create_fdt_uart(RISCVVirtState *s, - uint32_t irq_mmio_phandle) + uint32_t irq_mmio_phandle, int memId, int irqNo) { g_autofree char *name = NULL; MachineState *ms = MACHINE(s); name = g_strdup_printf("/soc/serial@%"HWADDR_PRIx, - s->memmap[VIRT_UART0].base); + s->memmap[memId].base); qemu_fdt_add_subnode(ms->fdt, name); qemu_fdt_setprop_string(ms->fdt, name, "compatible", "ns16550a"); qemu_fdt_setprop_sized_cells(ms->fdt, name, "reg", - 2, s->memmap[VIRT_UART0].base, - 2, s->memmap[VIRT_UART0].size); + 2, s->memmap[memId].base, + 2, s->memmap[memId].size); qemu_fdt_setprop_cell(ms->fdt, name, "clock-frequency", 3686400); qemu_fdt_setprop_cell(ms->fdt, name, "interrupt-parent", irq_mmio_phandle); if (s->aia_type == VIRT_AIA_TYPE_NONE) { - qemu_fdt_setprop_cell(ms->fdt, name, "interrupts", UART0_IRQ); + qemu_fdt_setprop_cell(ms->fdt, name, "interrupts", irqNo); } else { - qemu_fdt_setprop_cells(ms->fdt, name, "interrupts", UART0_IRQ, 0x4); + qemu_fdt_setprop_cells(ms->fdt, name, "interrupts", irqNo, 0x4); + } + + if (VIRT_UART0 == memId) { + qemu_fdt_setprop_string(ms->fdt, "/chosen", "stdout-path", name); + qemu_fdt_setprop_string(ms->fdt, "/aliases", "serial0", name); } +} - qemu_fdt_setprop_string(ms->fdt, "/chosen", "stdout-path", name); - qemu_fdt_setprop_string(ms->fdt, "/aliases", "serial0", name); +static void create_fdt_uarts(RISCVVirtState *s, uint32_t irq_mmio_phandle) +{ + if (s->uart1_present) { + create_fdt_uart(s, irq_mmio_phandle, VIRT_UART1, UART1_IRQ); + } + create_fdt_uart(s, irq_mmio_phandle, VIRT_UART0, UART0_IRQ); } static void create_fdt_rtc(RISCVVirtState *s, @@ -1023,7 +1036,7 @@ static void finalize_fdt(RISCVVirtState *s) create_fdt_reset(s, &phandle); - create_fdt_uart(s, irq_mmio_phandle); + create_fdt_uarts(s, irq_mmio_phandle); create_fdt_rtc(s, irq_mmio_phandle); } @@ -1567,6 +1580,13 @@ static void virt_machine_init(MachineState *machine) 0, qdev_get_gpio_in(mmio_irqchip, UART0_IRQ), 399193, serial_hd(0), DEVICE_LITTLE_ENDIAN); + if (serial_hd(1)) { + serial_mm_init(system_memory, s->memmap[VIRT_UART1].base, + 0, qdev_get_gpio_in(mmio_irqchip, UART1_IRQ), 399193, + serial_hd(1), DEVICE_LITTLE_ENDIAN); + s->uart1_present = true; + } + sysbus_create_simple("goldfish_rtc", s->memmap[VIRT_RTC].base, qdev_get_gpio_in(mmio_irqchip, RTC_IRQ)); diff --git a/include/hw/riscv/virt.h b/include/hw/riscv/virt.h index 18a2a323a3..7d57c8292e 100644 --- a/include/hw/riscv/virt.h +++ b/include/hw/riscv/virt.h @@ -59,6 +59,7 @@ struct RISCVVirtState { int aia_guests; char *oem_id; char *oem_table_id; + bool uart1_present; OnOffAuto acpi; const MemMapEntry *memmap; struct GPEXHost *gpex_host; @@ -78,6 +79,7 @@ enum { VIRT_APLIC_S, VIRT_UART0, VIRT_VIRTIO, + VIRT_UART1, VIRT_FW_CFG, VIRT_IMSIC_M, VIRT_IMSIC_S, @@ -93,6 +95,7 @@ enum { enum { UART0_IRQ = 10, RTC_IRQ = 11, + UART1_IRQ = 12, VIRTIO_IRQ = 1, /* 1 to 8 */ VIRTIO_COUNT = 8, PCIE_IRQ = 0x20, /* 32 to 35 */ -- 2.34.1
