All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] hw/riscv/virt: add dram-base machine property
@ 2026-07-30  9:41 Shawn Rutledge
  0 siblings, 0 replies; only message in thread
From: Shawn Rutledge @ 2026-07-30  9:41 UTC (permalink / raw)
  To: qemu-devel

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 <s@ecloud.org>
---
 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



^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2026-07-30  9:42 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-30  9:41 [PATCH] hw/riscv/virt: add dram-base machine property Shawn Rutledge

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.