aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
Diffstat (limited to 'hw')
-rw-r--r--hw/riscv/boot.c97
-rw-r--r--hw/riscv/microchip_pfsoc.c12
-rw-r--r--hw/riscv/opentitan.c4
-rw-r--r--hw/riscv/sifive_e.c4
-rw-r--r--hw/riscv/sifive_u.c12
-rw-r--r--hw/riscv/spike.c14
-rw-r--r--hw/riscv/virt.c12
7 files changed, 76 insertions, 79 deletions
diff --git a/hw/riscv/boot.c b/hw/riscv/boot.c
index c7e0e50bd8..52bf8e67de 100644
--- a/hw/riscv/boot.c
+++ b/hw/riscv/boot.c
@@ -173,12 +173,55 @@ target_ulong riscv_load_firmware(const char *firmware_filename,
exit(1);
}
+static void riscv_load_initrd(MachineState *machine, uint64_t kernel_entry)
+{
+ const char *filename = machine->initrd_filename;
+ uint64_t mem_size = machine->ram_size;
+ void *fdt = machine->fdt;
+ hwaddr start, end;
+ ssize_t size;
+
+ g_assert(filename != NULL);
+
+ /*
+ * We want to put the initrd far enough into RAM that when the
+ * kernel is uncompressed it will not clobber the initrd. However
+ * on boards without much RAM we must ensure that we still leave
+ * enough room for a decent sized initrd, and on boards with large
+ * amounts of RAM we must avoid the initrd being so far up in RAM
+ * that it is outside lowmem and inaccessible to the kernel.
+ * So for boards with less than 256MB of RAM we put the initrd
+ * halfway into RAM, and for boards with 256MB of RAM or more we put
+ * the initrd at 128MB.
+ */
+ start = kernel_entry + MIN(mem_size / 2, 128 * MiB);
+
+ size = load_ramdisk(filename, start, mem_size - start);
+ if (size == -1) {
+ size = load_image_targphys(filename, start, mem_size - start);
+ if (size == -1) {
+ error_report("could not load ramdisk '%s'", filename);
+ exit(1);
+ }
+ }
+
+ /* Some RISC-V machines (e.g. opentitan) don't have a fdt. */
+ if (fdt) {
+ end = start + size;
+ qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-start", start);
+ qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-end", end);
+ }
+}
+
target_ulong riscv_load_kernel(MachineState *machine,
+ RISCVHartArrayState *harts,
target_ulong kernel_start_addr,
+ bool load_initrd,
symbol_fn_t sym_cb)
{
const char *kernel_filename = machine->kernel_filename;
uint64_t kernel_load_base, kernel_entry;
+ void *fdt = machine->fdt;
g_assert(kernel_filename != NULL);
@@ -192,61 +235,43 @@ target_ulong riscv_load_kernel(MachineState *machine,
if (load_elf_ram_sym(kernel_filename, NULL, NULL, NULL,
NULL, &kernel_load_base, NULL, NULL, 0,
EM_RISCV, 1, 0, NULL, true, sym_cb) > 0) {
- return kernel_load_base;
+ kernel_entry = kernel_load_base;
+ goto out;
}
if (load_uimage_as(kernel_filename, &kernel_entry, NULL, NULL,
NULL, NULL, NULL) > 0) {
- return kernel_entry;
+ goto out;
}
if (load_image_targphys_as(kernel_filename, kernel_start_addr,
current_machine->ram_size, NULL) > 0) {
- return kernel_start_addr;
+ kernel_entry = kernel_start_addr;
+ goto out;
}
error_report("could not load kernel '%s'", kernel_filename);
exit(1);
-}
-
-void riscv_load_initrd(MachineState *machine, uint64_t kernel_entry)
-{
- const char *filename = machine->initrd_filename;
- uint64_t mem_size = machine->ram_size;
- void *fdt = machine->fdt;
- hwaddr start, end;
- ssize_t size;
-
- g_assert(filename != NULL);
+out:
/*
- * We want to put the initrd far enough into RAM that when the
- * kernel is uncompressed it will not clobber the initrd. However
- * on boards without much RAM we must ensure that we still leave
- * enough room for a decent sized initrd, and on boards with large
- * amounts of RAM we must avoid the initrd being so far up in RAM
- * that it is outside lowmem and inaccessible to the kernel.
- * So for boards with less than 256MB of RAM we put the initrd
- * halfway into RAM, and for boards with 256MB of RAM or more we put
- * the initrd at 128MB.
+ * For 32 bit CPUs 'kernel_entry' can be sign-extended by
+ * load_elf_ram_sym().
*/
- start = kernel_entry + MIN(mem_size / 2, 128 * MiB);
+ if (riscv_is_32bit(harts)) {
+ kernel_entry = extract64(kernel_entry, 0, 32);
+ }
- size = load_ramdisk(filename, start, mem_size - start);
- if (size == -1) {
- size = load_image_targphys(filename, start, mem_size - start);
- if (size == -1) {
- error_report("could not load ramdisk '%s'", filename);
- exit(1);
- }
+ if (load_initrd && machine->initrd_filename) {
+ riscv_load_initrd(machine, kernel_entry);
}
- /* Some RISC-V machines (e.g. opentitan) don't have a fdt. */
- if (fdt) {
- end = start + size;
- qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-start", start);
- qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-end", end);
+ if (fdt && machine->kernel_cmdline && *machine->kernel_cmdline) {
+ qemu_fdt_setprop_string(fdt, "/chosen", "bootargs",
+ machine->kernel_cmdline);
}
+
+ return kernel_entry;
}
/*
diff --git a/hw/riscv/microchip_pfsoc.c b/hw/riscv/microchip_pfsoc.c
index 2b91e49561..e81bbd12df 100644
--- a/hw/riscv/microchip_pfsoc.c
+++ b/hw/riscv/microchip_pfsoc.c
@@ -629,16 +629,8 @@ static void microchip_icicle_kit_machine_init(MachineState *machine)
kernel_start_addr = riscv_calc_kernel_start_addr(&s->soc.u_cpus,
firmware_end_addr);
- kernel_entry = riscv_load_kernel(machine, kernel_start_addr, NULL);
-
- if (machine->initrd_filename) {
- riscv_load_initrd(machine, kernel_entry);
- }
-
- if (machine->kernel_cmdline && *machine->kernel_cmdline) {
- qemu_fdt_setprop_string(machine->fdt, "/chosen",
- "bootargs", machine->kernel_cmdline);
- }
+ kernel_entry = riscv_load_kernel(machine, &s->soc.u_cpus,
+ kernel_start_addr, true, NULL);
/* Compute the fdt load address in dram */
fdt_load_addr = riscv_compute_fdt_addr(memmap[MICROCHIP_PFSOC_DRAM_LO].base,
diff --git a/hw/riscv/opentitan.c b/hw/riscv/opentitan.c
index 353f030d80..b06944d382 100644
--- a/hw/riscv/opentitan.c
+++ b/hw/riscv/opentitan.c
@@ -101,7 +101,9 @@ static void opentitan_board_init(MachineState *machine)
}
if (machine->kernel_filename) {
- riscv_load_kernel(machine, memmap[IBEX_DEV_RAM].base, NULL);
+ riscv_load_kernel(machine, &s->soc.cpus,
+ memmap[IBEX_DEV_RAM].base,
+ false, NULL);
}
}
diff --git a/hw/riscv/sifive_e.c b/hw/riscv/sifive_e.c
index 3e3f4b0088..04939b60c3 100644
--- a/hw/riscv/sifive_e.c
+++ b/hw/riscv/sifive_e.c
@@ -114,7 +114,9 @@ static void sifive_e_machine_init(MachineState *machine)
memmap[SIFIVE_E_DEV_MROM].base, &address_space_memory);
if (machine->kernel_filename) {
- riscv_load_kernel(machine, memmap[SIFIVE_E_DEV_DTIM].base, NULL);
+ riscv_load_kernel(machine, &s->soc.cpus,
+ memmap[SIFIVE_E_DEV_DTIM].base,
+ false, NULL);
}
}
diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c
index d3ab7a9cda..ad3bb35b34 100644
--- a/hw/riscv/sifive_u.c
+++ b/hw/riscv/sifive_u.c
@@ -598,16 +598,8 @@ static void sifive_u_machine_init(MachineState *machine)
kernel_start_addr = riscv_calc_kernel_start_addr(&s->soc.u_cpus,
firmware_end_addr);
- kernel_entry = riscv_load_kernel(machine, kernel_start_addr, NULL);
-
- if (machine->initrd_filename) {
- riscv_load_initrd(machine, kernel_entry);
- }
-
- if (machine->kernel_cmdline && *machine->kernel_cmdline) {
- qemu_fdt_setprop_string(machine->fdt, "/chosen", "bootargs",
- machine->kernel_cmdline);
- }
+ kernel_entry = riscv_load_kernel(machine, &s->soc.u_cpus,
+ kernel_start_addr, true, NULL);
} else {
/*
* If dynamic firmware is used, it doesn't know where is the next mode
diff --git a/hw/riscv/spike.c b/hw/riscv/spike.c
index cc3f6dac17..a584d5b3a2 100644
--- a/hw/riscv/spike.c
+++ b/hw/riscv/spike.c
@@ -305,17 +305,9 @@ static void spike_board_init(MachineState *machine)
kernel_start_addr = riscv_calc_kernel_start_addr(&s->soc[0],
firmware_end_addr);
- kernel_entry = riscv_load_kernel(machine, kernel_start_addr,
- htif_symbol_callback);
-
- if (machine->initrd_filename) {
- riscv_load_initrd(machine, kernel_entry);
- }
-
- if (machine->kernel_cmdline && *machine->kernel_cmdline) {
- qemu_fdt_setprop_string(machine->fdt, "/chosen", "bootargs",
- machine->kernel_cmdline);
- }
+ kernel_entry = riscv_load_kernel(machine, &s->soc[0],
+ kernel_start_addr,
+ true, htif_symbol_callback);
} else {
/*
* If dynamic firmware is used, it doesn't know where is the next mode
diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
index b81081c70b..86c4adc0c9 100644
--- a/hw/riscv/virt.c
+++ b/hw/riscv/virt.c
@@ -1277,16 +1277,8 @@ static void virt_machine_done(Notifier *notifier, void *data)
kernel_start_addr = riscv_calc_kernel_start_addr(&s->soc[0],
firmware_end_addr);
- kernel_entry = riscv_load_kernel(machine, kernel_start_addr, NULL);
-
- if (machine->initrd_filename) {
- riscv_load_initrd(machine, kernel_entry);
- }
-
- if (machine->kernel_cmdline && *machine->kernel_cmdline) {
- qemu_fdt_setprop_string(machine->fdt, "/chosen", "bootargs",
- machine->kernel_cmdline);
- }
+ kernel_entry = riscv_load_kernel(machine, &s->soc[0],
+ kernel_start_addr, true, NULL);
} else {
/*
* If dynamic firmware is used, it doesn't know where is the next mode