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
> 

Reply via email to