Re: [PATCH v3] riscv/virt: Add optional UART1
Yanfeng Liu <[email protected]>
| Newsgroups | org.nongnu.qemu-riscv,org.nongnu.qemu-devel |
|---|---|
| Message-ID | <[email protected]> |
On Sun, 2026-08-23 at 18:55 -0300, Daniel Henrique Barboza wrote: > > > On 7/17/2026 11:16 PM, Yanfeng Liu wrote: > > This adds optional UART1 to RiscV virt board if required at > > runtime to simplify multicore development. > > Can you please elaborate on the use case? We can add multiple serial > devices already. E.g. this will add 4 serials: > I was playing Bao hypervisor and found that having a 2nd NMIO UART can ba handy. Previoously when trying AMP I added 2nd MMIO UART to aid debugging. Since this happened to me at least twice, I am wondering someone else might also need it. Besides many real devices have muitlple UARTs. > > > $ ./build/qemu-system-riscv64 -M virt --nodefaults \ > -serial stdio \ > -serial tcp::4444,server,nowait \ > -serial pty \ > -serial file:uart4.log \ > --nographic > > > The difference here is that the additional serials won't have memory > mappings > and fdt nodes. > how these additional UARTs can be used by guests if they dont have MMIO? Regards, Yanfeng > > Thanks, > Daniel > > > > > 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 */