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
>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.