Alistair,
I was using 0x10000100 at first but soon noticed it is in the same MMU page as UART0, which is difficult for pass-through hypervisor guests. So current approach seems a little more flexible? Regards, yanfeng On Tue, 2026-07-14 at 01:13 +0000, Alistair Francis wrote: > On Fri, 2026-07-03 at 12:24 +0800, Yanfeng Liu wrote: > > 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 > > > > Signed-off-by: Yanfeng Liu <[email protected]> > > --- > > docs/system/riscv/virt.rst | 5 ++++- > > hw/riscv/virt-acpi-build.c | 12 ++++++++---- > > hw/riscv/virt.c | 39 ++++++++++++++++++++++++++++------ > > -- > > -- > > include/hw/riscv/virt.h | 3 +++ > > 4 files changed, 44 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..9a112ccdef 100644 > > --- a/hw/riscv/virt.c > > +++ b/hw/riscv/virt.c > > @@ -96,6 +96,7 @@ static const MemMapEntry virt_memmap[] = { > > [VIRT_APLIC_S] = { 0xd000000, APLIC_SIZE(VIRT_CPUS_MAX) > > }, > > [VIRT_UART0] = { 0x10000000, 0x100 }, > > [VIRT_VIRTIO] = { 0x10001000, 0x1000 }, > > + [VIRT_UART1] = { 0x1000a000, 0x100 }, > > This could be at address 0x10000100 instead and squish up against > UART0. > > Otherwise: > > Reviewed-by: Alistair Francis <[email protected]> > > Alistair > > > [VIRT_FW_CFG] = { 0x10100000, 0x18 }, > > [VIRT_FLASH] = { 0x20000000, 0x4000000 }, > > [VIRT_IMSIC_M] = { 0x24000000, VIRT_IMSIC_MAX_SIZE }, > > @@ -186,7 +187,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 +834,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 +1035,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 +1579,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 */
