hw/riscv/virt.c | 33 +++++++++++++++++++++++---------- include/hw/riscv/virt.h | 2 ++ 2 files changed, 25 insertions(+), 10 deletions(-)
This adds secondary UART device to RiscV virt board to simplify
multi-core bare-metal development as Virtio needs comparably
more work.
Signed-off-by: Yanfeng Liu <yfliu2008@qq.com>
---
hw/riscv/virt.c | 33 +++++++++++++++++++++++----------
include/hw/riscv/virt.h | 2 ++
2 files changed, 25 insertions(+), 10 deletions(-)
diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
index 33775a61fd..d414953d6f 100644
--- a/hw/riscv/virt.c
+++ b/hw/riscv/virt.c
@@ -86,6 +86,7 @@ static const MemMapEntry virt_memmap[] = {
[VIRT_MROM] = { 0x1000, 0xf000 },
[VIRT_TEST] = { 0x100000, 0x1000 },
[VIRT_RTC] = { 0x101000, 0x1000 },
+ [VIRT_UART1] = { 0x102000, 0x100 },
[VIRT_CLINT] = { 0x2000000, 0x10000 },
[VIRT_ACLINT_SSWI] = { 0x2F00000, 0x4000 },
[VIRT_PCIE_PIO] = { 0x3000000, 0x10000 },
@@ -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,36 @@ 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);
}
- qemu_fdt_setprop_string(ms->fdt, "/chosen", "stdout-path", name);
- qemu_fdt_setprop_string(ms->fdt, "/aliases", "serial0", name);
+ if (VIRT_UART0 == memId) {
+ 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)
+{
+ create_fdt_uart(s, irq_mmio_phandle, VIRT_UART0, UART0_IRQ);
+ create_fdt_uart(s, irq_mmio_phandle, VIRT_UART1, UART1_IRQ);
}
static void create_fdt_rtc(RISCVVirtState *s,
@@ -1023,7 +1033,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);
}
@@ -1566,6 +1576,9 @@ static void virt_machine_init(MachineState *machine)
serial_mm_init(system_memory, s->memmap[VIRT_UART0].base,
0, qdev_get_gpio_in(mmio_irqchip, UART0_IRQ), 399193,
serial_hd(0), DEVICE_LITTLE_ENDIAN);
+ 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);
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..d27bab9f64 100644
--- a/include/hw/riscv/virt.h
+++ b/include/hw/riscv/virt.h
@@ -78,6 +78,7 @@ enum {
VIRT_APLIC_S,
VIRT_UART0,
VIRT_VIRTIO,
+ VIRT_UART1,
VIRT_FW_CFG,
VIRT_IMSIC_M,
VIRT_IMSIC_S,
@@ -93,6 +94,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
On Sun, 28 Jun 2026 at 08:06, Yanfeng Liu <yfliu2008@qq.com> wrote: > > This adds secondary UART device to RiscV virt board to simplify > multi-core bare-metal development as Virtio needs comparably > more work. > > Signed-off-by: Yanfeng Liu <yfliu2008@qq.com> > --- Just a note that for other architectures we have seen the addition of an extra UART cause breakage for previously working guests, usually because they took the approach of "find the first UART node in the DTB" and/or because different software at different levels of the stack was looking for the UART in the DTB differently and so you ended up with e.g. UEFI outputting on one UART and the kernel on the other. A particular trap is that the order of nodes in the final DTB ends up being the reverse of the order in which they are added in the code in QEMU. Compare commit 5d8a250f9068 (openrisc) and e7100972f2 (arm) for descriptions of some of the things we've run into and the measures we've taken as a result. It's possible that not all of these will be relevant for riscv but it's quite likely that some will. thanks -- PMM
Peter, thanks a lot for the comments, will send v2 later. Regards, Yanfeng On Mon, 2026-06-29 at 10:37 +0100, Peter Maydell wrote: > On Sun, 28 Jun 2026 at 08:06, Yanfeng Liu <yfliu2008@qq.com> wrote: > > > > This adds secondary UART device to RiscV virt board to simplify > > multi-core bare-metal development as Virtio needs comparably > > more work. > > > > Signed-off-by: Yanfeng Liu <yfliu2008@qq.com> > > --- > > Just a note that for other architectures we have seen the > addition of an extra UART cause breakage for previously > working guests, usually because they took the approach of > "find the first UART node in the DTB" and/or because > different software at different levels of the stack was > looking for the UART in the DTB differently and so you > ended up with e.g. UEFI outputting on one UART and the > kernel on the other. A particular trap is that the order > of nodes in the final DTB ends up being the reverse of the > order in which they are added in the code in QEMU. > > Compare commit 5d8a250f9068 (openrisc) and e7100972f2 (arm) > for descriptions of some of the things we've run into and > the measures we've taken as a result. It's possible that > not all of these will be relevant for riscv but it's quite > likely that some will. > > thanks > -- PMM
© 2016 - 2026 Red Hat, Inc.