10ac24d56SAlistair Francis /* 20ac24d56SAlistair Francis * QEMU RISC-V Boot Helper 30ac24d56SAlistair Francis * 40ac24d56SAlistair Francis * Copyright (c) 2017 SiFive, Inc. 50ac24d56SAlistair Francis * Copyright (c) 2019 Alistair Francis <alistair.francis@wdc.com> 60ac24d56SAlistair Francis * 70ac24d56SAlistair Francis * This program is free software; you can redistribute it and/or modify it 80ac24d56SAlistair Francis * under the terms and conditions of the GNU General Public License, 90ac24d56SAlistair Francis * version 2 or later, as published by the Free Software Foundation. 100ac24d56SAlistair Francis * 110ac24d56SAlistair Francis * This program is distributed in the hope it will be useful, but WITHOUT 120ac24d56SAlistair Francis * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 130ac24d56SAlistair Francis * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 140ac24d56SAlistair Francis * more details. 150ac24d56SAlistair Francis * 160ac24d56SAlistair Francis * You should have received a copy of the GNU General Public License along with 170ac24d56SAlistair Francis * this program. If not, see <http://www.gnu.org/licenses/>. 180ac24d56SAlistair Francis */ 190ac24d56SAlistair Francis 200ac24d56SAlistair Francis #include "qemu/osdep.h" 212c65db5eSPaolo Bonzini #include "qemu/datadir.h" 220ac24d56SAlistair Francis #include "qemu/units.h" 230ac24d56SAlistair Francis #include "qemu/error-report.h" 240ac24d56SAlistair Francis #include "exec/cpu-defs.h" 2512e9493dSMarkus Armbruster #include "hw/boards.h" 260ac24d56SAlistair Francis #include "hw/loader.h" 270ac24d56SAlistair Francis #include "hw/riscv/boot.h" 28dc144fe1SAtish Patra #include "hw/riscv/boot_opensbi.h" 290ac24d56SAlistair Francis #include "elf.h" 3043cf723aSAtish Patra #include "sysemu/device_tree.h" 3175ea2529SAlistair Francis #include "sysemu/qtest.h" 32ad40be27SYifei Jiang #include "sysemu/kvm.h" 3364c75db3SJason A. Donenfeld #include "sysemu/reset.h" 340ac24d56SAlistair Francis 3543cf723aSAtish Patra #include <libfdt.h> 3643cf723aSAtish Patra 37a8259b53SAlistair Francis bool riscv_is_32bit(RISCVHartArrayState *harts) 38c4077842SAlistair Francis { 39db23e5d9SRichard Henderson return harts->harts[0].env.misa_mxl_max == MXL_RV32; 40c4077842SAlistair Francis } 41c4077842SAlistair Francis 42bf357e1dSAlistair Francis /* 43bf357e1dSAlistair Francis * Return the per-socket PLIC hart topology configuration string 44bf357e1dSAlistair Francis * (caller must free with g_free()) 45bf357e1dSAlistair Francis */ 46bf357e1dSAlistair Francis char *riscv_plic_hart_config_string(int hart_count) 47bf357e1dSAlistair Francis { 48bf357e1dSAlistair Francis g_autofree const char **vals = g_new(const char *, hart_count + 1); 49bf357e1dSAlistair Francis int i; 50bf357e1dSAlistair Francis 51bf357e1dSAlistair Francis for (i = 0; i < hart_count; i++) { 52bf357e1dSAlistair Francis CPUState *cs = qemu_get_cpu(i); 53bf357e1dSAlistair Francis CPURISCVState *env = &RISCV_CPU(cs)->env; 54bf357e1dSAlistair Francis 55ad40be27SYifei Jiang if (kvm_enabled()) { 56ad40be27SYifei Jiang vals[i] = "S"; 57ad40be27SYifei Jiang } else if (riscv_has_ext(env, RVS)) { 58bf357e1dSAlistair Francis vals[i] = "MS"; 59bf357e1dSAlistair Francis } else { 60bf357e1dSAlistair Francis vals[i] = "M"; 61bf357e1dSAlistair Francis } 62bf357e1dSAlistair Francis } 63bf357e1dSAlistair Francis vals[i] = NULL; 64bf357e1dSAlistair Francis 65bf357e1dSAlistair Francis /* g_strjoinv() obliges us to cast away const here */ 66bf357e1dSAlistair Francis return g_strjoinv(",", (char **)vals); 67bf357e1dSAlistair Francis } 68bf357e1dSAlistair Francis 69a8259b53SAlistair Francis target_ulong riscv_calc_kernel_start_addr(RISCVHartArrayState *harts, 7038bc4e34SAlistair Francis target_ulong firmware_end_addr) { 713ed2b8acSAlistair Francis if (riscv_is_32bit(harts)) { 7238bc4e34SAlistair Francis return QEMU_ALIGN_UP(firmware_end_addr, 4 * MiB); 7338bc4e34SAlistair Francis } else { 7438bc4e34SAlistair Francis return QEMU_ALIGN_UP(firmware_end_addr, 2 * MiB); 7538bc4e34SAlistair Francis } 7638bc4e34SAlistair Francis } 7738bc4e34SAlistair Francis 789d3f7108SDaniel Henrique Barboza const char *riscv_default_firmware_name(RISCVHartArrayState *harts) 799d3f7108SDaniel Henrique Barboza { 809d3f7108SDaniel Henrique Barboza if (riscv_is_32bit(harts)) { 819d3f7108SDaniel Henrique Barboza return RISCV32_BIOS_BIN; 829d3f7108SDaniel Henrique Barboza } 839d3f7108SDaniel Henrique Barboza 849d3f7108SDaniel Henrique Barboza return RISCV64_BIOS_BIN; 859d3f7108SDaniel Henrique Barboza } 869d3f7108SDaniel Henrique Barboza 878f619626SBin Meng static char *riscv_find_bios(const char *bios_filename) 88808faef7SDaniel Henrique Barboza { 89808faef7SDaniel Henrique Barboza char *filename; 90808faef7SDaniel Henrique Barboza 918f619626SBin Meng filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_filename); 92808faef7SDaniel Henrique Barboza if (filename == NULL) { 93808faef7SDaniel Henrique Barboza if (!qtest_enabled()) { 94808faef7SDaniel Henrique Barboza /* 95808faef7SDaniel Henrique Barboza * We only ship OpenSBI binary bios images in the QEMU source. 96808faef7SDaniel Henrique Barboza * For machines that use images other than the default bios, 97808faef7SDaniel Henrique Barboza * running QEMU test will complain hence let's suppress the error 98808faef7SDaniel Henrique Barboza * report for QEMU testing. 99808faef7SDaniel Henrique Barboza */ 1008f619626SBin Meng error_report("Unable to find the RISC-V BIOS \"%s\"", 1018f619626SBin Meng bios_filename); 102808faef7SDaniel Henrique Barboza exit(1); 103808faef7SDaniel Henrique Barboza } 104808faef7SDaniel Henrique Barboza } 105808faef7SDaniel Henrique Barboza 106808faef7SDaniel Henrique Barboza return filename; 107808faef7SDaniel Henrique Barboza } 108808faef7SDaniel Henrique Barboza 1098f619626SBin Meng char *riscv_find_firmware(const char *firmware_filename, 1108f619626SBin Meng const char *default_machine_firmware) 1118f619626SBin Meng { 1128f619626SBin Meng char *filename = NULL; 1138f619626SBin Meng 1148f619626SBin Meng if ((!firmware_filename) || (!strcmp(firmware_filename, "default"))) { 1158f619626SBin Meng /* 1168f619626SBin Meng * The user didn't specify -bios, or has specified "-bios default". 1178f619626SBin Meng * That means we are going to load the OpenSBI binary included in 1188f619626SBin Meng * the QEMU source. 1198f619626SBin Meng */ 1208f619626SBin Meng filename = riscv_find_bios(default_machine_firmware); 1218f619626SBin Meng } else if (strcmp(firmware_filename, "none")) { 1228f619626SBin Meng filename = riscv_find_bios(firmware_filename); 1238f619626SBin Meng } 1248f619626SBin Meng 1258f619626SBin Meng return filename; 1268f619626SBin Meng } 1278f619626SBin Meng 128e66c531eSAlistair Francis target_ulong riscv_find_and_load_firmware(MachineState *machine, 129fdd1bda4SAlistair Francis const char *default_machine_firmware, 13002777ac3SAnup Patel hwaddr firmware_load_addr, 13102777ac3SAnup Patel symbol_fn_t sym_cb) 132fdd1bda4SAlistair Francis { 1338f619626SBin Meng char *firmware_filename; 134e66c531eSAlistair Francis target_ulong firmware_end_addr = firmware_load_addr; 135fdd1bda4SAlistair Francis 1368f619626SBin Meng firmware_filename = riscv_find_firmware(machine->firmware, 1378f619626SBin Meng default_machine_firmware); 138fdd1bda4SAlistair Francis 1393aa9004fSAlistair Francis if (firmware_filename) { 140fdd1bda4SAlistair Francis /* If not "none" load the firmware */ 141e66c531eSAlistair Francis firmware_end_addr = riscv_load_firmware(firmware_filename, 142e66c531eSAlistair Francis firmware_load_addr, sym_cb); 143fdd1bda4SAlistair Francis g_free(firmware_filename); 144fdd1bda4SAlistair Francis } 145e66c531eSAlistair Francis 146e66c531eSAlistair Francis return firmware_end_addr; 147fdd1bda4SAlistair Francis } 148fdd1bda4SAlistair Francis 149b3042223SAlistair Francis target_ulong riscv_load_firmware(const char *firmware_filename, 15002777ac3SAnup Patel hwaddr firmware_load_addr, 15102777ac3SAnup Patel symbol_fn_t sym_cb) 152b3042223SAlistair Francis { 153af975131SJamie Iles uint64_t firmware_entry, firmware_end; 154af975131SJamie Iles ssize_t firmware_size; 155b3042223SAlistair Francis 1561db0c57aSDaniel Henrique Barboza g_assert(firmware_filename != NULL); 1571db0c57aSDaniel Henrique Barboza 15802777ac3SAnup Patel if (load_elf_ram_sym(firmware_filename, NULL, NULL, NULL, 159e66c531eSAlistair Francis &firmware_entry, NULL, &firmware_end, NULL, 16002777ac3SAnup Patel 0, EM_RISCV, 1, 0, NULL, true, sym_cb) > 0) { 161e66c531eSAlistair Francis return firmware_end; 162b3042223SAlistair Francis } 163b3042223SAlistair Francis 164e66c531eSAlistair Francis firmware_size = load_image_targphys_as(firmware_filename, 16582e69054SPaolo Bonzini firmware_load_addr, 16682e69054SPaolo Bonzini current_machine->ram_size, NULL); 167e66c531eSAlistair Francis 168e66c531eSAlistair Francis if (firmware_size > 0) { 169e66c531eSAlistair Francis return firmware_load_addr + firmware_size; 170b3042223SAlistair Francis } 171b3042223SAlistair Francis 172b3042223SAlistair Francis error_report("could not load firmware '%s'", firmware_filename); 173b3042223SAlistair Francis exit(1); 174b3042223SAlistair Francis } 175b3042223SAlistair Francis 17660c1f05eSDaniel Henrique Barboza target_ulong riscv_load_kernel(MachineState *machine, 17738bc4e34SAlistair Francis target_ulong kernel_start_addr, 17838bc4e34SAlistair Francis symbol_fn_t sym_cb) 1790ac24d56SAlistair Francis { 18060c1f05eSDaniel Henrique Barboza const char *kernel_filename = machine->kernel_filename; 1817e322a7fSJessica Clarke uint64_t kernel_load_base, kernel_entry; 1820ac24d56SAlistair Francis 1831db0c57aSDaniel Henrique Barboza g_assert(kernel_filename != NULL); 1841db0c57aSDaniel Henrique Barboza 1857e322a7fSJessica Clarke /* 1867e322a7fSJessica Clarke * NB: Use low address not ELF entry point to ensure that the fw_dynamic 1877e322a7fSJessica Clarke * behaviour when loading an ELF matches the fw_payload, fw_jump and BBL 1887e322a7fSJessica Clarke * behaviour, as well as fw_dynamic with a raw binary, all of which jump to 1897e322a7fSJessica Clarke * the (expected) load address load address. This allows kernels to have 1907e322a7fSJessica Clarke * separate SBI and ELF entry points (used by FreeBSD, for example). 1917e322a7fSJessica Clarke */ 1926478dd74SZhuang, Siwei (Data61, Kensington NSW) if (load_elf_ram_sym(kernel_filename, NULL, NULL, NULL, 1937e322a7fSJessica Clarke NULL, &kernel_load_base, NULL, NULL, 0, 1946478dd74SZhuang, Siwei (Data61, Kensington NSW) EM_RISCV, 1, 0, NULL, true, sym_cb) > 0) { 1957e322a7fSJessica Clarke return kernel_load_base; 1960ac24d56SAlistair Francis } 1970ac24d56SAlistair Francis 198395fd695SAlistair Francis if (load_uimage_as(kernel_filename, &kernel_entry, NULL, NULL, 199395fd695SAlistair Francis NULL, NULL, NULL) > 0) { 2000ac24d56SAlistair Francis return kernel_entry; 2010ac24d56SAlistair Francis } 2020ac24d56SAlistair Francis 20338bc4e34SAlistair Francis if (load_image_targphys_as(kernel_filename, kernel_start_addr, 20482e69054SPaolo Bonzini current_machine->ram_size, NULL) > 0) { 20538bc4e34SAlistair Francis return kernel_start_addr; 206395fd695SAlistair Francis } 207395fd695SAlistair Francis 208395fd695SAlistair Francis error_report("could not load kernel '%s'", kernel_filename); 209395fd695SAlistair Francis exit(1); 210395fd695SAlistair Francis } 211395fd695SAlistair Francis 2121f991461SDaniel Henrique Barboza void riscv_load_initrd(MachineState *machine, uint64_t kernel_entry) 2130ac24d56SAlistair Francis { 2141f991461SDaniel Henrique Barboza const char *filename = machine->initrd_filename; 2151f991461SDaniel Henrique Barboza uint64_t mem_size = machine->ram_size; 2161f991461SDaniel Henrique Barboza void *fdt = machine->fdt; 217b9a65476SDaniel Henrique Barboza hwaddr start, end; 218af975131SJamie Iles ssize_t size; 2190ac24d56SAlistair Francis 2201db0c57aSDaniel Henrique Barboza g_assert(filename != NULL); 2211db0c57aSDaniel Henrique Barboza 2220ac24d56SAlistair Francis /* 2230ac24d56SAlistair Francis * We want to put the initrd far enough into RAM that when the 2240ac24d56SAlistair Francis * kernel is uncompressed it will not clobber the initrd. However 2250ac24d56SAlistair Francis * on boards without much RAM we must ensure that we still leave 2260ac24d56SAlistair Francis * enough room for a decent sized initrd, and on boards with large 2270ac24d56SAlistair Francis * amounts of RAM we must avoid the initrd being so far up in RAM 2280ac24d56SAlistair Francis * that it is outside lowmem and inaccessible to the kernel. 2290ac24d56SAlistair Francis * So for boards with less than 256MB of RAM we put the initrd 2300ac24d56SAlistair Francis * halfway into RAM, and for boards with 256MB of RAM or more we put 2310ac24d56SAlistair Francis * the initrd at 128MB. 2320ac24d56SAlistair Francis */ 233b9a65476SDaniel Henrique Barboza start = kernel_entry + MIN(mem_size / 2, 128 * MiB); 2340ac24d56SAlistair Francis 235b9a65476SDaniel Henrique Barboza size = load_ramdisk(filename, start, mem_size - start); 2360ac24d56SAlistair Francis if (size == -1) { 237b9a65476SDaniel Henrique Barboza size = load_image_targphys(filename, start, mem_size - start); 2380ac24d56SAlistair Francis if (size == -1) { 2390ac24d56SAlistair Francis error_report("could not load ramdisk '%s'", filename); 2400ac24d56SAlistair Francis exit(1); 2410ac24d56SAlistair Francis } 2420ac24d56SAlistair Francis } 2430ac24d56SAlistair Francis 244b9a65476SDaniel Henrique Barboza /* Some RISC-V machines (e.g. opentitan) don't have a fdt. */ 245b9a65476SDaniel Henrique Barboza if (fdt) { 246b9a65476SDaniel Henrique Barboza end = start + size; 247b9a65476SDaniel Henrique Barboza qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-start", start); 248b9a65476SDaniel Henrique Barboza qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-end", end); 249b9a65476SDaniel Henrique Barboza } 2500ac24d56SAlistair Francis } 25143cf723aSAtish Patra 252faee5441SDylan Jhong uint64_t riscv_load_fdt(hwaddr dram_base, uint64_t mem_size, void *fdt) 25366b1205bSAtish Patra { 254faee5441SDylan Jhong uint64_t temp, fdt_addr; 25566b1205bSAtish Patra hwaddr dram_end = dram_base + mem_size; 256*909f7da6SDaniel Henrique Barboza int ret = fdt_pack(fdt); 257*909f7da6SDaniel Henrique Barboza int fdtsize; 25866b1205bSAtish Patra 259*909f7da6SDaniel Henrique Barboza /* Should only fail if we've built a corrupted tree */ 260*909f7da6SDaniel Henrique Barboza g_assert(ret == 0); 261*909f7da6SDaniel Henrique Barboza 262*909f7da6SDaniel Henrique Barboza fdtsize = fdt_totalsize(fdt); 26366b1205bSAtish Patra if (fdtsize <= 0) { 26466b1205bSAtish Patra error_report("invalid device-tree"); 26566b1205bSAtish Patra exit(1); 26666b1205bSAtish Patra } 26766b1205bSAtish Patra 26866b1205bSAtish Patra /* 26966b1205bSAtish Patra * We should put fdt as far as possible to avoid kernel/initrd overwriting 27066b1205bSAtish Patra * its content. But it should be addressable by 32 bit system as well. 271ec2c62daSAlistair Francis * Thus, put it at an 2MB aligned address that less than fdt size from the 2721a475d39SAtish Patra * end of dram or 3GB whichever is lesser. 27366b1205bSAtish Patra */ 274faee5441SDylan Jhong temp = (dram_base < 3072 * MiB) ? MIN(dram_end, 3072 * MiB) : dram_end; 275ec2c62daSAlistair Francis fdt_addr = QEMU_ALIGN_DOWN(temp - fdtsize, 2 * MiB); 27666b1205bSAtish Patra 27766b1205bSAtish Patra /* copy in the device tree */ 27866b1205bSAtish Patra qemu_fdt_dumpdtb(fdt, fdtsize); 27966b1205bSAtish Patra 28066b1205bSAtish Patra rom_add_blob_fixed_as("fdt", fdt, fdtsize, fdt_addr, 28166b1205bSAtish Patra &address_space_memory); 28264c75db3SJason A. Donenfeld qemu_register_reset_nosnapshotload(qemu_fdt_randomize_seeds, 28364c75db3SJason A. Donenfeld rom_ptr_for_as(&address_space_memory, fdt_addr, fdtsize)); 28466b1205bSAtish Patra 28566b1205bSAtish Patra return fdt_addr; 28666b1205bSAtish Patra } 28766b1205bSAtish Patra 28878936771SAlistair Francis void riscv_rom_copy_firmware_info(MachineState *machine, hwaddr rom_base, 28978936771SAlistair Francis hwaddr rom_size, uint32_t reset_vec_size, 29078936771SAlistair Francis uint64_t kernel_entry) 291dc144fe1SAtish Patra { 292dc144fe1SAtish Patra struct fw_dynamic_info dinfo; 293dc144fe1SAtish Patra size_t dinfo_len; 294dc144fe1SAtish Patra 29578936771SAlistair Francis if (sizeof(dinfo.magic) == 4) { 29678936771SAlistair Francis dinfo.magic = cpu_to_le32(FW_DYNAMIC_INFO_MAGIC_VALUE); 29778936771SAlistair Francis dinfo.version = cpu_to_le32(FW_DYNAMIC_INFO_VERSION); 29878936771SAlistair Francis dinfo.next_mode = cpu_to_le32(FW_DYNAMIC_INFO_NEXT_MODE_S); 29978936771SAlistair Francis dinfo.next_addr = cpu_to_le32(kernel_entry); 30078936771SAlistair Francis } else { 30178936771SAlistair Francis dinfo.magic = cpu_to_le64(FW_DYNAMIC_INFO_MAGIC_VALUE); 30278936771SAlistair Francis dinfo.version = cpu_to_le64(FW_DYNAMIC_INFO_VERSION); 30378936771SAlistair Francis dinfo.next_mode = cpu_to_le64(FW_DYNAMIC_INFO_NEXT_MODE_S); 30478936771SAlistair Francis dinfo.next_addr = cpu_to_le64(kernel_entry); 30578936771SAlistair Francis } 306dc144fe1SAtish Patra dinfo.options = 0; 307dc144fe1SAtish Patra dinfo.boot_hart = 0; 308dc144fe1SAtish Patra dinfo_len = sizeof(dinfo); 309dc144fe1SAtish Patra 310dc144fe1SAtish Patra /** 311dc144fe1SAtish Patra * copy the dynamic firmware info. This information is specific to 312dc144fe1SAtish Patra * OpenSBI but doesn't break any other firmware as long as they don't 313dc144fe1SAtish Patra * expect any certain value in "a2" register. 314dc144fe1SAtish Patra */ 315dc144fe1SAtish Patra if (dinfo_len > (rom_size - reset_vec_size)) { 316dc144fe1SAtish Patra error_report("not enough space to store dynamic firmware info"); 317dc144fe1SAtish Patra exit(1); 318dc144fe1SAtish Patra } 319dc144fe1SAtish Patra 320dc144fe1SAtish Patra rom_add_blob_fixed_as("mrom.finfo", &dinfo, dinfo_len, 321dc144fe1SAtish Patra rom_base + reset_vec_size, 322dc144fe1SAtish Patra &address_space_memory); 323dc144fe1SAtish Patra } 324dc144fe1SAtish Patra 325a8259b53SAlistair Francis void riscv_setup_rom_reset_vec(MachineState *machine, RISCVHartArrayState *harts, 3263ed2b8acSAlistair Francis hwaddr start_addr, 32778936771SAlistair Francis hwaddr rom_base, hwaddr rom_size, 32878936771SAlistair Francis uint64_t kernel_entry, 3296934f15bSDaniel Henrique Barboza uint64_t fdt_load_addr) 33043cf723aSAtish Patra { 33143cf723aSAtish Patra int i; 3328590f536SAtish Patra uint32_t start_addr_hi32 = 0x00000000; 333faee5441SDylan Jhong uint32_t fdt_load_addr_hi32 = 0x00000000; 33443cf723aSAtish Patra 3353ed2b8acSAlistair Francis if (!riscv_is_32bit(harts)) { 3368590f536SAtish Patra start_addr_hi32 = start_addr >> 32; 337faee5441SDylan Jhong fdt_load_addr_hi32 = fdt_load_addr >> 32; 33878936771SAlistair Francis } 33943cf723aSAtish Patra /* reset vector */ 34066b1205bSAtish Patra uint32_t reset_vec[10] = { 341dc144fe1SAtish Patra 0x00000297, /* 1: auipc t0, %pcrel_hi(fw_dyn) */ 342dc144fe1SAtish Patra 0x02828613, /* addi a2, t0, %pcrel_lo(1b) */ 34343cf723aSAtish Patra 0xf1402573, /* csrr a0, mhartid */ 34478936771SAlistair Francis 0, 34578936771SAlistair Francis 0, 34643cf723aSAtish Patra 0x00028067, /* jr t0 */ 34743cf723aSAtish Patra start_addr, /* start: .dword */ 3488590f536SAtish Patra start_addr_hi32, 34966b1205bSAtish Patra fdt_load_addr, /* fdt_laddr: .dword */ 350faee5441SDylan Jhong fdt_load_addr_hi32, 351dc144fe1SAtish Patra /* fw_dyn: */ 35243cf723aSAtish Patra }; 3533ed2b8acSAlistair Francis if (riscv_is_32bit(harts)) { 35478936771SAlistair Francis reset_vec[3] = 0x0202a583; /* lw a1, 32(t0) */ 35578936771SAlistair Francis reset_vec[4] = 0x0182a283; /* lw t0, 24(t0) */ 35678936771SAlistair Francis } else { 35778936771SAlistair Francis reset_vec[3] = 0x0202b583; /* ld a1, 32(t0) */ 35878936771SAlistair Francis reset_vec[4] = 0x0182b283; /* ld t0, 24(t0) */ 35978936771SAlistair Francis } 36043cf723aSAtish Patra 36132c435a1SAlistair Francis if (!harts->harts[0].cfg.ext_icsr) { 36232c435a1SAlistair Francis /* 36332c435a1SAlistair Francis * The Zicsr extension has been disabled, so let's ensure we don't 36432c435a1SAlistair Francis * run the CSR instruction. Let's fill the address with a non 36532c435a1SAlistair Francis * compressed nop. 36632c435a1SAlistair Francis */ 36732c435a1SAlistair Francis reset_vec[2] = 0x00000013; /* addi x0, x0, 0 */ 36832c435a1SAlistair Francis } 36932c435a1SAlistair Francis 37043cf723aSAtish Patra /* copy in the reset vector in little_endian byte order */ 37166b1205bSAtish Patra for (i = 0; i < ARRAY_SIZE(reset_vec); i++) { 37243cf723aSAtish Patra reset_vec[i] = cpu_to_le32(reset_vec[i]); 37343cf723aSAtish Patra } 37443cf723aSAtish Patra rom_add_blob_fixed_as("mrom.reset", reset_vec, sizeof(reset_vec), 37543cf723aSAtish Patra rom_base, &address_space_memory); 37678936771SAlistair Francis riscv_rom_copy_firmware_info(machine, rom_base, rom_size, sizeof(reset_vec), 377dc144fe1SAtish Patra kernel_entry); 37843cf723aSAtish Patra } 379ad40be27SYifei Jiang 380ad40be27SYifei Jiang void riscv_setup_direct_kernel(hwaddr kernel_addr, hwaddr fdt_addr) 381ad40be27SYifei Jiang { 382ad40be27SYifei Jiang CPUState *cs; 383ad40be27SYifei Jiang 384ad40be27SYifei Jiang for (cs = first_cpu; cs; cs = CPU_NEXT(cs)) { 385ad40be27SYifei Jiang RISCVCPU *riscv_cpu = RISCV_CPU(cs); 386ad40be27SYifei Jiang riscv_cpu->env.kernel_addr = kernel_addr; 387ad40be27SYifei Jiang riscv_cpu->env.fdt_addr = fdt_addr; 388ad40be27SYifei Jiang } 389ad40be27SYifei Jiang } 390a5b0249dSSunil V L 391a5b0249dSSunil V L void riscv_setup_firmware_boot(MachineState *machine) 392a5b0249dSSunil V L { 393a5b0249dSSunil V L if (machine->kernel_filename) { 394a5b0249dSSunil V L FWCfgState *fw_cfg; 395a5b0249dSSunil V L fw_cfg = fw_cfg_find(); 396a5b0249dSSunil V L 397a5b0249dSSunil V L assert(fw_cfg); 398a5b0249dSSunil V L /* 399a5b0249dSSunil V L * Expose the kernel, the command line, and the initrd in fw_cfg. 400a5b0249dSSunil V L * We don't process them here at all, it's all left to the 401a5b0249dSSunil V L * firmware. 402a5b0249dSSunil V L */ 403a5b0249dSSunil V L load_image_to_fw_cfg(fw_cfg, 404a5b0249dSSunil V L FW_CFG_KERNEL_SIZE, FW_CFG_KERNEL_DATA, 405a5b0249dSSunil V L machine->kernel_filename, 406a5b0249dSSunil V L true); 407a5b0249dSSunil V L load_image_to_fw_cfg(fw_cfg, 408a5b0249dSSunil V L FW_CFG_INITRD_SIZE, FW_CFG_INITRD_DATA, 409a5b0249dSSunil V L machine->initrd_filename, false); 410a5b0249dSSunil V L 411a5b0249dSSunil V L if (machine->kernel_cmdline) { 412a5b0249dSSunil V L fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, 413a5b0249dSSunil V L strlen(machine->kernel_cmdline) + 1); 414a5b0249dSSunil V L fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA, 415a5b0249dSSunil V L machine->kernel_cmdline); 416a5b0249dSSunil V L } 417a5b0249dSSunil V L } 418a5b0249dSSunil V L } 419