[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH] hw/riscv: split RAM into low and high memory
From: |
Fei Wu |
Subject: |
[PATCH] hw/riscv: split RAM into low and high memory |
Date: |
Mon, 31 Jul 2023 09:53:17 +0800 |
riscv virt platform's memory started at 0x80000000 and
straddled the 4GiB boundary. Curiously enough, this choice
of a memory layout will prevent from launching a VM with
a bit more than 2000MiB and PCIe pass-thru on an x86 host, due
to identity mapping requirements for the MSI doorbell on x86,
and these (APIC/IOAPIC) live right below 4GiB.
So just split the RAM range into two portions:
- 1 GiB range from 0x80000000 to 0xc0000000.
- The remainder at 0x100000000
...leaving a hole between the ranges.
Signed-off-by: Andrei Warkentin <andrei.warkentin@intel.com>
Signed-off-by: Fei Wu <fei2.wu@intel.com>
---
hw/riscv/virt.c | 74 ++++++++++++++++++++++++++++++++++++-----
include/hw/riscv/virt.h | 1 +
2 files changed, 66 insertions(+), 9 deletions(-)
diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
index d90286dc46..8fbdc7220c 100644
--- a/hw/riscv/virt.c
+++ b/hw/riscv/virt.c
@@ -75,7 +75,9 @@
#error "Can't accomodate all IMSIC groups in address space"
#endif
-static const MemMapEntry virt_memmap[] = {
+#define LOW_MEM (1 * GiB)
+
+static MemMapEntry virt_memmap[] = {
[VIRT_DEBUG] = { 0x0, 0x100 },
[VIRT_MROM] = { 0x1000, 0xf000 },
[VIRT_TEST] = { 0x100000, 0x1000 },
@@ -96,6 +98,7 @@ static const MemMapEntry virt_memmap[] = {
[VIRT_PCIE_ECAM] = { 0x30000000, 0x10000000 },
[VIRT_PCIE_MMIO] = { 0x40000000, 0x40000000 },
[VIRT_DRAM] = { 0x80000000, 0x0 },
+ [VIRT_DRAM_HIGH] = { 0x100000000, 0x0 },
};
/* PCIe high mmio is fixed for RV32 */
@@ -295,15 +298,12 @@ static void create_fdt_socket_cpus(RISCVVirtState *s, int
socket,
}
}
-static void create_fdt_socket_memory(RISCVVirtState *s,
- const MemMapEntry *memmap, int socket)
+static void create_fdt_socket_mem_range(RISCVVirtState *s, uint64_t addr,
+ uint64_t size, int socket)
{
char *mem_name;
- uint64_t addr, size;
MachineState *ms = MACHINE(s);
- addr = memmap[VIRT_DRAM].base + riscv_socket_mem_offset(ms, socket);
- size = riscv_socket_mem_size(ms, socket);
mem_name = g_strdup_printf("/memory@%lx", (long)addr);
qemu_fdt_add_subnode(ms->fdt, mem_name);
qemu_fdt_setprop_cells(ms->fdt, mem_name, "reg",
@@ -313,6 +313,34 @@ static void create_fdt_socket_memory(RISCVVirtState *s,
g_free(mem_name);
}
+static void create_fdt_socket_memory(RISCVVirtState *s,
+ const MemMapEntry *memmap, int socket)
+{
+ uint64_t addr, size;
+ MachineState *mc = MACHINE(s);
+ uint64_t sock_offset = riscv_socket_mem_offset(mc, socket);
+ uint64_t sock_size = riscv_socket_mem_size(mc, socket);
+
+ if (sock_offset < memmap[VIRT_DRAM].size) {
+ uint64_t low_mem_end = memmap[VIRT_DRAM].base + memmap[VIRT_DRAM].size;
+
+ addr = memmap[VIRT_DRAM].base + sock_offset;
+ size = MIN(low_mem_end - addr, sock_size);
+ create_fdt_socket_mem_range(s, addr, size, socket);
+
+ size = sock_size - size;
+ if (size > 0) {
+ create_fdt_socket_mem_range(s, memmap[VIRT_DRAM_HIGH].base,
+ size, socket);
+ }
+ } else {
+ addr = memmap[VIRT_DRAM_HIGH].base +
+ sock_offset - memmap[VIRT_DRAM].size;
+
+ create_fdt_socket_mem_range(s, addr, sock_size, socket);
+ }
+}
+
static void create_fdt_socket_clint(RISCVVirtState *s,
const MemMapEntry *memmap, int socket,
uint32_t *intc_phandles)
@@ -1334,10 +1362,12 @@ static void virt_machine_done(Notifier *notifier, void
*data)
static void virt_machine_init(MachineState *machine)
{
- const MemMapEntry *memmap = virt_memmap;
+ MemMapEntry *memmap = virt_memmap;
RISCVVirtState *s = RISCV_VIRT_MACHINE(machine);
MemoryRegion *system_memory = get_system_memory();
MemoryRegion *mask_rom = g_new(MemoryRegion, 1);
+ MemoryRegion *ram_below_4g, *ram_above_4g;
+ uint64_t ram_size_low, ram_size_high;
char *soc_name;
DeviceState *mmio_irqchip, *virtio_irqchip, *pcie_irqchip;
int i, base_hartid, hart_count;
@@ -1448,6 +1478,17 @@ static void virt_machine_init(MachineState *machine)
}
}
+ if (machine->ram_size > LOW_MEM) {
+ ram_size_high = machine->ram_size - LOW_MEM;
+ ram_size_low = LOW_MEM;
+ } else {
+ ram_size_high = 0;
+ ram_size_low = machine->ram_size;
+ }
+
+ memmap[VIRT_DRAM].size = ram_size_low;
+ memmap[VIRT_DRAM_HIGH].size = ram_size_high;
+
if (riscv_is_32bit(&s->soc[0])) {
#if HOST_LONG_BITS == 64
/* limit RAM size in a 32-bit system */
@@ -1460,7 +1501,8 @@ static void virt_machine_init(MachineState *machine)
virt_high_pcie_memmap.size = VIRT32_HIGH_PCIE_MMIO_SIZE;
} else {
virt_high_pcie_memmap.size = VIRT64_HIGH_PCIE_MMIO_SIZE;
- virt_high_pcie_memmap.base = memmap[VIRT_DRAM].base +
machine->ram_size;
+ virt_high_pcie_memmap.base = memmap[VIRT_DRAM_HIGH].base +
+ memmap[VIRT_DRAM_HIGH].size;
virt_high_pcie_memmap.base =
ROUND_UP(virt_high_pcie_memmap.base, virt_high_pcie_memmap.size);
}
@@ -1468,8 +1510,22 @@ static void virt_machine_init(MachineState *machine)
s->memmap = virt_memmap;
/* register system main memory (actual RAM) */
+ ram_below_4g = g_malloc(sizeof(*ram_below_4g));
+ memory_region_init_alias(ram_below_4g, NULL, "ram-below-4g", machine->ram,
+ 0, memmap[VIRT_DRAM].size);
memory_region_add_subregion(system_memory, memmap[VIRT_DRAM].base,
- machine->ram);
+ ram_below_4g);
+
+ if (memmap[VIRT_DRAM_HIGH].size) {
+ ram_above_4g = g_malloc(sizeof(*ram_above_4g));
+ memory_region_init_alias(ram_above_4g, NULL, "ram-above-4g",
+ machine->ram,
+ memmap[VIRT_DRAM].size,
+ memmap[VIRT_DRAM_HIGH].size);
+ memory_region_add_subregion(system_memory,
+ memmap[VIRT_DRAM_HIGH].base,
+ ram_above_4g);
+ }
/* boot rom */
memory_region_init_rom(mask_rom, NULL, "riscv_virt_board.mrom",
diff --git a/include/hw/riscv/virt.h b/include/hw/riscv/virt.h
index e5c474b26e..36004eb6ef 100644
--- a/include/hw/riscv/virt.h
+++ b/include/hw/riscv/virt.h
@@ -79,6 +79,7 @@ enum {
VIRT_IMSIC_S,
VIRT_FLASH,
VIRT_DRAM,
+ VIRT_DRAM_HIGH,
VIRT_PCIE_MMIO,
VIRT_PCIE_PIO,
VIRT_PLATFORM_BUS,
--
2.34.1
- [PATCH] hw/riscv: split RAM into low and high memory,
Fei Wu <=