aboutsummaryrefslogtreecommitdiff
path: root/hw/riscv
diff options
context:
space:
mode:
authorBin Meng <bin.meng@windriver.com>2021-04-30 15:13:02 +0800
committerAlistair Francis <alistair.francis@wdc.com>2021-06-08 09:59:42 +1000
commit143897b50140cfd7540f867edca5d658e76aa9bf (patch)
treea692283ffa71f67886d59c56c3110dbe141f94bb /hw/riscv
parenta0acd0a175891afe554c907c4ecc941abbd98602 (diff)
hw/riscv: microchip_pfsoc: Support direct kernel boot
At present the Microchip Icicle Kit machine only supports using '-bios' to load the HSS, and does not support '-kernel' for direct kernel booting just like other RISC-V machines do. One has to use U-Boot which is chain-loaded by HSS, to load a kernel for testing. This is not so convenient. Adding '-kernel' support together with the existing '-bios', we follow the following table to select which payload we execute: -bios | -kernel | payload ------+------------+-------- N | N | HSS Y | don't care | HSS N | Y | kernel This ensures backwards compatibility with how we used to expose '-bios' to users. When '-kernel' is used for direct boot, '-dtb' must be present to provide a valid device tree for the board, as we don't generate device tree. When direct kernel boot is used, the OpenSBI fw_dynamic BIOS image is used to boot a payload like U-Boot or OS kernel directly. Documentation is updated to describe the direct kernel boot. Note as of today there is still no PolarFire SoC support in the upstream Linux kernel hence the document does not include instructions for that. It will be updated in the future. Signed-off-by: Bin Meng <bin.meng@windriver.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-id: 20210430071302.1489082-8-bmeng.cn@gmail.com Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
Diffstat (limited to 'hw/riscv')
-rw-r--r--hw/riscv/microchip_pfsoc.c81
1 files changed, 78 insertions, 3 deletions
diff --git a/hw/riscv/microchip_pfsoc.c b/hw/riscv/microchip_pfsoc.c
index 6cbd17ebf2..eb8e79e0a1 100644
--- a/hw/riscv/microchip_pfsoc.c
+++ b/hw/riscv/microchip_pfsoc.c
@@ -51,6 +51,7 @@
#include "hw/riscv/microchip_pfsoc.h"
#include "hw/intc/sifive_clint.h"
#include "hw/intc/sifive_plic.h"
+#include "sysemu/device_tree.h"
#include "sysemu/sysemu.h"
/*
@@ -460,6 +461,12 @@ static void microchip_icicle_kit_machine_init(MachineState *machine)
MemoryRegion *mem_high = g_new(MemoryRegion, 1);
MemoryRegion *mem_high_alias = g_new(MemoryRegion, 1);
uint64_t mem_high_size;
+ hwaddr firmware_load_addr;
+ const char *firmware_name;
+ bool kernel_as_payload = false;
+ target_ulong firmware_end_addr, kernel_start_addr;
+ uint64_t kernel_entry;
+ uint32_t fdt_load_addr;
DriveInfo *dinfo = drive_get_next(IF_SD);
/* Sanity check on RAM size */
@@ -504,9 +511,6 @@ static void microchip_icicle_kit_machine_init(MachineState *machine)
memmap[MICROCHIP_PFSOC_DRAM_HI_ALIAS].base,
mem_high_alias);
- /* Load the firmware */
- riscv_find_and_load_firmware(machine, BIOS_FILENAME, RESET_VECTOR, NULL);
-
/* Attach an SD card */
if (dinfo) {
CadenceSDHCIState *sdhci = &(s->soc.sdhci);
@@ -516,6 +520,77 @@ static void microchip_icicle_kit_machine_init(MachineState *machine)
&error_fatal);
qdev_realize_and_unref(card, sdhci->bus, &error_fatal);
}
+
+ /*
+ * We follow the following table to select which payload we execute.
+ *
+ * -bios | -kernel | payload
+ * -------+------------+--------
+ * N | N | HSS
+ * Y | don't care | HSS
+ * N | Y | kernel
+ *
+ * This ensures backwards compatibility with how we used to expose -bios
+ * to users but allows them to run through direct kernel booting as well.
+ *
+ * When -kernel is used for direct boot, -dtb must be present to provide
+ * a valid device tree for the board, as we don't generate device tree.
+ */
+
+ if (machine->kernel_filename && machine->dtb) {
+ int fdt_size;
+ machine->fdt = load_device_tree(machine->dtb, &fdt_size);
+ if (!machine->fdt) {
+ error_report("load_device_tree() failed");
+ exit(1);
+ }
+
+ firmware_name = RISCV64_BIOS_BIN;
+ firmware_load_addr = memmap[MICROCHIP_PFSOC_DRAM_LO].base;
+ kernel_as_payload = true;
+ }
+
+ if (!kernel_as_payload) {
+ firmware_name = BIOS_FILENAME;
+ firmware_load_addr = RESET_VECTOR;
+ }
+
+ /* Load the firmware */
+ firmware_end_addr = riscv_find_and_load_firmware(machine, firmware_name,
+ firmware_load_addr, NULL);
+
+ if (kernel_as_payload) {
+ kernel_start_addr = riscv_calc_kernel_start_addr(&s->soc.u_cpus,
+ firmware_end_addr);
+
+ kernel_entry = riscv_load_kernel(machine->kernel_filename,
+ kernel_start_addr, NULL);
+
+ if (machine->initrd_filename) {
+ hwaddr start;
+ hwaddr end = riscv_load_initrd(machine->initrd_filename,
+ machine->ram_size, kernel_entry,
+ &start);
+ qemu_fdt_setprop_cell(machine->fdt, "/chosen",
+ "linux,initrd-start", start);
+ qemu_fdt_setprop_cell(machine->fdt, "/chosen",
+ "linux,initrd-end", end);
+ }
+
+ if (machine->kernel_cmdline) {
+ qemu_fdt_setprop_string(machine->fdt, "/chosen",
+ "bootargs", machine->kernel_cmdline);
+ }
+
+ /* Compute the fdt load address in dram */
+ fdt_load_addr = riscv_load_fdt(memmap[MICROCHIP_PFSOC_DRAM_LO].base,
+ machine->ram_size, machine->fdt);
+ /* Load the reset vector */
+ riscv_setup_rom_reset_vec(machine, &s->soc.u_cpus, firmware_load_addr,
+ memmap[MICROCHIP_PFSOC_ENVM_DATA].base,
+ memmap[MICROCHIP_PFSOC_ENVM_DATA].size,
+ kernel_entry, fdt_load_addr, machine->fdt);
+ }
}
static void microchip_icicle_kit_machine_class_init(ObjectClass *oc, void *data)