diff --git a/docs/system/riscv/microchip-icicle-kit.rst b/docs/system/riscv/microchip-icicle-kit.rst index e803131763..54ced661e3 100644 --- a/docs/system/riscv/microchip-icicle-kit.rst +++ b/docs/system/riscv/microchip-icicle-kit.rst @@ -31,17 +31,37 @@ Boot options The ``microchip-icicle-kit`` machine can start using the standard -bios functionality for loading its BIOS image, aka Hart Software Services (HSS_). -HSS loads the second stage bootloader U-Boot from an SD card. It does not -support direct kernel loading via the -kernel option. One has to load kernel -from U-Boot. +HSS loads the second stage bootloader U-Boot from an SD card. Then a kernel +can be loaded from U-Boot. It also supports direct kernel booting via the +-kernel option along with the device tree blob via -dtb. 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. + +The user provided DTB should have the following requirements: + +* The /cpus node should contain at least one subnode for E51 and the number + of subnodes should match QEMU's ``-smp`` option +* The /memory reg size should match QEMU’s selected ram_size via ``-m`` +* Should contain a node for the CLINT device with a compatible string + "riscv,clint0" + +QEMU follows below truth table to select which payload to execute: + +===== ========== ======= +-bios -kernel payload +===== ========== ======= + N N HSS + Y don't care HSS + N Y kernel +===== ========== ======= The memory is set to 1537 MiB by default which is the minimum required high memory size by HSS. A sanity check on ram size is performed in the machine init routine to prompt user to increase the RAM size to > 1537 MiB when less than 1537 MiB ram is detected. -Boot the machine ----------------- +Running HSS +----------- HSS 2020.12 release is tested at the time of writing. To build an HSS image that can be booted by the ``microchip-icicle-kit`` machine, type the following 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)