[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH v9 1/3] hw/riscv: clear kernel_entry higher bits from load_elf_ra
From: |
Daniel Henrique Barboza |
Subject: |
[PATCH v9 1/3] hw/riscv: clear kernel_entry higher bits from load_elf_ram_sym() |
Date: |
Thu, 19 Jan 2023 18:37:05 -0300 |
load_elf_ram_sym() will sign-extend 32 bit addresses. If a 32 bit
QEMU guest happens to be running in a hypervisor that are using 64
bits to encode its address, kernel_entry can be padded with '1's
and create problems [1].
Use a translate_fn() callback to be called by load_elf_ram_sym() and
return only the 32 bits address if we're running a 32 bit CPU.
[1] https://lists.gnu.org/archive/html/qemu-devel/2023-01/msg02281.html
Suggested-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Suggested-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
---
hw/riscv/boot.c | 20 +++++++++++++++++++-
hw/riscv/microchip_pfsoc.c | 3 ++-
hw/riscv/opentitan.c | 3 ++-
hw/riscv/sifive_e.c | 3 ++-
hw/riscv/sifive_u.c | 3 ++-
hw/riscv/spike.c | 3 ++-
hw/riscv/virt.c | 3 ++-
include/hw/riscv/boot.h | 1 +
8 files changed, 32 insertions(+), 7 deletions(-)
diff --git a/hw/riscv/boot.c b/hw/riscv/boot.c
index 2594276223..46fc7adccf 100644
--- a/hw/riscv/boot.c
+++ b/hw/riscv/boot.c
@@ -173,7 +173,24 @@ target_ulong riscv_load_firmware(const char
*firmware_filename,
exit(1);
}
+static uint64_t translate_kernel_address(void *opaque, uint64_t addr)
+{
+ RISCVHartArrayState *harts = opaque;
+
+ if (riscv_is_32bit(harts)) {
+ /*
+ * For 32 bit CPUs, kernel_load_base is sign-extended
+ * (i.e. it can be padded with '1's) by load_elf().
+ * Remove the sign extension by truncating to 32-bit.
+ */
+ return extract64(addr, 0, 32);
+ }
+
+ return addr;
+}
+
target_ulong riscv_load_kernel(MachineState *machine,
+ RISCVHartArrayState *harts,
target_ulong kernel_start_addr,
symbol_fn_t sym_cb)
{
@@ -189,7 +206,8 @@ target_ulong riscv_load_kernel(MachineState *machine,
* the (expected) load address load address. This allows kernels to have
* separate SBI and ELF entry points (used by FreeBSD, for example).
*/
- if (load_elf_ram_sym(kernel_filename, NULL, NULL, NULL,
+ if (load_elf_ram_sym(kernel_filename, NULL,
+ translate_kernel_address, harts,
NULL, &kernel_load_base, NULL, NULL, 0,
EM_RISCV, 1, 0, NULL, true, sym_cb) > 0) {
return kernel_load_base;
diff --git a/hw/riscv/microchip_pfsoc.c b/hw/riscv/microchip_pfsoc.c
index 82ae5e7023..bdefeb3cbb 100644
--- a/hw/riscv/microchip_pfsoc.c
+++ b/hw/riscv/microchip_pfsoc.c
@@ -629,7 +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);
+ kernel_entry = riscv_load_kernel(machine, &s->soc.u_cpus,
+ kernel_start_addr, NULL);
if (machine->initrd_filename) {
riscv_load_initrd(machine, kernel_entry);
diff --git a/hw/riscv/opentitan.c b/hw/riscv/opentitan.c
index 64d5d435b9..2731138c41 100644
--- a/hw/riscv/opentitan.c
+++ b/hw/riscv/opentitan.c
@@ -101,7 +101,8 @@ 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, NULL);
}
}
diff --git a/hw/riscv/sifive_e.c b/hw/riscv/sifive_e.c
index 3e3f4b0088..1a7d381514 100644
--- a/hw/riscv/sifive_e.c
+++ b/hw/riscv/sifive_e.c
@@ -114,7 +114,8 @@ 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, NULL);
}
}
diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c
index 2fb6ee231f..83dfe09877 100644
--- a/hw/riscv/sifive_u.c
+++ b/hw/riscv/sifive_u.c
@@ -598,7 +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);
+ kernel_entry = riscv_load_kernel(machine, &s->soc.u_cpus,
+ kernel_start_addr, NULL);
if (machine->initrd_filename) {
riscv_load_initrd(machine, kernel_entry);
diff --git a/hw/riscv/spike.c b/hw/riscv/spike.c
index badc11ec43..2bcc50d90d 100644
--- a/hw/riscv/spike.c
+++ b/hw/riscv/spike.c
@@ -305,7 +305,8 @@ 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,
+ kernel_entry = riscv_load_kernel(machine, &s->soc[0],
+ kernel_start_addr,
htif_symbol_callback);
if (machine->initrd_filename) {
diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
index 4a11b4b010..ac173a6ed6 100644
--- a/hw/riscv/virt.c
+++ b/hw/riscv/virt.c
@@ -1274,7 +1274,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);
+ kernel_entry = riscv_load_kernel(machine, &s->soc[0],
+ kernel_start_addr, NULL);
if (machine->initrd_filename) {
riscv_load_initrd(machine, kernel_entry);
diff --git a/include/hw/riscv/boot.h b/include/hw/riscv/boot.h
index f94653a09b..105706bf25 100644
--- a/include/hw/riscv/boot.h
+++ b/include/hw/riscv/boot.h
@@ -44,6 +44,7 @@ target_ulong riscv_load_firmware(const char
*firmware_filename,
hwaddr firmware_load_addr,
symbol_fn_t sym_cb);
target_ulong riscv_load_kernel(MachineState *machine,
+ RISCVHartArrayState *harts,
target_ulong firmware_end_addr,
symbol_fn_t sym_cb);
void riscv_load_initrd(MachineState *machine, uint64_t kernel_entry);
--
2.39.0