Re: [PATCH] hw/riscv/virt: add dram-base machine property
lists <[email protected]>
| Newsgroups | gmane.comp.emulators.qemu |
|---|---|
| Message-ID | <[email protected]> |
Ping. Do you have a different solution to emulate memory layouts of actual boards? For me this is necessary for the Plan 9 porting work: a Banana Pi F3 has a different base address than one of the K3 boards, and both different than the QEMU default. > On Jul 30, 2026, at 12:42, Shawn Rutledge <[email protected]> wrote: > > The 'virt' RISC-V machine hardcodes its DRAM base to 0x80000000. > Real-world RISC-V SoCs put DRAM elsewhere (SpacemiT K1 at 0x40000000, > SpacemiT K3 at 0x100000000, etc.), which forces ports that target > those boards to build separate kernels for QEMU testing. > > Add a 'dram-base' string property that lets users move VIRT_DRAM up > without rebuilding QEMU. Values must be 2 MiB-aligned and at or > above the default 0x80000000 to avoid colliding with statically- > placed MMIO regions (PCIE_MMIO ends at 0x80000000). Lower bases > would also require moving PCIE_MMIO/IMSIC/etc. and are rejected with > an explicit error pointing at the cause. > > Example: > qemu-system-riscv64 -machine virt,dram-base=0x100000000 -m 6G ... > runs OpenSBI at firmware base 0x100000000, matching K3 memory layout. > > Signed-off-by: Shawn Rutledge <[email protected]> > --- > hw/riscv/virt.c | 59 ++++++++++++++++++++++++++++++++++++++++- > include/hw/riscv/virt.h | 2 ++ > 2 files changed, 60 insertions(+), 1 deletion(-) > > diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c > index 51bac47a91..6ccc98842f 100644 > --- a/hw/riscv/virt.c > +++ b/hw/riscv/virt.c > @@ -20,6 +20,7 @@ > > #include "qemu/osdep.h" > #include "qemu/units.h" > +#include "qemu/cutils.h" > #include "qemu/error-report.h" > #include "qemu/guest-random.h" > #include "qapi/error.h" > @@ -1307,7 +1308,13 @@ static void virt_machine_init(MachineState *machine) > int i, base_hartid, hart_count; > int socket_count = riscv_socket_count(machine); > > - s->memmap = virt_memmap; > + if (s->dram_base) { > + s->memmap_storage = g_memdup2(virt_memmap, sizeof(virt_memmap)); > + s->memmap_storage[VIRT_DRAM].base = s->dram_base; > + s->memmap = s->memmap_storage; > + } else { > + s->memmap = virt_memmap; > + } > > /* Check socket count limit */ > if (VIRT_SOCKETS_MAX < socket_count) { > @@ -1545,6 +1552,7 @@ static void virt_machine_instance_finalize(Object *obj) > } > g_free(s->oem_id); > g_free(s->oem_table_id); > + g_free(s->memmap_storage); > } > > static void virt_machine_instance_init(Object *obj) > @@ -1616,6 +1624,46 @@ static void virt_set_aia(Object *obj, const char *val, Error **errp) > } > } > > +static char *virt_get_dram_base(Object *obj, Error **errp) > +{ > + RISCVVirtState *s = RISCV_VIRT_MACHINE(obj); > + uint64_t val = s->dram_base ? s->dram_base : virt_memmap[VIRT_DRAM].base; > + > + return g_strdup_printf("0x%" PRIx64, val); > +} > + > +static void virt_set_dram_base(Object *obj, const char *val, Error **errp) > +{ > + RISCVVirtState *s = RISCV_VIRT_MACHINE(obj); > + const char *endptr; > + uint64_t base; > + > + if (qemu_strtou64(val, &endptr, 0, &base) < 0 || *endptr != '\0') { > + error_setg(errp, "Invalid dram-base value '%s'", val); > + return; > + } > + /* > + * DRAM must clear all statically-placed MMIO regions in virt_memmap[] > + * (PCIE_MMIO ends at 0x80000000) and be 2 MiB-aligned so a standard > + * OpenSBI + kernel layout (firmware at base, kernel at base+0x200000) > + * fits. Values below the default base would collide with on-board > + * MMIO and are rejected. > + */ > + if (base < virt_memmap[VIRT_DRAM].base) { > + error_setg(errp, > + "dram-base 0x%" PRIx64 " is below default 0x%" PRIx64 > + "; would collide with static MMIO regions", > + base, (uint64_t)virt_memmap[VIRT_DRAM].base); > + return; > + } > + if (base & (2 * MiB - 1)) { > + error_setg(errp, "dram-base 0x%" PRIx64 " must be 2 MiB-aligned", > + base); > + return; > + } > + s->dram_base = base; > +} > + > static bool virt_get_aclint(Object *obj, Error **errp) > { > RISCVVirtState *s = RISCV_VIRT_MACHINE(obj); > @@ -1744,6 +1792,15 @@ static void virt_machine_class_init(ObjectClass *oc, const void *data) > machine_class_allow_dynamic_sysbus_dev(mc, TYPE_TPM_TIS_SYSBUS); > #endif > > + object_class_property_add_str(oc, "dram-base", virt_get_dram_base, > + virt_set_dram_base); > + object_class_property_set_description(oc, "dram-base", > + "Base physical address of DRAM " > + "(default 0x80000000). Must be " > + "2 MiB-aligned and at or above " > + "the default to avoid colliding " > + "with statically-placed MMIO."); > + > object_class_property_add_bool(oc, "aclint", virt_get_aclint, > virt_set_aclint); > object_class_property_set_description(oc, "aclint", > diff --git a/include/hw/riscv/virt.h b/include/hw/riscv/virt.h > index 36a2def410..be8a4ac049 100644 > --- a/include/hw/riscv/virt.h > +++ b/include/hw/riscv/virt.h > @@ -61,6 +61,8 @@ struct RISCVVirtState { > char *oem_table_id; > OnOffAuto acpi; > const MemMapEntry *memmap; > + MemMapEntry *memmap_storage; /* g_malloc'd copy when dram-base override is set */ > + uint64_t dram_base; /* 0 = use compiled-in default (0x80000000) */ > struct GPEXHost *gpex_host; > OnOffAuto iommu_sys; > uint16_t pci_iommu_bdf; > -- > 2.55.0 >