@samitouri / QOSamiQemu / commits / 772ffd7ff8

hw/riscv/boot: Account for discontiguous memory when loading firmware

This loads firmware into the first (low) memory range, accounting for machines having discontiguous memory regions. Reviewed-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Signed-off-by: Nicholas Piggin <npiggin@gmail.com> Signed-off-by: Joel Stanley <joel@jms.id.au> Message-ID: <20260630024952.1520546-3-joel@jms.id.au> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>

Nicholas Piggin committed Jun 30, 2026 at 12:19 UTC 772ffd7ff883d253e46ce0853fcca525f80532a1
10 files changed +54 -22
hw/riscv/boot.c
+12 -6
@@ -151,6 +151,7 @@ char *riscv_find_firmware(const char *firmware_filename,
151 }
152
153 hwaddr riscv_find_and_load_firmware(MachineState *machine,
154 + RISCVBootInfo *info,
155 const char *default_machine_firmware,
156 hwaddr *firmware_load_addr,
157 symbol_fn_t sym_cb)
@@ -163,7 +164,8 @@ hwaddr riscv_find_and_load_firmware(MachineState *machine,
164
165 if (firmware_filename) {
166 /* If not "none" load the firmware */
166 - firmware_end_addr = riscv_load_firmware(firmware_filename,
167 + firmware_end_addr = riscv_load_firmware(machine, info,
168 + firmware_filename,
169 firmware_load_addr, sym_cb);
170 g_free(firmware_filename);
171 }
@@ -171,10 +173,13 @@ hwaddr riscv_find_and_load_firmware(MachineState *machine,
173 return firmware_end_addr;
174 }
175
174 -hwaddr riscv_load_firmware(const char *firmware_filename,
176 +hwaddr riscv_load_firmware(MachineState *machine,
177 + const RISCVBootInfo *info,
178 + const char *firmware_filename,
179 hwaddr *firmware_load_addr,
180 symbol_fn_t sym_cb)
181 {
182 + uint64_t mem_size = info->ram_low_size ?: machine->ram_size;
183 uint64_t firmware_entry, firmware_end;
184 ssize_t firmware_size;
185
@@ -203,7 +208,7 @@ hwaddr riscv_load_firmware(const char *firmware_filename,
208
209 firmware_size = load_image_targphys_as(firmware_filename,
210 *firmware_load_addr,
206 - current_machine->ram_size, NULL,
211 + mem_size, NULL,
212 NULL);
213
214 if (firmware_size > 0) {
@@ -218,7 +223,7 @@ hwaddr riscv_load_firmware(const char *firmware_filename,
223 static void riscv_load_initrd(MachineState *machine, RISCVBootInfo *info)
224 {
225 const char *filename = machine->initrd_filename;
221 - uint64_t mem_size = machine->ram_size;
226 + uint64_t mem_size = info->ram_low_size ?: machine->ram_size;
227 void *fdt = machine->fdt;
228 hwaddr start, end;
229 ssize_t size;
@@ -264,6 +269,7 @@ void riscv_load_kernel(MachineState *machine,
269 bool load_initrd,
270 symbol_fn_t sym_cb)
271 {
272 + uint64_t mem_size = info->ram_low_size ?: machine->ram_size;
273 const char *kernel_filename = machine->kernel_filename;
274 ssize_t kernel_size;
275 void *fdt = machine->fdt;
@@ -295,7 +301,7 @@ void riscv_load_kernel(MachineState *machine,
301 }
302
303 kernel_size = load_image_targphys_as(kernel_filename, kernel_start_addr,
298 - current_machine->ram_size, NULL, NULL);
304 + mem_size, NULL, NULL);
305 if (kernel_size > 0) {
306 info->kernel_size = kernel_size;
307 info->image_low_addr = kernel_start_addr;
@@ -391,7 +397,7 @@ uint64_t riscv_compute_fdt_addr(hwaddr dram_base, hwaddr dram_size,
397 dtb_start = QEMU_ALIGN_DOWN(temp - fdtsize, 2 * MiB);
398
399 if (dtb_start_limit && (dtb_start < dtb_start_limit)) {
394 - error_report("No enough memory to place DTB after kernel/initrd");
400 + error_report("Not enough memory to place DTB after kernel/initrd");
401 exit(1);
402 }
403
hw/riscv/k230.c
+6 -2
@@ -424,7 +424,8 @@ static void k230_direct_boot(K230MachineState *s, MachineState *machine)
424
425 riscv_load_fdt(K230_DIRECT_DTB_ADDR, machine->fdt);
426
427 - firmware_end_addr = riscv_find_and_load_firmware(machine, firmware_name,
427 + firmware_end_addr = riscv_find_and_load_firmware(machine, &boot_info,
428 + firmware_name,
429 &start_addr, NULL);
430 if (firmware_end_addr > K230_DIRECT_KERNEL_ADDR) {
431 error_report("K230 firmware overlaps kernel address 0x%x",
@@ -442,13 +443,16 @@ static void k230_firmware_boot(K230MachineState *s, MachineState *machine)
443 {
444 const char *firmware_name = riscv_default_firmware_name(&s->soc.c908_cpu);
445 hwaddr start_addr = memmap[K230_DEV_DDRC].base;
446 + RISCVBootInfo boot_info = {0};
447
448 if (machine->dtb || (machine->kernel_cmdline && *machine->kernel_cmdline)) {
449 error_report("K230 firmware boot does not support -dtb or -append");
450 exit(EXIT_FAILURE);
451 }
452
451 - riscv_find_and_load_firmware(machine, firmware_name, &start_addr, NULL);
453 + riscv_boot_info_init(&boot_info, &s->soc.c908_cpu);
454 + riscv_find_and_load_firmware(machine, &boot_info, firmware_name,
455 + &start_addr, NULL);
456
457 riscv_setup_rom_reset_vec(machine, &s->soc.c908_cpu, start_addr,
458 memmap[K230_DEV_BOOTROM].base,
hw/riscv/microchip_pfsoc.c
+6 -2
@@ -619,18 +619,22 @@ static void microchip_icicle_kit_machine_init(MachineState *machine)
619 firmware_load_addr = RESET_VECTOR;
620 }
621
622 + riscv_boot_info_init_discontig_mem(&boot_info, &s->soc.u_cpus,
623 + memmap[MICROCHIP_PFSOC_DRAM_LO].base,
624 + mem_low_size);
625 +
626 /* Load the firmware if necessary */
627 firmware_end_addr = firmware_load_addr;
628 if (firmware_name) {
629 char *filename = riscv_find_firmware(firmware_name, NULL);
630 if (filename) {
627 - firmware_end_addr = riscv_load_firmware(filename,
631 + firmware_end_addr = riscv_load_firmware(machine, &boot_info,
632 + filename,
633 &firmware_load_addr, NULL);
634 g_free(filename);
635 }
636 }
637
633 - riscv_boot_info_init(&boot_info, &s->soc.u_cpus);
638 if (machine->kernel_filename) {
639 kernel_start_addr = riscv_calc_kernel_start_addr(&boot_info,
640 firmware_end_addr);
hw/riscv/opentitan.c
+4 -2
@@ -100,12 +100,14 @@ static void opentitan_machine_init(MachineState *machine)
100 memory_region_add_subregion(sys_mem,
101 memmap[IBEX_DEV_RAM].base, machine->ram);
102
103 + riscv_boot_info_init(&boot_info, &s->soc.cpus);
104 +
105 if (machine->firmware) {
106 hwaddr firmware_load_addr = memmap[IBEX_DEV_RAM].base;
105 - riscv_load_firmware(machine->firmware, &firmware_load_addr, NULL);
107 + riscv_load_firmware(machine, &boot_info, machine->firmware,
108 + &firmware_load_addr, NULL);
109 }
110
108 - riscv_boot_info_init(&boot_info, &s->soc.cpus);
111 if (machine->kernel_filename) {
112 riscv_load_kernel(machine, &boot_info,
113 memmap[IBEX_DEV_RAM].base,
hw/riscv/shakti_c.c
+5 -1
@@ -46,6 +46,7 @@ static void shakti_c_machine_state_init(MachineState *mstate)
46 {
47 ShaktiCMachineState *sms = RISCV_SHAKTI_MACHINE(mstate);
48 MemoryRegion *system_memory = get_system_memory();
49 + RISCVBootInfo boot_info;
50 hwaddr firmware_load_addr = shakti_c_memmap[SHAKTI_C_RAM].base;
51
52 /* Initialize SoC */
@@ -58,8 +59,11 @@ static void shakti_c_machine_state_init(MachineState *mstate)
59 shakti_c_memmap[SHAKTI_C_RAM].base,
60 mstate->ram);
61
62 + riscv_boot_info_init(&boot_info, &sms->soc.cpus);
63 +
64 if (mstate->firmware) {
62 - riscv_load_firmware(mstate->firmware, &firmware_load_addr, NULL);
65 + riscv_load_firmware(mstate, &boot_info, mstate->firmware,
66 + &firmware_load_addr, NULL);
67 }
68
69 /* ROM reset vector */
hw/riscv/sifive_u.c
+4 -2
@@ -524,11 +524,13 @@ static void sifive_u_machine_init(MachineState *machine)
524 break;
525 }
526
527 + riscv_boot_info_init(&boot_info, &s->soc.u_cpus);
528 +
529 firmware_name = riscv_default_firmware_name(&s->soc.u_cpus);
528 - firmware_end_addr = riscv_find_and_load_firmware(machine, firmware_name,
530 + firmware_end_addr = riscv_find_and_load_firmware(machine, &boot_info,
531 + firmware_name,
532 &start_addr, NULL);
533
531 - riscv_boot_info_init(&boot_info, &s->soc.u_cpus);
534 if (machine->kernel_filename) {
535 kernel_start_addr = riscv_calc_kernel_start_addr(&boot_info,
536 firmware_end_addr);
hw/riscv/spike.c
+4 -2
@@ -205,9 +205,12 @@ static void spike_board_init(MachineState *machine)
205 }
206 }
207
208 + riscv_boot_info_init(&boot_info, &s->soc[0]);
209 +
210 /* Load firmware */
211 if (firmware_name) {
210 - firmware_end_addr = riscv_load_firmware(firmware_name,
212 + firmware_end_addr = riscv_load_firmware(machine, &boot_info,
213 + firmware_name,
214 &firmware_load_addr,
215 htif_symbol_callback);
216 g_free(firmware_name);
@@ -217,7 +220,6 @@ static void spike_board_init(MachineState *machine)
220 create_fdt(s, memmap, riscv_is_32bit(&s->soc[0]), htif_custom_base);
221
222 /* Load kernel */
220 - riscv_boot_info_init(&boot_info, &s->soc[0]);
223 if (machine->kernel_filename) {
224 kernel_start_addr = riscv_calc_kernel_start_addr(&boot_info,
225 firmware_end_addr);
hw/riscv/virt.c
+4 -3
@@ -1310,7 +1310,10 @@ static void virt_machine_done(Notifier *notifier, void *data)
1310 }
1311 }
1312
1313 - firmware_end_addr = riscv_find_and_load_firmware(machine, firmware_name,
1313 + riscv_boot_info_init(&boot_info, &s->soc[0]);
1314 +
1315 + firmware_end_addr = riscv_find_and_load_firmware(machine, &boot_info,
1316 + firmware_name,
1317 &start_addr, NULL);
1318
1319 pflash_blk0 = pflash_cfi01_get_blk(s->flash[0]);
@@ -1333,8 +1336,6 @@ static void virt_machine_done(Notifier *notifier, void *data)
1336 }
1337 }
1338
1336 - riscv_boot_info_init(&boot_info, &s->soc[0]);
1337 -
1339 if (machine->kernel_filename && !kernel_entry) {
1340 kernel_start_addr = riscv_calc_kernel_start_addr(&boot_info,
1341 firmware_end_addr);
hw/riscv/xiangshan_kmh.c
+5 -1
@@ -167,6 +167,7 @@ static void xiangshan_kmh_machine_init(MachineState *machine)
167 const MemMapEntry *memmap = xiangshan_kmh_memmap;
168 MemoryRegion *system_memory = get_system_memory();
169 hwaddr start_addr = memmap[XIANGSHAN_KMH_DRAM].base;
170 + RISCVBootInfo boot_info;
171
172 /* Initialize SoC */
173 object_initialize_child(OBJECT(machine), "soc", &s->soc,
@@ -178,13 +179,16 @@ static void xiangshan_kmh_machine_init(MachineState *machine)
179 memmap[XIANGSHAN_KMH_DRAM].base,
180 machine->ram);
181
182 + riscv_boot_info_init(&boot_info, &s->soc.cpus);
183 +
184 /* ROM reset vector */
185 riscv_setup_rom_reset_vec(machine, &s->soc.cpus,
186 start_addr,
187 memmap[XIANGSHAN_KMH_ROM].base,
188 memmap[XIANGSHAN_KMH_ROM].size, 0, 0);
189 if (machine->firmware) {
187 - riscv_load_firmware(machine->firmware, &start_addr, NULL);
190 + riscv_load_firmware(machine, &boot_info, machine->firmware,
191 + &start_addr, NULL);
192 }
193
194 /* Note: dtb has been integrated into firmware(OpenSBI) when compiling */
include/hw/riscv/boot.h
+4 -1
@@ -53,13 +53,16 @@ void riscv_boot_info_init_discontig_mem(RISCVBootInfo *info,
53 vaddr riscv_calc_kernel_start_addr(RISCVBootInfo *info,
54 hwaddr firmware_end_addr);
55 hwaddr riscv_find_and_load_firmware(MachineState *machine,
56 + RISCVBootInfo *info,
57 const char *default_machine_firmware,
58 hwaddr *firmware_load_addr,
59 symbol_fn_t sym_cb);
60 const char *riscv_default_firmware_name(RISCVHartArrayState *harts);
61 char *riscv_find_firmware(const char *firmware_filename,
62 const char *default_machine_firmware);
62 -hwaddr riscv_load_firmware(const char *firmware_filename,
63 +hwaddr riscv_load_firmware(MachineState *machine,
64 + const RISCVBootInfo *info,
65 + const char *firmware_filename,
66 hwaddr *firmware_load_addr,
67 symbol_fn_t sym_cb);
68 void riscv_load_kernel(MachineState *machine,