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,