diff --git a/MAINTAINERS b/MAINTAINERS index eb917e48c0..5c1ee41139 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -287,6 +287,9 @@ RISC-V TCG CPUs M: Palmer Dabbelt M: Alistair Francis M: Bin Meng +R: Weiwei Li +R: Daniel Henrique Barboza +R: Liu Zhiwei L: qemu-riscv@nongnu.org S: Supported F: target/riscv/ 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,43 +173,7 @@ target_ulong riscv_load_firmware(const char *firmware_filename, exit(1); } -target_ulong riscv_load_kernel(MachineState *machine, - target_ulong kernel_start_addr, - symbol_fn_t sym_cb) -{ - const char *kernel_filename = machine->kernel_filename; - uint64_t kernel_load_base, kernel_entry; - - g_assert(kernel_filename != NULL); - - /* - * NB: Use low address not ELF entry point to ensure that the fw_dynamic - * behaviour when loading an ELF matches the fw_payload, fw_jump and BBL - * behaviour, as well as fw_dynamic with a raw binary, all of which jump to - * 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, - NULL, &kernel_load_base, NULL, NULL, 0, - EM_RISCV, 1, 0, NULL, true, sym_cb) > 0) { - return kernel_load_base; - } - - if (load_uimage_as(kernel_filename, &kernel_entry, NULL, NULL, - NULL, NULL, NULL) > 0) { - return kernel_entry; - } - - if (load_image_targphys_as(kernel_filename, kernel_start_addr, - current_machine->ram_size, NULL) > 0) { - return kernel_start_addr; - } - - error_report("could not load kernel '%s'", kernel_filename); - exit(1); -} - -void riscv_load_initrd(MachineState *machine, uint64_t kernel_entry) +static void riscv_load_initrd(MachineState *machine, uint64_t kernel_entry) { const char *filename = machine->initrd_filename; uint64_t mem_size = machine->ram_size; @@ -249,6 +213,67 @@ void riscv_load_initrd(MachineState *machine, uint64_t kernel_entry) } } +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); + + /* + * NB: Use low address not ELF entry point to ensure that the fw_dynamic + * behaviour when loading an ELF matches the fw_payload, fw_jump and BBL + * behaviour, as well as fw_dynamic with a raw binary, all of which jump to + * 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, + NULL, &kernel_load_base, NULL, NULL, 0, + EM_RISCV, 1, 0, NULL, true, sym_cb) > 0) { + kernel_entry = kernel_load_base; + goto out; + } + + if (load_uimage_as(kernel_filename, &kernel_entry, NULL, NULL, + NULL, NULL, NULL) > 0) { + goto out; + } + + if (load_image_targphys_as(kernel_filename, kernel_start_addr, + current_machine->ram_size, NULL) > 0) { + kernel_entry = kernel_start_addr; + goto out; + } + + error_report("could not load kernel '%s'", kernel_filename); + exit(1); + +out: + /* + * For 32 bit CPUs 'kernel_entry' can be sign-extended by + * load_elf_ram_sym(). + */ + if (riscv_is_32bit(harts)) { + kernel_entry = extract64(kernel_entry, 0, 32); + } + + if (load_initrd && machine->initrd_filename) { + riscv_load_initrd(machine, kernel_entry); + } + + if (fdt && machine->kernel_cmdline && *machine->kernel_cmdline) { + qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", + machine->kernel_cmdline); + } + + return kernel_entry; +} + /* * This function makes an assumption that the DRAM interval * 'dram_base' + 'dram_size' is contiguous. 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 diff --git a/include/hw/riscv/boot.h b/include/hw/riscv/boot.h index 511390f60e..a2e4ae9cb0 100644 --- a/include/hw/riscv/boot.h +++ b/include/hw/riscv/boot.h @@ -44,9 +44,10 @@ 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, + bool load_initrd, symbol_fn_t sym_cb); -void riscv_load_initrd(MachineState *machine, uint64_t kernel_entry); uint64_t riscv_compute_fdt_addr(hwaddr dram_start, uint64_t dram_size, MachineState *ms); void riscv_load_fdt(hwaddr fdt_addr, void *fdt); diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 0dd2f0c753..93b52b826c 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -73,7 +73,7 @@ struct isa_ext_data { */ static const struct isa_ext_data isa_edata_arr[] = { ISA_EXT_DATA_ENTRY(h, false, PRIV_VERSION_1_12_0, ext_h), - ISA_EXT_DATA_ENTRY(v, false, PRIV_VERSION_1_12_0, ext_v), + ISA_EXT_DATA_ENTRY(v, false, PRIV_VERSION_1_10_0, ext_v), ISA_EXT_DATA_ENTRY(zicsr, true, PRIV_VERSION_1_10_0, ext_icsr), ISA_EXT_DATA_ENTRY(zifencei, true, PRIV_VERSION_1_10_0, ext_ifencei), ISA_EXT_DATA_ENTRY(zihintpause, true, PRIV_VERSION_1_10_0, ext_zihintpause), diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c index ad8d82662c..3a9472a2ff 100644 --- a/target/riscv/cpu_helper.c +++ b/target/riscv/cpu_helper.c @@ -60,7 +60,7 @@ void cpu_get_tb_cpu_state(CPURISCVState *env, target_ulong *pc, * which is not supported by GVEC. So we set vl_eq_vlmax flag to true * only when maxsz >= 8 bytes. */ - uint32_t vlmax = vext_get_vlmax(env_archcpu(env), env->vtype); + uint32_t vlmax = vext_get_vlmax(cpu, env->vtype); uint32_t sew = FIELD_EX64(env->vtype, VTYPE, VSEW); uint32_t maxsz = vlmax << sew; bool vl_eq_vlmax = (env->vstart == 0) && (vlmax == env->vl) && diff --git a/target/riscv/csr.c b/target/riscv/csr.c index fa17d7770c..1b0a0c1693 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -3980,20 +3980,13 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = { [CSR_FRM] = { "frm", fs, read_frm, write_frm }, [CSR_FCSR] = { "fcsr", fs, read_fcsr, write_fcsr }, /* Vector CSRs */ - [CSR_VSTART] = { "vstart", vs, read_vstart, write_vstart, - .min_priv_ver = PRIV_VERSION_1_12_0 }, - [CSR_VXSAT] = { "vxsat", vs, read_vxsat, write_vxsat, - .min_priv_ver = PRIV_VERSION_1_12_0 }, - [CSR_VXRM] = { "vxrm", vs, read_vxrm, write_vxrm, - .min_priv_ver = PRIV_VERSION_1_12_0 }, - [CSR_VCSR] = { "vcsr", vs, read_vcsr, write_vcsr, - .min_priv_ver = PRIV_VERSION_1_12_0 }, - [CSR_VL] = { "vl", vs, read_vl, - .min_priv_ver = PRIV_VERSION_1_12_0 }, - [CSR_VTYPE] = { "vtype", vs, read_vtype, - .min_priv_ver = PRIV_VERSION_1_12_0 }, - [CSR_VLENB] = { "vlenb", vs, read_vlenb, - .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_VSTART] = { "vstart", vs, read_vstart, write_vstart }, + [CSR_VXSAT] = { "vxsat", vs, read_vxsat, write_vxsat }, + [CSR_VXRM] = { "vxrm", vs, read_vxrm, write_vxrm }, + [CSR_VCSR] = { "vcsr", vs, read_vcsr, write_vcsr }, + [CSR_VL] = { "vl", vs, read_vl }, + [CSR_VTYPE] = { "vtype", vs, read_vtype }, + [CSR_VLENB] = { "vlenb", vs, read_vlenb }, /* User Timers and Counters */ [CSR_CYCLE] = { "cycle", ctr, read_hpmcounter }, [CSR_INSTRET] = { "instret", ctr, read_hpmcounter }, diff --git a/target/riscv/pmp.c b/target/riscv/pmp.c index d1126a6066..4bc4113531 100644 --- a/target/riscv/pmp.c +++ b/target/riscv/pmp.c @@ -441,9 +441,12 @@ int pmp_hart_has_privs(CPURISCVState *env, target_ulong addr, } } - if ((privs & *allowed_privs) == privs) { - ret = i; - } + /* + * If matching address range was found, the protection bits + * defined with PMP must be used. We shouldn't fallback on + * finding default privileges. + */ + ret = i; break; } } diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index 00de879787..3073c54871 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -5038,7 +5038,7 @@ GEN_VEXT_VSLIDEDOWN_VX(vslidedown_vx_w, uint32_t, H4) GEN_VEXT_VSLIDEDOWN_VX(vslidedown_vx_d, uint64_t, H8) #define GEN_VEXT_VSLIE1UP(BITWIDTH, H) \ -static void vslide1up_##BITWIDTH(void *vd, void *v0, target_ulong s1, \ +static void vslide1up_##BITWIDTH(void *vd, void *v0, uint64_t s1, \ void *vs2, CPURISCVState *env, uint32_t desc) \ { \ typedef uint##BITWIDTH##_t ETYPE; \ @@ -5086,7 +5086,7 @@ GEN_VEXT_VSLIDE1UP_VX(vslide1up_vx_w, 32) GEN_VEXT_VSLIDE1UP_VX(vslide1up_vx_d, 64) #define GEN_VEXT_VSLIDE1DOWN(BITWIDTH, H) \ -static void vslide1down_##BITWIDTH(void *vd, void *v0, target_ulong s1, \ +static void vslide1down_##BITWIDTH(void *vd, void *v0, uint64_t s1, \ void *vs2, CPURISCVState *env, uint32_t desc) \ { \ typedef uint##BITWIDTH##_t ETYPE; \