diff options
-rw-r--r-- | disas/riscv.c | 65 | ||||
-rw-r--r-- | hw/riscv/Makefile.objs | 1 | ||||
-rw-r--r-- | hw/riscv/boot.c | 105 | ||||
-rw-r--r-- | hw/riscv/sifive_e.c | 30 | ||||
-rw-r--r-- | hw/riscv/sifive_prci.c | 49 | ||||
-rw-r--r-- | hw/riscv/sifive_u.c | 54 | ||||
-rw-r--r-- | hw/riscv/spike.c | 21 | ||||
-rw-r--r-- | hw/riscv/virt.c | 79 | ||||
-rw-r--r-- | include/hw/riscv/boot.h | 29 | ||||
-rw-r--r-- | include/hw/riscv/sifive_e.h | 2 | ||||
-rw-r--r-- | include/hw/riscv/sifive_prci.h | 32 | ||||
-rw-r--r-- | linux-user/riscv/syscall_nr.h | 15 | ||||
-rw-r--r-- | qemu-deprecated.texi | 8 | ||||
-rw-r--r-- | target/riscv/cpu.c | 137 | ||||
-rw-r--r-- | target/riscv/cpu.h | 33 | ||||
-rw-r--r-- | target/riscv/cpu_bits.h | 1 | ||||
-rw-r--r-- | target/riscv/cpu_helper.c | 55 | ||||
-rw-r--r-- | target/riscv/csr.c | 30 | ||||
-rw-r--r-- | target/riscv/insn_trans/trans_privileged.inc.c | 2 | ||||
-rw-r--r-- | target/riscv/insn_trans/trans_rva.inc.c | 8 | ||||
-rw-r--r-- | target/riscv/insn_trans/trans_rvi.inc.c | 4 | ||||
-rw-r--r-- | target/riscv/pmp.c | 17 | ||||
-rw-r--r-- | target/riscv/pmp.h | 2 | ||||
-rw-r--r-- | target/riscv/translate.c | 3 |
24 files changed, 583 insertions, 199 deletions
diff --git a/disas/riscv.c b/disas/riscv.c index 59a9b0437a..278d9be924 100644 --- a/disas/riscv.c +++ b/disas/riscv.c @@ -504,14 +504,19 @@ typedef struct { const rvc_constraint *constraints; } rv_comp_data; +enum { + rvcd_imm_nz = 0x1 +}; + typedef struct { const char * const name; const rv_codec codec; const char * const format; const rv_comp_data *pseudo; - const int decomp_rv32; - const int decomp_rv64; - const int decomp_rv128; + const short decomp_rv32; + const short decomp_rv64; + const short decomp_rv128; + const short decomp_data; } rv_opcode_data; /* register names */ @@ -609,7 +614,8 @@ static const rvc_constraint rvcc_rdtime[] = { rvc_rs1_eq_x0, rvc_csr_eq_0xc01, r static const rvc_constraint rvcc_rdinstret[] = { rvc_rs1_eq_x0, rvc_csr_eq_0xc02, rvc_end }; static const rvc_constraint rvcc_rdcycleh[] = { rvc_rs1_eq_x0, rvc_csr_eq_0xc80, rvc_end }; static const rvc_constraint rvcc_rdtimeh[] = { rvc_rs1_eq_x0, rvc_csr_eq_0xc81, rvc_end }; -static const rvc_constraint rvcc_rdinstreth[] = { rvc_rs1_eq_x0, rvc_csr_eq_0xc80, rvc_end }; +static const rvc_constraint rvcc_rdinstreth[] = { rvc_rs1_eq_x0, + rvc_csr_eq_0xc82, rvc_end }; static const rvc_constraint rvcc_frcsr[] = { rvc_rs1_eq_x0, rvc_csr_eq_0x003, rvc_end }; static const rvc_constraint rvcc_frrm[] = { rvc_rs1_eq_x0, rvc_csr_eq_0x002, rvc_end }; static const rvc_constraint rvcc_frflags[] = { rvc_rs1_eq_x0, rvc_csr_eq_0x001, rvc_end }; @@ -1011,7 +1017,8 @@ const rv_opcode_data opcode_data[] = { { "fcvt.q.lu", rv_codec_r_m, rv_fmt_rm_frd_rs1, NULL, 0, 0, 0 }, { "fmv.x.q", rv_codec_r, rv_fmt_rd_frs1, NULL, 0, 0, 0 }, { "fmv.q.x", rv_codec_r, rv_fmt_frd_rs1, NULL, 0, 0, 0 }, - { "c.addi4spn", rv_codec_ciw_4spn, rv_fmt_rd_rs1_imm, NULL, rv_op_addi, rv_op_addi, rv_op_addi }, + { "c.addi4spn", rv_codec_ciw_4spn, rv_fmt_rd_rs1_imm, NULL, rv_op_addi, + rv_op_addi, rv_op_addi, rvcd_imm_nz }, { "c.fld", rv_codec_cl_ld, rv_fmt_frd_offset_rs1, NULL, rv_op_fld, rv_op_fld, 0 }, { "c.lw", rv_codec_cl_lw, rv_fmt_rd_offset_rs1, NULL, rv_op_lw, rv_op_lw, rv_op_lw }, { "c.flw", rv_codec_cl_lw, rv_fmt_frd_offset_rs1, NULL, rv_op_flw, 0, 0 }, @@ -1019,14 +1026,20 @@ const rv_opcode_data opcode_data[] = { { "c.sw", rv_codec_cs_sw, rv_fmt_rs2_offset_rs1, NULL, rv_op_sw, rv_op_sw, rv_op_sw }, { "c.fsw", rv_codec_cs_sw, rv_fmt_frs2_offset_rs1, NULL, rv_op_fsw, 0, 0 }, { "c.nop", rv_codec_ci_none, rv_fmt_none, NULL, rv_op_addi, rv_op_addi, rv_op_addi }, - { "c.addi", rv_codec_ci, rv_fmt_rd_rs1_imm, NULL, rv_op_addi, rv_op_addi, rv_op_addi }, + { "c.addi", rv_codec_ci, rv_fmt_rd_rs1_imm, NULL, rv_op_addi, rv_op_addi, + rv_op_addi, rvcd_imm_nz }, { "c.jal", rv_codec_cj_jal, rv_fmt_rd_offset, NULL, rv_op_jal, 0, 0 }, { "c.li", rv_codec_ci_li, rv_fmt_rd_rs1_imm, NULL, rv_op_addi, rv_op_addi, rv_op_addi }, - { "c.addi16sp", rv_codec_ci_16sp, rv_fmt_rd_rs1_imm, NULL, rv_op_addi, rv_op_addi, rv_op_addi }, - { "c.lui", rv_codec_ci_lui, rv_fmt_rd_imm, NULL, rv_op_lui, rv_op_lui, rv_op_lui }, - { "c.srli", rv_codec_cb_sh6, rv_fmt_rd_rs1_imm, NULL, rv_op_srli, rv_op_srli, rv_op_srli }, - { "c.srai", rv_codec_cb_sh6, rv_fmt_rd_rs1_imm, NULL, rv_op_srai, rv_op_srai, rv_op_srai }, - { "c.andi", rv_codec_cb_imm, rv_fmt_rd_rs1_imm, NULL, rv_op_andi, rv_op_andi, rv_op_andi }, + { "c.addi16sp", rv_codec_ci_16sp, rv_fmt_rd_rs1_imm, NULL, rv_op_addi, + rv_op_addi, rv_op_addi, rvcd_imm_nz }, + { "c.lui", rv_codec_ci_lui, rv_fmt_rd_imm, NULL, rv_op_lui, rv_op_lui, + rv_op_lui, rvcd_imm_nz }, + { "c.srli", rv_codec_cb_sh6, rv_fmt_rd_rs1_imm, NULL, rv_op_srli, + rv_op_srli, rv_op_srli, rvcd_imm_nz }, + { "c.srai", rv_codec_cb_sh6, rv_fmt_rd_rs1_imm, NULL, rv_op_srai, + rv_op_srai, rv_op_srai, rvcd_imm_nz }, + { "c.andi", rv_codec_cb_imm, rv_fmt_rd_rs1_imm, NULL, rv_op_andi, + rv_op_andi, rv_op_andi }, { "c.sub", rv_codec_cs, rv_fmt_rd_rs1_rs2, NULL, rv_op_sub, rv_op_sub, rv_op_sub }, { "c.xor", rv_codec_cs, rv_fmt_rd_rs1_rs2, NULL, rv_op_xor, rv_op_xor, rv_op_xor }, { "c.or", rv_codec_cs, rv_fmt_rd_rs1_rs2, NULL, rv_op_or, rv_op_or, rv_op_or }, @@ -1036,7 +1049,8 @@ const rv_opcode_data opcode_data[] = { { "c.j", rv_codec_cj, rv_fmt_rd_offset, NULL, rv_op_jal, rv_op_jal, rv_op_jal }, { "c.beqz", rv_codec_cb, rv_fmt_rs1_rs2_offset, NULL, rv_op_beq, rv_op_beq, rv_op_beq }, { "c.bnez", rv_codec_cb, rv_fmt_rs1_rs2_offset, NULL, rv_op_bne, rv_op_bne, rv_op_bne }, - { "c.slli", rv_codec_ci_sh6, rv_fmt_rd_rs1_imm, NULL, rv_op_slli, rv_op_slli, rv_op_slli }, + { "c.slli", rv_codec_ci_sh6, rv_fmt_rd_rs1_imm, NULL, rv_op_slli, + rv_op_slli, rv_op_slli, rvcd_imm_nz }, { "c.fldsp", rv_codec_ci_ldsp, rv_fmt_frd_offset_rs1, NULL, rv_op_fld, rv_op_fld, rv_op_fld }, { "c.lwsp", rv_codec_ci_lwsp, rv_fmt_rd_offset_rs1, NULL, rv_op_lw, rv_op_lw, rv_op_lw }, { "c.flwsp", rv_codec_ci_lwsp, rv_fmt_frd_offset_rs1, NULL, rv_op_flw, 0, 0 }, @@ -2795,8 +2809,13 @@ static void decode_inst_decompress_rv32(rv_decode *dec) { int decomp_op = opcode_data[dec->op].decomp_rv32; if (decomp_op != rv_op_illegal) { - dec->op = decomp_op; - dec->codec = opcode_data[decomp_op].codec; + if ((opcode_data[dec->op].decomp_data & rvcd_imm_nz) + && dec->imm == 0) { + dec->op = rv_op_illegal; + } else { + dec->op = decomp_op; + dec->codec = opcode_data[decomp_op].codec; + } } } @@ -2804,8 +2823,13 @@ static void decode_inst_decompress_rv64(rv_decode *dec) { int decomp_op = opcode_data[dec->op].decomp_rv64; if (decomp_op != rv_op_illegal) { - dec->op = decomp_op; - dec->codec = opcode_data[decomp_op].codec; + if ((opcode_data[dec->op].decomp_data & rvcd_imm_nz) + && dec->imm == 0) { + dec->op = rv_op_illegal; + } else { + dec->op = decomp_op; + dec->codec = opcode_data[decomp_op].codec; + } } } @@ -2813,8 +2837,13 @@ static void decode_inst_decompress_rv128(rv_decode *dec) { int decomp_op = opcode_data[dec->op].decomp_rv128; if (decomp_op != rv_op_illegal) { - dec->op = decomp_op; - dec->codec = opcode_data[decomp_op].codec; + if ((opcode_data[dec->op].decomp_data & rvcd_imm_nz) + && dec->imm == 0) { + dec->op = rv_op_illegal; + } else { + dec->op = decomp_op; + dec->codec = opcode_data[decomp_op].codec; + } } } diff --git a/hw/riscv/Makefile.objs b/hw/riscv/Makefile.objs index a65027304a..eb9d4f9ffc 100644 --- a/hw/riscv/Makefile.objs +++ b/hw/riscv/Makefile.objs @@ -1,3 +1,4 @@ +obj-y += boot.o obj-$(CONFIG_SPIKE) += riscv_htif.o obj-$(CONFIG_HART) += riscv_hart.o obj-$(CONFIG_SIFIVE_E) += sifive_e.o diff --git a/hw/riscv/boot.c b/hw/riscv/boot.c new file mode 100644 index 0000000000..ff023f42d0 --- /dev/null +++ b/hw/riscv/boot.c @@ -0,0 +1,105 @@ +/* + * QEMU RISC-V Boot Helper + * + * Copyright (c) 2017 SiFive, Inc. + * Copyright (c) 2019 Alistair Francis <alistair.francis@wdc.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2 or later, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "qemu/osdep.h" +#include "qemu/units.h" +#include "qemu/error-report.h" +#include "exec/cpu-defs.h" +#include "hw/loader.h" +#include "hw/riscv/boot.h" +#include "hw/boards.h" +#include "elf.h" + +#if defined(TARGET_RISCV32) +# define KERNEL_BOOT_ADDRESS 0x80400000 +#else +# define KERNEL_BOOT_ADDRESS 0x80200000 +#endif + +target_ulong riscv_load_firmware(const char *firmware_filename, + hwaddr firmware_load_addr) +{ + uint64_t firmware_entry, firmware_start, firmware_end; + + if (load_elf(firmware_filename, NULL, NULL, NULL, &firmware_entry, + &firmware_start, &firmware_end, 0, EM_RISCV, 1, 0) > 0) { + return firmware_entry; + } + + if (load_image_targphys_as(firmware_filename, firmware_load_addr, + ram_size, NULL) > 0) { + return firmware_load_addr; + } + + error_report("could not load firmware '%s'", firmware_filename); + exit(1); +} + +target_ulong riscv_load_kernel(const char *kernel_filename) +{ + uint64_t kernel_entry, kernel_high; + + if (load_elf(kernel_filename, NULL, NULL, NULL, + &kernel_entry, NULL, &kernel_high, 0, EM_RISCV, 1, 0) > 0) { + return kernel_entry; + } + + 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_BOOT_ADDRESS, + ram_size, NULL) > 0) { + return KERNEL_BOOT_ADDRESS; + } + + error_report("could not load kernel '%s'", kernel_filename); + exit(1); +} + +hwaddr riscv_load_initrd(const char *filename, uint64_t mem_size, + uint64_t kernel_entry, hwaddr *start) +{ + int size; + + /* + * We want to put the initrd far enough into RAM that when the + * kernel is uncompressed it will not clobber the initrd. However + * on boards without much RAM we must ensure that we still leave + * enough room for a decent sized initrd, and on boards with large + * amounts of RAM we must avoid the initrd being so far up in RAM + * that it is outside lowmem and inaccessible to the kernel. + * So for boards with less than 256MB of RAM we put the initrd + * halfway into RAM, and for boards with 256MB of RAM or more we put + * the initrd at 128MB. + */ + *start = kernel_entry + MIN(mem_size / 2, 128 * MiB); + + size = load_ramdisk(filename, *start, mem_size - *start); + if (size == -1) { + size = load_image_targphys(filename, *start, mem_size - *start); + if (size == -1) { + error_report("could not load ramdisk '%s'", filename); + exit(1); + } + } + + return *start + size; +} diff --git a/hw/riscv/sifive_e.c b/hw/riscv/sifive_e.c index 80ac56fa7d..d27f626529 100644 --- a/hw/riscv/sifive_e.c +++ b/hw/riscv/sifive_e.c @@ -44,10 +44,10 @@ #include "hw/riscv/sifive_prci.h" #include "hw/riscv/sifive_uart.h" #include "hw/riscv/sifive_e.h" +#include "hw/riscv/boot.h" #include "chardev/char.h" #include "sysemu/arch_init.h" #include "exec/address-spaces.h" -#include "elf.h" static const struct MemmapEntry { hwaddr base; @@ -74,19 +74,6 @@ static const struct MemmapEntry { [SIFIVE_E_DTIM] = { 0x80000000, 0x4000 } }; -static target_ulong load_kernel(const char *kernel_filename) -{ - uint64_t kernel_entry, kernel_high; - - if (load_elf(kernel_filename, NULL, NULL, NULL, - &kernel_entry, NULL, &kernel_high, - 0, EM_RISCV, 1, 0) < 0) { - error_report("could not load kernel '%s'", kernel_filename); - exit(1); - } - return kernel_entry; -} - static void sifive_mmio_emulate(MemoryRegion *parent, const char *name, uintptr_t offset, uintptr_t length) { @@ -131,7 +118,7 @@ static void riscv_sifive_e_init(MachineState *machine) memmap[SIFIVE_E_MROM].base, &address_space_memory); if (machine->kernel_filename) { - load_kernel(machine->kernel_filename); + riscv_load_kernel(machine->kernel_filename); } } @@ -158,17 +145,15 @@ static void riscv_sifive_e_soc_realize(DeviceState *dev, Error **errp) SiFiveESoCState *s = RISCV_E_SOC(dev); MemoryRegion *sys_mem = get_system_memory(); - MemoryRegion *xip_mem = g_new(MemoryRegion, 1); - MemoryRegion *mask_rom = g_new(MemoryRegion, 1); object_property_set_bool(OBJECT(&s->cpus), true, "realized", &error_abort); /* Mask ROM */ - memory_region_init_rom(mask_rom, NULL, "riscv.sifive.e.mrom", + memory_region_init_rom(&s->mask_rom, NULL, "riscv.sifive.e.mrom", memmap[SIFIVE_E_MROM].size, &error_fatal); memory_region_add_subregion(sys_mem, - memmap[SIFIVE_E_MROM].base, mask_rom); + memmap[SIFIVE_E_MROM].base, &s->mask_rom); /* MMIO */ s->plic = sifive_plic_create(memmap[SIFIVE_E_PLIC].base, @@ -228,10 +213,11 @@ static void riscv_sifive_e_soc_realize(DeviceState *dev, Error **errp) memmap[SIFIVE_E_PWM2].base, memmap[SIFIVE_E_PWM2].size); /* Flash memory */ - memory_region_init_ram(xip_mem, NULL, "riscv.sifive.e.xip", + memory_region_init_ram(&s->xip_mem, NULL, "riscv.sifive.e.xip", memmap[SIFIVE_E_XIP].size, &error_fatal); - memory_region_set_readonly(xip_mem, true); - memory_region_add_subregion(sys_mem, memmap[SIFIVE_E_XIP].base, xip_mem); + memory_region_set_readonly(&s->xip_mem, true); + memory_region_add_subregion(sys_mem, memmap[SIFIVE_E_XIP].base, + &s->xip_mem); } static void riscv_sifive_e_machine_init(MachineClass *mc) diff --git a/hw/riscv/sifive_prci.c b/hw/riscv/sifive_prci.c index fa136b5a9f..f406682c91 100644 --- a/hw/riscv/sifive_prci.c +++ b/hw/riscv/sifive_prci.c @@ -24,15 +24,18 @@ #include "target/riscv/cpu.h" #include "hw/riscv/sifive_prci.h" -/* currently implements enough to mock freedom-e-sdk BSP clock programming */ - static uint64_t sifive_prci_read(void *opaque, hwaddr addr, unsigned int size) { - if (addr == 0 /* PRCI_HFROSCCFG */) { - return 1 << 31; /* ROSC_RDY */ - } - if (addr == 8 /* PRCI_PLLCFG */) { - return 1 << 31; /* PLL_LOCK */ + SiFivePRCIState *s = opaque; + switch (addr) { + case SIFIVE_PRCI_HFROSCCFG: + return s->hfrosccfg; + case SIFIVE_PRCI_HFXOSCCFG: + return s->hfxosccfg; + case SIFIVE_PRCI_PLLCFG: + return s->pllcfg; + case SIFIVE_PRCI_PLLOUTDIV: + return s->plloutdiv; } hw_error("%s: read: addr=0x%x\n", __func__, (int)addr); return 0; @@ -41,7 +44,30 @@ static uint64_t sifive_prci_read(void *opaque, hwaddr addr, unsigned int size) static void sifive_prci_write(void *opaque, hwaddr addr, uint64_t val64, unsigned int size) { - /* discard writes */ + SiFivePRCIState *s = opaque; + switch (addr) { + case SIFIVE_PRCI_HFROSCCFG: + s->hfrosccfg = (uint32_t) val64; + /* OSC stays ready */ + s->hfrosccfg |= SIFIVE_PRCI_HFROSCCFG_RDY; + break; + case SIFIVE_PRCI_HFXOSCCFG: + s->hfxosccfg = (uint32_t) val64; + /* OSC stays ready */ + s->hfxosccfg |= SIFIVE_PRCI_HFXOSCCFG_RDY; + break; + case SIFIVE_PRCI_PLLCFG: + s->pllcfg = (uint32_t) val64; + /* PLL stays locked */ + s->pllcfg |= SIFIVE_PRCI_PLLCFG_LOCK; + break; + case SIFIVE_PRCI_PLLOUTDIV: + s->plloutdiv = (uint32_t) val64; + break; + default: + hw_error("%s: bad write: addr=0x%x v=0x%x\n", + __func__, (int)addr, (int)val64); + } } static const MemoryRegionOps sifive_prci_ops = { @@ -61,6 +87,13 @@ static void sifive_prci_init(Object *obj) memory_region_init_io(&s->mmio, obj, &sifive_prci_ops, s, TYPE_SIFIVE_PRCI, 0x8000); sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio); + + s->hfrosccfg = (SIFIVE_PRCI_HFROSCCFG_RDY | SIFIVE_PRCI_HFROSCCFG_EN); + s->hfxosccfg = (SIFIVE_PRCI_HFROSCCFG_RDY | SIFIVE_PRCI_HFROSCCFG_EN); + s->pllcfg = (SIFIVE_PRCI_PLLCFG_REFSEL | SIFIVE_PRCI_PLLCFG_BYPASS | + SIFIVE_PRCI_PLLCFG_LOCK); + s->plloutdiv = SIFIVE_PRCI_PLLOUTDIV_DIV1; + } static const TypeInfo sifive_prci_info = { diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c index 5ecc47cea3..4208671552 100644 --- a/hw/riscv/sifive_u.c +++ b/hw/riscv/sifive_u.c @@ -41,11 +41,11 @@ #include "hw/riscv/sifive_uart.h" #include "hw/riscv/sifive_prci.h" #include "hw/riscv/sifive_u.h" +#include "hw/riscv/boot.h" #include "chardev/char.h" #include "sysemu/arch_init.h" #include "sysemu/device_tree.h" #include "exec/address-spaces.h" -#include "elf.h" #include <libfdt.h> @@ -65,19 +65,6 @@ static const struct MemmapEntry { #define GEM_REVISION 0x10070109 -static target_ulong load_kernel(const char *kernel_filename) -{ - uint64_t kernel_entry, kernel_high; - - if (load_elf(kernel_filename, NULL, NULL, NULL, - &kernel_entry, NULL, &kernel_high, - 0, EM_RISCV, 1, 0) < 0) { - error_report("could not load kernel '%s'", kernel_filename); - exit(1); - } - return kernel_entry; -} - static void create_fdt(SiFiveUState *s, const struct MemmapEntry *memmap, uint64_t mem_size, const char *cmdline) { @@ -86,7 +73,7 @@ static void create_fdt(SiFiveUState *s, const struct MemmapEntry *memmap, uint32_t *cells; char *nodename; char ethclk_names[] = "pclk\0hclk\0tx_clk"; - uint32_t plic_phandle, ethclk_phandle; + uint32_t plic_phandle, ethclk_phandle, phandle = 1; fdt = s->fdt = create_device_tree(&s->fdt_size); if (!fdt) { @@ -121,6 +108,7 @@ static void create_fdt(SiFiveUState *s, const struct MemmapEntry *memmap, qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 0x1); for (cpu = s->soc.cpus.num_harts - 1; cpu >= 0; cpu--) { + int cpu_phandle = phandle++; nodename = g_strdup_printf("/cpus/cpu@%d", cpu); char *intc = g_strdup_printf("/cpus/cpu@%d/interrupt-controller", cpu); char *isa = riscv_isa_string(&s->soc.cpus.harts[cpu]); @@ -134,8 +122,8 @@ static void create_fdt(SiFiveUState *s, const struct MemmapEntry *memmap, qemu_fdt_setprop_cell(fdt, nodename, "reg", cpu); qemu_fdt_setprop_string(fdt, nodename, "device_type", "cpu"); qemu_fdt_add_subnode(fdt, intc); - qemu_fdt_setprop_cell(fdt, intc, "phandle", 1); - qemu_fdt_setprop_cell(fdt, intc, "linux,phandle", 1); + qemu_fdt_setprop_cell(fdt, intc, "phandle", cpu_phandle); + qemu_fdt_setprop_cell(fdt, intc, "linux,phandle", cpu_phandle); qemu_fdt_setprop_string(fdt, intc, "compatible", "riscv,cpu-intc"); qemu_fdt_setprop(fdt, intc, "interrupt-controller", NULL, 0); qemu_fdt_setprop_cell(fdt, intc, "#interrupt-cells", 1); @@ -167,6 +155,7 @@ static void create_fdt(SiFiveUState *s, const struct MemmapEntry *memmap, g_free(cells); g_free(nodename); + plic_phandle = phandle++; cells = g_new0(uint32_t, s->soc.cpus.num_harts * 4); for (cpu = 0; cpu < s->soc.cpus.num_harts; cpu++) { nodename = @@ -192,20 +181,21 @@ static void create_fdt(SiFiveUState *s, const struct MemmapEntry *memmap, qemu_fdt_setprop_string(fdt, nodename, "reg-names", "control"); qemu_fdt_setprop_cell(fdt, nodename, "riscv,max-priority", 7); qemu_fdt_setprop_cell(fdt, nodename, "riscv,ndev", 0x35); - qemu_fdt_setprop_cells(fdt, nodename, "phandle", 2); - qemu_fdt_setprop_cells(fdt, nodename, "linux,phandle", 2); + qemu_fdt_setprop_cells(fdt, nodename, "phandle", plic_phandle); + qemu_fdt_setprop_cells(fdt, nodename, "linux,phandle", plic_phandle); plic_phandle = qemu_fdt_get_phandle(fdt, nodename); g_free(cells); g_free(nodename); + ethclk_phandle = phandle++; nodename = g_strdup_printf("/soc/ethclk"); qemu_fdt_add_subnode(fdt, nodename); qemu_fdt_setprop_string(fdt, nodename, "compatible", "fixed-clock"); qemu_fdt_setprop_cell(fdt, nodename, "#clock-cells", 0x0); qemu_fdt_setprop_cell(fdt, nodename, "clock-frequency", SIFIVE_U_GEM_CLOCK_FREQ); - qemu_fdt_setprop_cell(fdt, nodename, "phandle", 3); - qemu_fdt_setprop_cell(fdt, nodename, "linux,phandle", 3); + qemu_fdt_setprop_cell(fdt, nodename, "phandle", ethclk_phandle); + qemu_fdt_setprop_cell(fdt, nodename, "linux,phandle", ethclk_phandle); ethclk_phandle = qemu_fdt_get_phandle(fdt, nodename); g_free(nodename); @@ -279,8 +269,12 @@ static void riscv_sifive_u_init(MachineState *machine) /* create device tree */ create_fdt(s, memmap, machine->ram_size, machine->kernel_cmdline); + if (machine->firmware) { + riscv_load_firmware(machine->firmware, memmap[SIFIVE_U_DRAM].base); + } + if (machine->kernel_filename) { - load_kernel(machine->kernel_filename); + riscv_load_kernel(machine->kernel_filename); } /* reset vector */ @@ -341,6 +335,8 @@ static void riscv_sifive_u_soc_realize(DeviceState *dev, Error **errp) MemoryRegion *system_memory = get_system_memory(); MemoryRegion *mask_rom = g_new(MemoryRegion, 1); qemu_irq plic_gpios[SIFIVE_U_PLIC_NUM_SOURCES]; + char *plic_hart_config; + size_t plic_hart_config_len; int i; Error *err = NULL; NICInfo *nd = &nd_table[0]; @@ -354,9 +350,21 @@ static void riscv_sifive_u_soc_realize(DeviceState *dev, Error **errp) memory_region_add_subregion(system_memory, memmap[SIFIVE_U_MROM].base, mask_rom); + /* create PLIC hart topology configuration string */ + plic_hart_config_len = (strlen(SIFIVE_U_PLIC_HART_CONFIG) + 1) * smp_cpus; + plic_hart_config = g_malloc0(plic_hart_config_len); + for (i = 0; i < smp_cpus; i++) { + if (i != 0) { + strncat(plic_hart_config, ",", plic_hart_config_len); + } + strncat(plic_hart_config, SIFIVE_U_PLIC_HART_CONFIG, + plic_hart_config_len); + plic_hart_config_len -= (strlen(SIFIVE_U_PLIC_HART_CONFIG) + 1); + } + /* MMIO */ s->plic = sifive_plic_create(memmap[SIFIVE_U_PLIC].base, - (char *)SIFIVE_U_PLIC_HART_CONFIG, + plic_hart_config, SIFIVE_U_PLIC_NUM_SOURCES, SIFIVE_U_PLIC_NUM_PRIORITIES, SIFIVE_U_PLIC_PRIORITY_BASE, diff --git a/hw/riscv/spike.c b/hw/riscv/spike.c index 5b33d4be3b..e68be00a5f 100644 --- a/hw/riscv/spike.c +++ b/hw/riscv/spike.c @@ -36,12 +36,12 @@ #include "hw/riscv/riscv_hart.h" #include "hw/riscv/sifive_clint.h" #include "hw/riscv/spike.h" +#include "hw/riscv/boot.h" #include "chardev/char.h" #include "sysemu/arch_init.h" #include "sysemu/device_tree.h" #include "sysemu/qtest.h" #include "exec/address-spaces.h" -#include "elf.h" #include <libfdt.h> @@ -54,19 +54,6 @@ static const struct MemmapEntry { [SPIKE_DRAM] = { 0x80000000, 0x0 }, }; -static target_ulong load_kernel(const char *kernel_filename) -{ - uint64_t kernel_entry, kernel_high; - - if (load_elf_ram_sym(kernel_filename, NULL, NULL, NULL, - &kernel_entry, NULL, &kernel_high, 0, EM_RISCV, 1, 0, - NULL, true, htif_symbol_callback) < 0) { - error_report("could not load kernel '%s'", kernel_filename); - exit(1); - } - return kernel_entry; -} - static void create_fdt(SpikeState *s, const struct MemmapEntry *memmap, uint64_t mem_size, const char *cmdline) { @@ -199,7 +186,7 @@ static void spike_board_init(MachineState *machine) mask_rom); if (machine->kernel_filename) { - load_kernel(machine->kernel_filename); + riscv_load_kernel(machine->kernel_filename); } /* reset vector */ @@ -287,7 +274,7 @@ static void spike_v1_10_0_board_init(MachineState *machine) mask_rom); if (machine->kernel_filename) { - load_kernel(machine->kernel_filename); + riscv_load_kernel(machine->kernel_filename); } /* reset vector */ @@ -372,7 +359,7 @@ static void spike_v1_09_1_board_init(MachineState *machine) mask_rom); if (machine->kernel_filename) { - load_kernel(machine->kernel_filename); + riscv_load_kernel(machine->kernel_filename); } /* reset vector */ diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index 84d94d0c42..d8181a4ff1 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -34,13 +34,13 @@ #include "hw/riscv/sifive_clint.h" #include "hw/riscv/sifive_test.h" #include "hw/riscv/virt.h" +#include "hw/riscv/boot.h" #include "chardev/char.h" #include "sysemu/arch_init.h" #include "sysemu/device_tree.h" #include "exec/address-spaces.h" #include "hw/pci/pci.h" #include "hw/pci-host/gpex.h" -#include "elf.h" #include <libfdt.h> @@ -61,47 +61,6 @@ static const struct MemmapEntry { [VIRT_PCIE_ECAM] = { 0x30000000, 0x10000000 }, }; -static target_ulong load_kernel(const char *kernel_filename) -{ - uint64_t kernel_entry, kernel_high; - - if (load_elf(kernel_filename, NULL, NULL, NULL, - &kernel_entry, NULL, &kernel_high, - 0, EM_RISCV, 1, 0) < 0) { - error_report("could not load kernel '%s'", kernel_filename); - exit(1); - } - return kernel_entry; -} - -static hwaddr load_initrd(const char *filename, uint64_t mem_size, - uint64_t kernel_entry, hwaddr *start) -{ - int size; - - /* We want to put the initrd far enough into RAM that when the - * kernel is uncompressed it will not clobber the initrd. However - * on boards without much RAM we must ensure that we still leave - * enough room for a decent sized initrd, and on boards with large - * amounts of RAM we must avoid the initrd being so far up in RAM - * that it is outside lowmem and inaccessible to the kernel. - * So for boards with less than 256MB of RAM we put the initrd - * halfway into RAM, and for boards with 256MB of RAM or more we put - * the initrd at 128MB. - */ - *start = kernel_entry + MIN(mem_size / 2, 128 * MiB); - - size = load_ramdisk(filename, *start, mem_size - *start); - if (size == -1) { - size = load_image_targphys(filename, *start, mem_size - *start); - if (size == -1) { - error_report("could not load ramdisk '%s'", filename); - exit(1); - } - } - return *start + size; -} - static void create_pcie_irq_map(void *fdt, char *nodename, uint32_t plic_phandle) { @@ -191,6 +150,7 @@ static void *create_fdt(RISCVVirtState *s, const struct MemmapEntry *memmap, for (cpu = s->soc.num_harts - 1; cpu >= 0; cpu--) { int cpu_phandle = phandle++; + int intc_phandle; nodename = g_strdup_printf("/cpus/cpu@%d", cpu); char *intc = g_strdup_printf("/cpus/cpu@%d/interrupt-controller", cpu); char *isa = riscv_isa_string(&s->soc.harts[cpu]); @@ -203,9 +163,12 @@ static void *create_fdt(RISCVVirtState *s, const struct MemmapEntry *memmap, qemu_fdt_setprop_string(fdt, nodename, "status", "okay"); qemu_fdt_setprop_cell(fdt, nodename, "reg", cpu); qemu_fdt_setprop_string(fdt, nodename, "device_type", "cpu"); + qemu_fdt_setprop_cell(fdt, nodename, "phandle", cpu_phandle); + qemu_fdt_setprop_cell(fdt, nodename, "linux,phandle", cpu_phandle); + intc_phandle = phandle++; qemu_fdt_add_subnode(fdt, intc); - qemu_fdt_setprop_cell(fdt, intc, "phandle", cpu_phandle); - qemu_fdt_setprop_cell(fdt, intc, "linux,phandle", cpu_phandle); + qemu_fdt_setprop_cell(fdt, intc, "phandle", intc_phandle); + qemu_fdt_setprop_cell(fdt, intc, "linux,phandle", intc_phandle); qemu_fdt_setprop_string(fdt, intc, "compatible", "riscv,cpu-intc"); qemu_fdt_setprop(fdt, intc, "interrupt-controller", NULL, 0); qemu_fdt_setprop_cell(fdt, intc, "#interrupt-cells", 1); @@ -214,6 +177,20 @@ static void *create_fdt(RISCVVirtState *s, const struct MemmapEntry *memmap, g_free(nodename); } + /* Add cpu-topology node */ + qemu_fdt_add_subnode(fdt, "/cpus/cpu-map"); + qemu_fdt_add_subnode(fdt, "/cpus/cpu-map/cluster0"); + for (cpu = s->soc.num_harts - 1; cpu >= 0; cpu--) { + char *core_nodename = g_strdup_printf("/cpus/cpu-map/cluster0/core%d", + cpu); + char *cpu_nodename = g_strdup_printf("/cpus/cpu@%d", cpu); + uint32_t intc_phandle = qemu_fdt_get_phandle(fdt, cpu_nodename); + qemu_fdt_add_subnode(fdt, core_nodename); + qemu_fdt_setprop_cell(fdt, core_nodename, "cpu", intc_phandle); + g_free(core_nodename); + g_free(cpu_nodename); + } + cells = g_new0(uint32_t, s->soc.num_harts * 4); for (cpu = 0; cpu < s->soc.num_harts; cpu++) { nodename = @@ -298,7 +275,7 @@ static void *create_fdt(RISCVVirtState *s, const struct MemmapEntry *memmap, qemu_fdt_setprop_string(fdt, nodename, "device_type", "pci"); qemu_fdt_setprop_cell(fdt, nodename, "linux,pci-domain", 0); qemu_fdt_setprop_cells(fdt, nodename, "bus-range", 0, - memmap[VIRT_PCIE_ECAM].base / + memmap[VIRT_PCIE_ECAM].size / PCIE_MMCFG_SIZE_MIN - 1); qemu_fdt_setprop(fdt, nodename, "dma-coherent", NULL, 0); qemu_fdt_setprop_cells(fdt, nodename, "reg", 0, memmap[VIRT_PCIE_ECAM].base, @@ -421,14 +398,18 @@ static void riscv_virt_board_init(MachineState *machine) memory_region_add_subregion(system_memory, memmap[VIRT_MROM].base, mask_rom); + if (machine->firmware) { + riscv_load_firmware(machine->firmware, memmap[VIRT_DRAM].base); + } + if (machine->kernel_filename) { - uint64_t kernel_entry = load_kernel(machine->kernel_filename); + uint64_t kernel_entry = riscv_load_kernel(machine->kernel_filename); if (machine->initrd_filename) { hwaddr start; - hwaddr end = load_initrd(machine->initrd_filename, - machine->ram_size, kernel_entry, - &start); + hwaddr end = riscv_load_initrd(machine->initrd_filename, + machine->ram_size, kernel_entry, + &start); qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-start", start); qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-end", diff --git a/include/hw/riscv/boot.h b/include/hw/riscv/boot.h new file mode 100644 index 0000000000..daa179b600 --- /dev/null +++ b/include/hw/riscv/boot.h @@ -0,0 +1,29 @@ +/* + * QEMU RISC-V Boot Helper + * + * Copyright (c) 2017 SiFive, Inc. + * Copyright (c) 2019 Alistair Francis <alistair.francis@wdc.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2 or later, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef RISCV_BOOT_H +#define RISCV_BOOT_H + +target_ulong riscv_load_firmware(const char *firmware_filename, + hwaddr firmware_load_addr); +target_ulong riscv_load_kernel(const char *kernel_filename); +hwaddr riscv_load_initrd(const char *filename, uint64_t mem_size, + uint64_t kernel_entry, hwaddr *start); + +#endif /* RISCV_BOOT_H */ diff --git a/include/hw/riscv/sifive_e.h b/include/hw/riscv/sifive_e.h index 3b14eb7462..d175b24cb2 100644 --- a/include/hw/riscv/sifive_e.h +++ b/include/hw/riscv/sifive_e.h @@ -33,6 +33,8 @@ typedef struct SiFiveESoCState { RISCVHartArrayState cpus; DeviceState *plic; SIFIVEGPIOState gpio; + MemoryRegion xip_mem; + MemoryRegion mask_rom; } SiFiveESoCState; typedef struct SiFiveEState { diff --git a/include/hw/riscv/sifive_prci.h b/include/hw/riscv/sifive_prci.h index b6f4c486cc..bd51c4af3c 100644 --- a/include/hw/riscv/sifive_prci.h +++ b/include/hw/riscv/sifive_prci.h @@ -19,6 +19,34 @@ #ifndef HW_SIFIVE_PRCI_H #define HW_SIFIVE_PRCI_H +enum { + SIFIVE_PRCI_HFROSCCFG = 0x0, + SIFIVE_PRCI_HFXOSCCFG = 0x4, + SIFIVE_PRCI_PLLCFG = 0x8, + SIFIVE_PRCI_PLLOUTDIV = 0xC +}; + +enum { + SIFIVE_PRCI_HFROSCCFG_RDY = (1 << 31), + SIFIVE_PRCI_HFROSCCFG_EN = (1 << 30) +}; + +enum { + SIFIVE_PRCI_HFXOSCCFG_RDY = (1 << 31), + SIFIVE_PRCI_HFXOSCCFG_EN = (1 << 30) +}; + +enum { + SIFIVE_PRCI_PLLCFG_PLLSEL = (1 << 16), + SIFIVE_PRCI_PLLCFG_REFSEL = (1 << 17), + SIFIVE_PRCI_PLLCFG_BYPASS = (1 << 18), + SIFIVE_PRCI_PLLCFG_LOCK = (1 << 31) +}; + +enum { + SIFIVE_PRCI_PLLOUTDIV_DIV1 = (1 << 8) +}; + #define TYPE_SIFIVE_PRCI "riscv.sifive.prci" #define SIFIVE_PRCI(obj) \ @@ -30,6 +58,10 @@ typedef struct SiFivePRCIState { /*< public >*/ MemoryRegion mmio; + uint32_t hfrosccfg; + uint32_t hfxosccfg; + uint32_t pllcfg; + uint32_t plloutdiv; } SiFivePRCIState; DeviceState *sifive_prci_create(hwaddr addr); diff --git a/linux-user/riscv/syscall_nr.h b/linux-user/riscv/syscall_nr.h index dab6509e3a..5c87282209 100644 --- a/linux-user/riscv/syscall_nr.h +++ b/linux-user/riscv/syscall_nr.h @@ -72,7 +72,11 @@ #define TARGET_NR_pipe2 59 #define TARGET_NR_quotactl 60 #define TARGET_NR_getdents64 61 +#ifdef TARGET_RISCV32 +#define TARGET_NR__llseek 62 +#else #define TARGET_NR_lseek 62 +#endif #define TARGET_NR_read 63 #define TARGET_NR_write 64 #define TARGET_NR_readv 65 @@ -286,7 +290,16 @@ #define TARGET_NR_membarrier 283 #define TARGET_NR_mlock2 284 #define TARGET_NR_copy_file_range 285 +#define TARGET_NR_preadv2 286 +#define TARGET_NR_pwritev2 287 +#define TARGET_NR_pkey_mprotect 288 +#define TARGET_NR_pkey_alloc 289 +#define TARGET_NR_pkey_free 290 +#define TARGET_NR_statx 291 +#define TARGET_NR_io_pgetevents 292 +#define TARGET_NR_rseq 293 +#define TARGET_NR_kexec_file_load 294 -#define TARGET_NR_syscalls (TARGET_NR_copy_file_range + 1) +#define TARGET_NR_syscalls (TARGET_NR_kexec_file_load + 1) #endif diff --git a/qemu-deprecated.texi b/qemu-deprecated.texi index df04f2840b..97ea4ef300 100644 --- a/qemu-deprecated.texi +++ b/qemu-deprecated.texi @@ -144,6 +144,14 @@ The ``acl_show'', ``acl_reset'', ``acl_policy'', ``acl_add'', and ``acl_remove'' commands are deprecated with no replacement. Authorization for VNC should be performed using the pluggable QAuthZ objects. +@section Guest Emulator ISAs + +@subsection RISC-V ISA privledge specification version 1.09.1 (since 4.1) + +The RISC-V ISA privledge specification version 1.09.1 has been deprecated. +QEMU supports both the newer version 1.10.0 and the ratified version 1.11.0, these +should be used instead of the 1.09.1 version. + @section System emulator CPUS @subsection RISC-V ISA CPUs (since 4.1) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 6f2b644220..f8d07bd20a 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -24,6 +24,7 @@ #include "cpu.h" #include "exec/exec-all.h" #include "qapi/error.h" +#include "qemu/error-report.h" #include "hw/qdev-properties.h" #include "migration/vmstate.h" @@ -88,9 +89,8 @@ static void set_misa(CPURISCVState *env, target_ulong misa) env->misa_mask = env->misa = misa; } -static void set_versions(CPURISCVState *env, int user_ver, int priv_ver) +static void set_priv_version(CPURISCVState *env, int priv_ver) { - env->user_ver = user_ver; env->priv_ver = priv_ver; } @@ -110,7 +110,7 @@ static void riscv_any_cpu_init(Object *obj) { CPURISCVState *env = &RISCV_CPU(obj)->env; set_misa(env, RVXLEN | RVI | RVM | RVA | RVF | RVD | RVC | RVU); - set_versions(env, USER_VERSION_2_02_0, PRIV_VERSION_1_10_0); + set_priv_version(env, PRIV_VERSION_1_11_0); set_resetvec(env, DEFAULT_RSTVEC); } @@ -119,14 +119,15 @@ static void riscv_any_cpu_init(Object *obj) static void riscv_base32_cpu_init(Object *obj) { CPURISCVState *env = &RISCV_CPU(obj)->env; - set_misa(env, RV32 | RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU); + /* We set this in the realise function */ + set_misa(env, 0); } static void rv32gcsu_priv1_09_1_cpu_init(Object *obj) { CPURISCVState *env = &RISCV_CPU(obj)->env; set_misa(env, RV32 | RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU); - set_versions(env, USER_VERSION_2_02_0, PRIV_VERSION_1_09_1); + set_priv_version(env, PRIV_VERSION_1_09_1); set_resetvec(env, DEFAULT_RSTVEC); set_feature(env, RISCV_FEATURE_MMU); set_feature(env, RISCV_FEATURE_PMP); @@ -136,7 +137,7 @@ static void rv32gcsu_priv1_10_0_cpu_init(Object *obj) { CPURISCVState *env = &RISCV_CPU(obj)->env; set_misa(env, RV32 | RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU); - set_versions(env, USER_VERSION_2_02_0, PRIV_VERSION_1_10_0); + set_priv_version(env, PRIV_VERSION_1_10_0); set_resetvec(env, DEFAULT_RSTVEC); set_feature(env, RISCV_FEATURE_MMU); set_feature(env, RISCV_FEATURE_PMP); @@ -146,7 +147,7 @@ static void rv32imacu_nommu_cpu_init(Object *obj) { CPURISCVState *env = &RISCV_CPU(obj)->env; set_misa(env, RV32 | RVI | RVM | RVA | RVC | RVU); - set_versions(env, USER_VERSION_2_02_0, PRIV_VERSION_1_10_0); + set_priv_version(env, PRIV_VERSION_1_10_0); set_resetvec(env, DEFAULT_RSTVEC); set_feature(env, RISCV_FEATURE_PMP); } @@ -156,14 +157,15 @@ static void rv32imacu_nommu_cpu_init(Object *obj) static void riscv_base64_cpu_init(Object *obj) { CPURISCVState *env = &RISCV_CPU(obj)->env; - set_misa(env, RV64 | RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU); + /* We set this in the realise function */ + set_misa(env, 0); } static void rv64gcsu_priv1_09_1_cpu_init(Object *obj) { CPURISCVState *env = &RISCV_CPU(obj)->env; set_misa(env, RV64 | RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU); - set_versions(env, USER_VERSION_2_02_0, PRIV_VERSION_1_09_1); + set_priv_version(env, PRIV_VERSION_1_09_1); set_resetvec(env, DEFAULT_RSTVEC); set_feature(env, RISCV_FEATURE_MMU); set_feature(env, RISCV_FEATURE_PMP); @@ -173,7 +175,7 @@ static void rv64gcsu_priv1_10_0_cpu_init(Object *obj) { CPURISCVState *env = &RISCV_CPU(obj)->env; set_misa(env, RV64 | RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU); - set_versions(env, USER_VERSION_2_02_0, PRIV_VERSION_1_10_0); + set_priv_version(env, PRIV_VERSION_1_10_0); set_resetvec(env, DEFAULT_RSTVEC); set_feature(env, RISCV_FEATURE_MMU); set_feature(env, RISCV_FEATURE_PMP); @@ -183,7 +185,7 @@ static void rv64imacu_nommu_cpu_init(Object *obj) { CPURISCVState *env = &RISCV_CPU(obj)->env; set_misa(env, RV64 | RVI | RVM | RVA | RVC | RVU); - set_versions(env, USER_VERSION_2_02_0, PRIV_VERSION_1_10_0); + set_priv_version(env, PRIV_VERSION_1_10_0); set_resetvec(env, DEFAULT_RSTVEC); set_feature(env, RISCV_FEATURE_PMP); } @@ -295,6 +297,7 @@ static void riscv_cpu_reset(CPUState *cs) env->pc = env->resetvec; #endif cs->exception_index = EXCP_NONE; + env->load_res = -1; set_default_nan_mode(1, &env->fp_status); } @@ -313,8 +316,8 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp) RISCVCPU *cpu = RISCV_CPU(dev); CPURISCVState *env = &cpu->env; RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(dev); - int priv_version = PRIV_VERSION_1_10_0; - int user_version = USER_VERSION_2_02_0; + int priv_version = PRIV_VERSION_1_11_0; + target_ulong target_misa = 0; Error *local_err = NULL; cpu_exec_realizefn(cs, &local_err); @@ -324,7 +327,9 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp) } if (cpu->cfg.priv_spec) { - if (!g_strcmp0(cpu->cfg.priv_spec, "v1.10.0")) { + if (!g_strcmp0(cpu->cfg.priv_spec, "v1.11.0")) { + priv_version = PRIV_VERSION_1_11_0; + } else if (!g_strcmp0(cpu->cfg.priv_spec, "v1.10.0")) { priv_version = PRIV_VERSION_1_10_0; } else if (!g_strcmp0(cpu->cfg.priv_spec, "v1.9.1")) { priv_version = PRIV_VERSION_1_09_1; @@ -336,18 +341,7 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp) } } - if (cpu->cfg.user_spec) { - if (!g_strcmp0(cpu->cfg.user_spec, "v2.02.0")) { - user_version = USER_VERSION_2_02_0; - } else { - error_setg(errp, - "Unsupported user spec version '%s'", - cpu->cfg.user_spec); - return; - } - } - - set_versions(env, user_version, priv_version); + set_priv_version(env, priv_version); set_resetvec(env, DEFAULT_RSTVEC); if (cpu->cfg.mmu) { @@ -358,6 +352,64 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp) set_feature(env, RISCV_FEATURE_PMP); } + /* If misa isn't set (rv32 and rv64 machines) set it here */ + if (!env->misa) { + /* Do some ISA extension error checking */ + if (cpu->cfg.ext_i && cpu->cfg.ext_e) { + error_setg(errp, + "I and E extensions are incompatible"); + return; + } + + if (!cpu->cfg.ext_i && !cpu->cfg.ext_e) { + error_setg(errp, + "Either I or E extension must be set"); + return; + } + + if (cpu->cfg.ext_g && !(cpu->cfg.ext_i & cpu->cfg.ext_m & + cpu->cfg.ext_a & cpu->cfg.ext_f & + cpu->cfg.ext_d)) { + warn_report("Setting G will also set IMAFD"); + cpu->cfg.ext_i = true; + cpu->cfg.ext_m = true; + cpu->cfg.ext_a = true; + cpu->cfg.ext_f = true; + cpu->cfg.ext_d = true; + } + + /* Set the ISA extensions, checks should have happened above */ + if (cpu->cfg.ext_i) { + target_misa |= RVI; + } + if (cpu->cfg.ext_e) { + target_misa |= RVE; + } + if (cpu->cfg.ext_m) { + target_misa |= RVM; + } + if (cpu->cfg.ext_a) { + target_misa |= RVA; + } + if (cpu->cfg.ext_f) { + target_misa |= RVF; + } + if (cpu->cfg.ext_d) { + target_misa |= RVD; + } + if (cpu->cfg.ext_c) { + target_misa |= RVC; + } + if (cpu->cfg.ext_s) { + target_misa |= RVS; + } + if (cpu->cfg.ext_u) { + target_misa |= RVU; + } + + set_misa(env, RVXLEN | target_misa); + } + riscv_cpu_register_gdb_regs_for_features(cs); qemu_init_vcpu(cs); @@ -379,8 +431,20 @@ static const VMStateDescription vmstate_riscv_cpu = { }; static Property riscv_cpu_properties[] = { + DEFINE_PROP_BOOL("i", RISCVCPU, cfg.ext_i, true), + DEFINE_PROP_BOOL("e", RISCVCPU, cfg.ext_e, false), + DEFINE_PROP_BOOL("g", RISCVCPU, cfg.ext_g, true), + DEFINE_PROP_BOOL("m", RISCVCPU, cfg.ext_m, true), + DEFINE_PROP_BOOL("a", RISCVCPU, cfg.ext_a, true), + DEFINE_PROP_BOOL("f", RISCVCPU, cfg.ext_f, true), + DEFINE_PROP_BOOL("d", RISCVCPU, cfg.ext_d, true), + DEFINE_PROP_BOOL("c", RISCVCPU, cfg.ext_c, true), + DEFINE_PROP_BOOL("s", RISCVCPU, cfg.ext_s, true), + DEFINE_PROP_BOOL("u", RISCVCPU, cfg.ext_u, true), + DEFINE_PROP_BOOL("Counters", RISCVCPU, cfg.ext_counters, true), + DEFINE_PROP_BOOL("Zifencei", RISCVCPU, cfg.ext_ifencei, true), + DEFINE_PROP_BOOL("Zicsr", RISCVCPU, cfg.ext_icsr, true), DEFINE_PROP_STRING("priv_spec", RISCVCPU, cfg.priv_spec), - DEFINE_PROP_STRING("user_spec", RISCVCPU, cfg.user_spec), DEFINE_PROP_BOOL("mmu", RISCVCPU, cfg.mmu, true), DEFINE_PROP_BOOL("pmp", RISCVCPU, cfg.pmp, true), DEFINE_PROP_END_OF_LIST(), @@ -416,6 +480,7 @@ static void riscv_cpu_class_init(ObjectClass *c, void *data) cc->gdb_stop_before_watchpoint = true; cc->disas_set_info = riscv_cpu_disas_set_info; #ifndef CONFIG_USER_ONLY + cc->do_unassigned_access = riscv_cpu_unassigned_access; cc->do_unaligned_access = riscv_cpu_do_unaligned_access; cc->get_phys_page_debug = riscv_cpu_get_phys_page_debug; #endif @@ -492,18 +557,20 @@ static const TypeInfo riscv_cpu_type_infos[] = { DEFINE_CPU(TYPE_RISCV_CPU_ANY, riscv_any_cpu_init), #if defined(TARGET_RISCV32) DEFINE_CPU(TYPE_RISCV_CPU_BASE32, riscv_base32_cpu_init), - DEFINE_CPU(TYPE_RISCV_CPU_RV32GCSU_V1_09_1, rv32gcsu_priv1_09_1_cpu_init), - DEFINE_CPU(TYPE_RISCV_CPU_RV32GCSU_V1_10_0, rv32gcsu_priv1_10_0_cpu_init), - DEFINE_CPU(TYPE_RISCV_CPU_RV32IMACU_NOMMU, rv32imacu_nommu_cpu_init), DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_E31, rv32imacu_nommu_cpu_init), - DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_U34, rv32gcsu_priv1_10_0_cpu_init) + DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_U34, rv32gcsu_priv1_10_0_cpu_init), + /* Depreacted */ + DEFINE_CPU(TYPE_RISCV_CPU_RV32IMACU_NOMMU, rv32imacu_nommu_cpu_init), + DEFINE_CPU(TYPE_RISCV_CPU_RV32GCSU_V1_09_1, rv32gcsu_priv1_09_1_cpu_init), + DEFINE_CPU(TYPE_RISCV_CPU_RV32GCSU_V1_10_0, rv32gcsu_priv1_10_0_cpu_init) #elif defined(TARGET_RISCV64) DEFINE_CPU(TYPE_RISCV_CPU_BASE64, riscv_base64_cpu_init), - DEFINE_CPU(TYPE_RISCV_CPU_RV64GCSU_V1_09_1, rv64gcsu_priv1_09_1_cpu_init), - DEFINE_CPU(TYPE_RISCV_CPU_RV64GCSU_V1_10_0, rv64gcsu_priv1_10_0_cpu_init), - DEFINE_CPU(TYPE_RISCV_CPU_RV64IMACU_NOMMU, rv64imacu_nommu_cpu_init), DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_E51, rv64imacu_nommu_cpu_init), - DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_U54, rv64gcsu_priv1_10_0_cpu_init) + DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_U54, rv64gcsu_priv1_10_0_cpu_init), + /* Deprecated */ + DEFINE_CPU(TYPE_RISCV_CPU_RV64IMACU_NOMMU, rv64imacu_nommu_cpu_init), + DEFINE_CPU(TYPE_RISCV_CPU_RV64GCSU_V1_09_1, rv64gcsu_priv1_09_1_cpu_init), + DEFINE_CPU(TYPE_RISCV_CPU_RV64GCSU_V1_10_0, rv64gcsu_priv1_10_0_cpu_init) #endif }; diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 6c5de37b25..0adb307f32 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -35,16 +35,17 @@ #define TYPE_RISCV_CPU_ANY RISCV_CPU_TYPE_NAME("any") #define TYPE_RISCV_CPU_BASE32 RISCV_CPU_TYPE_NAME("rv32") #define TYPE_RISCV_CPU_BASE64 RISCV_CPU_TYPE_NAME("rv64") -#define TYPE_RISCV_CPU_RV32GCSU_V1_09_1 RISCV_CPU_TYPE_NAME("rv32gcsu-v1.9.1") -#define TYPE_RISCV_CPU_RV32GCSU_V1_10_0 RISCV_CPU_TYPE_NAME("rv32gcsu-v1.10.0") -#define TYPE_RISCV_CPU_RV32IMACU_NOMMU RISCV_CPU_TYPE_NAME("rv32imacu-nommu") -#define TYPE_RISCV_CPU_RV64GCSU_V1_09_1 RISCV_CPU_TYPE_NAME("rv64gcsu-v1.9.1") -#define TYPE_RISCV_CPU_RV64GCSU_V1_10_0 RISCV_CPU_TYPE_NAME("rv64gcsu-v1.10.0") -#define TYPE_RISCV_CPU_RV64IMACU_NOMMU RISCV_CPU_TYPE_NAME("rv64imacu-nommu") #define TYPE_RISCV_CPU_SIFIVE_E31 RISCV_CPU_TYPE_NAME("sifive-e31") #define TYPE_RISCV_CPU_SIFIVE_E51 RISCV_CPU_TYPE_NAME("sifive-e51") #define TYPE_RISCV_CPU_SIFIVE_U34 RISCV_CPU_TYPE_NAME("sifive-u34") #define TYPE_RISCV_CPU_SIFIVE_U54 RISCV_CPU_TYPE_NAME("sifive-u54") +/* Deprecated */ +#define TYPE_RISCV_CPU_RV32IMACU_NOMMU RISCV_CPU_TYPE_NAME("rv32imacu-nommu") +#define TYPE_RISCV_CPU_RV32GCSU_V1_09_1 RISCV_CPU_TYPE_NAME("rv32gcsu-v1.9.1") +#define TYPE_RISCV_CPU_RV32GCSU_V1_10_0 RISCV_CPU_TYPE_NAME("rv32gcsu-v1.10.0") +#define TYPE_RISCV_CPU_RV64IMACU_NOMMU RISCV_CPU_TYPE_NAME("rv64imacu-nommu") +#define TYPE_RISCV_CPU_RV64GCSU_V1_09_1 RISCV_CPU_TYPE_NAME("rv64gcsu-v1.9.1") +#define TYPE_RISCV_CPU_RV64GCSU_V1_10_0 RISCV_CPU_TYPE_NAME("rv64gcsu-v1.10.0") #define RV32 ((target_ulong)1 << (TARGET_LONG_BITS - 2)) #define RV64 ((target_ulong)2 << (TARGET_LONG_BITS - 2)) @@ -77,10 +78,11 @@ enum { RISCV_FEATURE_MISA }; -#define USER_VERSION_2_02_0 0x00020200 #define PRIV_VERSION_1_09_1 0x00010901 #define PRIV_VERSION_1_10_0 0x00011000 +#define PRIV_VERSION_1_11_0 0x00011100 +#define TRANSLATE_PMP_FAIL 2 #define TRANSLATE_FAIL 1 #define TRANSLATE_SUCCESS 0 #define MMU_USER_IDX 3 @@ -102,7 +104,6 @@ struct CPURISCVState { target_ulong badaddr; - target_ulong user_ver; target_ulong priv_ver; target_ulong misa; target_ulong misa_mask; @@ -211,6 +212,20 @@ typedef struct RISCVCPU { /* Configuration Settings */ struct { + bool ext_i; + bool ext_e; + bool ext_g; + bool ext_m; + bool ext_a; + bool ext_f; + bool ext_d; + bool ext_c; + bool ext_s; + bool ext_u; + bool ext_counters; + bool ext_ifencei; + bool ext_icsr; + char *priv_spec; char *user_spec; bool mmu; @@ -248,6 +263,8 @@ void riscv_cpu_do_unaligned_access(CPUState *cs, vaddr addr, bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size, MMUAccessType access_type, int mmu_idx, bool probe, uintptr_t retaddr); +void riscv_cpu_unassigned_access(CPUState *cpu, hwaddr addr, bool is_write, + bool is_exec, int unused, unsigned size); char *riscv_isa_string(RISCVCPU *cpu); void riscv_cpu_list(void); diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h index 47450a3cdb..11f971ad5d 100644 --- a/target/riscv/cpu_bits.h +++ b/target/riscv/cpu_bits.h @@ -136,6 +136,7 @@ #define CSR_MCOUNTEREN 0x306 /* Legacy Counter Setup (priv v1.9.1) */ +/* Update to #define CSR_MCOUNTINHIBIT 0x320 for 1.11.0 */ #define CSR_MUCOUNTEREN 0x320 #define CSR_MSCOUNTEREN 0x321 #define CSR_MHCOUNTEREN 0x322 diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c index 8b6754b917..e32b6126af 100644 --- a/target/riscv/cpu_helper.c +++ b/target/riscv/cpu_helper.c @@ -132,6 +132,16 @@ void riscv_cpu_set_mode(CPURISCVState *env, target_ulong newpriv) } /* tlb_flush is unnecessary as mode is contained in mmu_idx */ env->priv = newpriv; + + /* + * Clear the load reservation - otherwise a reservation placed in one + * context/process can be used by another, resulting in an SC succeeding + * incorrectly. Version 2.2 of the ISA specification explicitly requires + * this behaviour, while later revisions say that the kernel "should" use + * an SC instruction to force the yielding of a load reservation on a + * preemptive context switch. As a result, do both. + */ + env->load_res = -1; } /* get_physical_address - get the physical address for this virtual address @@ -230,6 +240,12 @@ restart: /* check that physical address of PTE is legal */ target_ulong pte_addr = base + idx * ptesize; + + if (riscv_feature(env, RISCV_FEATURE_PMP) && + !pmp_hart_has_privs(env, pte_addr, sizeof(target_ulong), + 1 << MMU_DATA_LOAD, PRV_S)) { + return TRANSLATE_PMP_FAIL; + } #if defined(TARGET_RISCV32) target_ulong pte = ldl_phys(cs->as, pte_addr); #elif defined(TARGET_RISCV64) @@ -337,12 +353,13 @@ restart: } static void raise_mmu_exception(CPURISCVState *env, target_ulong address, - MMUAccessType access_type) + MMUAccessType access_type, bool pmp_violation) { CPUState *cs = env_cpu(env); int page_fault_exceptions = (env->priv_ver >= PRIV_VERSION_1_10_0) && - get_field(env->satp, SATP_MODE) != VM_1_10_MBARE; + get_field(env->satp, SATP_MODE) != VM_1_10_MBARE && + !pmp_violation; switch (access_type) { case MMU_INST_FETCH: cs->exception_index = page_fault_exceptions ? @@ -375,6 +392,22 @@ hwaddr riscv_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) return phys_addr; } +void riscv_cpu_unassigned_access(CPUState *cs, hwaddr addr, bool is_write, + bool is_exec, int unused, unsigned size) +{ + RISCVCPU *cpu = RISCV_CPU(cs); + CPURISCVState *env = &cpu->env; + + if (is_write) { + cs->exception_index = RISCV_EXCP_STORE_AMO_ACCESS_FAULT; + } else { + cs->exception_index = RISCV_EXCP_LOAD_ACCESS_FAULT; + } + + env->badaddr = addr; + riscv_raise_exception(&cpu->env, cs->exception_index, GETPC()); +} + void riscv_cpu_do_unaligned_access(CPUState *cs, vaddr addr, MMUAccessType access_type, int mmu_idx, uintptr_t retaddr) @@ -408,20 +441,32 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size, CPURISCVState *env = &cpu->env; hwaddr pa = 0; int prot; + bool pmp_violation = false; int ret = TRANSLATE_FAIL; + int mode = mmu_idx; qemu_log_mask(CPU_LOG_MMU, "%s ad %" VADDR_PRIx " rw %d mmu_idx %d\n", __func__, address, access_type, mmu_idx); ret = get_physical_address(env, &pa, &prot, address, access_type, mmu_idx); + if (mode == PRV_M && access_type != MMU_INST_FETCH) { + if (get_field(env->mstatus, MSTATUS_MPRV)) { + mode = get_field(env->mstatus, MSTATUS_MPP); + } + } + qemu_log_mask(CPU_LOG_MMU, "%s address=%" VADDR_PRIx " ret %d physical " TARGET_FMT_plx " prot %d\n", __func__, address, ret, pa, prot); if (riscv_feature(env, RISCV_FEATURE_PMP) && - !pmp_hart_has_privs(env, pa, TARGET_PAGE_SIZE, 1 << access_type)) { - ret = TRANSLATE_FAIL; + (ret == TRANSLATE_SUCCESS) && + !pmp_hart_has_privs(env, pa, size, 1 << access_type, mode)) { + ret = TRANSLATE_PMP_FAIL; + } + if (ret == TRANSLATE_PMP_FAIL) { + pmp_violation = true; } if (ret == TRANSLATE_SUCCESS) { tlb_set_page(cs, address & TARGET_PAGE_MASK, pa & TARGET_PAGE_MASK, @@ -430,7 +475,7 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size, } else if (probe) { return false; } else { - raise_mmu_exception(env, address, access_type); + raise_mmu_exception(env, address, access_type, pmp_violation); riscv_raise_exception(env, cs->exception_index, retaddr); } #else diff --git a/target/riscv/csr.c b/target/riscv/csr.c index c67d29e206..e0d4586760 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -56,8 +56,24 @@ static int fs(CPURISCVState *env, int csrno) static int ctr(CPURISCVState *env, int csrno) { #if !defined(CONFIG_USER_ONLY) + CPUState *cs = env_cpu(env); + RISCVCPU *cpu = RISCV_CPU(cs); uint32_t ctr_en = ~0u; + if (!cpu->cfg.ext_counters) { + /* The Counters extensions is not enabled */ + return -1; + } + + /* + * The counters are always enabled at run time on newer priv specs, as the + * CSR has changed from controlling that the counters can be read to + * controlling that the counters increment. + */ + if (env->priv_ver > PRIV_VERSION_1_09_1) { + return 0; + } + if (env->priv < PRV_M) { ctr_en &= env->mcounteren; } @@ -461,18 +477,22 @@ static int write_mcounteren(CPURISCVState *env, int csrno, target_ulong val) return 0; } +/* This regiser is replaced with CSR_MCOUNTINHIBIT in 1.11.0 */ static int read_mscounteren(CPURISCVState *env, int csrno, target_ulong *val) { - if (env->priv_ver > PRIV_VERSION_1_09_1) { + if (env->priv_ver > PRIV_VERSION_1_09_1 + && env->priv_ver < PRIV_VERSION_1_11_0) { return -1; } *val = env->mcounteren; return 0; } +/* This regiser is replaced with CSR_MCOUNTINHIBIT in 1.11.0 */ static int write_mscounteren(CPURISCVState *env, int csrno, target_ulong val) { - if (env->priv_ver > PRIV_VERSION_1_09_1) { + if (env->priv_ver > PRIV_VERSION_1_09_1 + && env->priv_ver < PRIV_VERSION_1_11_0) { return -1; } env->mcounteren = val; @@ -773,6 +793,7 @@ int riscv_csrrw(CPURISCVState *env, int csrno, target_ulong *ret_value, { int ret; target_ulong old_value; + RISCVCPU *cpu = env_archcpu(env); /* check privileges and return -1 if check fails */ #if !defined(CONFIG_USER_ONLY) @@ -783,6 +804,11 @@ int riscv_csrrw(CPURISCVState *env, int csrno, target_ulong *ret_value, } #endif + /* ensure the CSR extension is enabled. */ + if (!cpu->cfg.ext_icsr) { + return -1; + } + /* check predicate */ if (!csr_ops[csrno].predicate || csr_ops[csrno].predicate(env, csrno) < 0) { return -1; diff --git a/target/riscv/insn_trans/trans_privileged.inc.c b/target/riscv/insn_trans/trans_privileged.inc.c index 664d6ba3f2..c5e4b3e49a 100644 --- a/target/riscv/insn_trans/trans_privileged.inc.c +++ b/target/riscv/insn_trans/trans_privileged.inc.c @@ -90,7 +90,7 @@ static bool trans_wfi(DisasContext *ctx, arg_wfi *a) static bool trans_sfence_vma(DisasContext *ctx, arg_sfence_vma *a) { #ifndef CONFIG_USER_ONLY - if (ctx->priv_ver == PRIV_VERSION_1_10_0) { + if (ctx->priv_ver >= PRIV_VERSION_1_10_0) { gen_helper_tlb_flush(cpu_env); return true; } diff --git a/target/riscv/insn_trans/trans_rva.inc.c b/target/riscv/insn_trans/trans_rva.inc.c index f6dbbc065e..fadd88849e 100644 --- a/target/riscv/insn_trans/trans_rva.inc.c +++ b/target/riscv/insn_trans/trans_rva.inc.c @@ -61,7 +61,7 @@ static inline bool gen_sc(DisasContext *ctx, arg_atomic *a, TCGMemOp mop) gen_set_label(l1); /* - * Address comparion failure. However, we still need to + * Address comparison failure. However, we still need to * provide the memory barrier implied by AQ/RL. */ tcg_gen_mb(TCG_MO_ALL + a->aq * TCG_BAR_LDAQ + a->rl * TCG_BAR_STRL); @@ -69,6 +69,12 @@ static inline bool gen_sc(DisasContext *ctx, arg_atomic *a, TCGMemOp mop) gen_set_gpr(a->rd, dat); gen_set_label(l2); + /* + * Clear the load reservation, since an SC must fail if there is + * an SC to any address, in between an LR and SC pair. + */ + tcg_gen_movi_tl(load_res, -1); + tcg_temp_free(dat); tcg_temp_free(src1); tcg_temp_free(src2); diff --git a/target/riscv/insn_trans/trans_rvi.inc.c b/target/riscv/insn_trans/trans_rvi.inc.c index 6cda078ed6..ea6473111c 100644 --- a/target/riscv/insn_trans/trans_rvi.inc.c +++ b/target/riscv/insn_trans/trans_rvi.inc.c @@ -484,6 +484,10 @@ static bool trans_fence(DisasContext *ctx, arg_fence *a) static bool trans_fence_i(DisasContext *ctx, arg_fence_i *a) { + if (!ctx->ext_ifencei) { + return false; + } + /* * FENCE_I is a no-op in QEMU, * however we need to end the translation block diff --git a/target/riscv/pmp.c b/target/riscv/pmp.c index fed1c3c030..958c7502a0 100644 --- a/target/riscv/pmp.c +++ b/target/riscv/pmp.c @@ -228,7 +228,7 @@ static int pmp_is_in_range(CPURISCVState *env, int pmp_index, target_ulong addr) * Check if the address has required RWX privs to complete desired operation */ bool pmp_hart_has_privs(CPURISCVState *env, target_ulong addr, - target_ulong size, pmp_priv_t privs) + target_ulong size, pmp_priv_t privs, target_ulong mode) { int i = 0; int ret = -1; @@ -245,7 +245,7 @@ bool pmp_hart_has_privs(CPURISCVState *env, target_ulong addr, from low to high */ for (i = 0; i < MAX_RISCV_PMPS; i++) { s = pmp_is_in_range(env, i, addr); - e = pmp_is_in_range(env, i, addr + size); + e = pmp_is_in_range(env, i, addr + size - 1); /* partially inside */ if ((s + e) == 1) { @@ -258,13 +258,14 @@ bool pmp_hart_has_privs(CPURISCVState *env, target_ulong addr, /* fully inside */ const uint8_t a_field = pmp_get_a_field(env->pmp_state.pmp[i].cfg_reg); - if ((s + e) == 2) { - if (PMP_AMATCH_OFF == a_field) { - return 1; - } + /* + * If the PMP entry is not off and the address is in range, do the priv + * check + */ + if (((s + e) == 2) && (PMP_AMATCH_OFF != a_field)) { allowed_privs = PMP_READ | PMP_WRITE | PMP_EXEC; - if ((env->priv != PRV_M) || pmp_is_locked(env, i)) { + if ((mode != PRV_M) || pmp_is_locked(env, i)) { allowed_privs &= env->pmp_state.pmp[i].cfg_reg; } @@ -280,7 +281,7 @@ bool pmp_hart_has_privs(CPURISCVState *env, target_ulong addr, /* No rule matched */ if (ret == -1) { - if (env->priv == PRV_M) { + if (mode == PRV_M) { ret = 1; /* Privileged spec v1.10 states if no PMP entry matches an * M-Mode access, the access succeeds */ } else { diff --git a/target/riscv/pmp.h b/target/riscv/pmp.h index 66790950eb..8e19793132 100644 --- a/target/riscv/pmp.h +++ b/target/riscv/pmp.h @@ -59,6 +59,6 @@ void pmpaddr_csr_write(CPURISCVState *env, uint32_t addr_index, target_ulong val); target_ulong pmpaddr_csr_read(CPURISCVState *env, uint32_t addr_index); bool pmp_hart_has_privs(CPURISCVState *env, target_ulong addr, - target_ulong size, pmp_priv_t priv); + target_ulong size, pmp_priv_t priv, target_ulong mode); #endif diff --git a/target/riscv/translate.c b/target/riscv/translate.c index 313c27b700..8d6ab73258 100644 --- a/target/riscv/translate.c +++ b/target/riscv/translate.c @@ -54,6 +54,7 @@ typedef struct DisasContext { to any system register, which includes CSR_FRM, so we do not have to reset this known value. */ int frm; + bool ext_ifencei; } DisasContext; #ifdef TARGET_RISCV64 @@ -752,6 +753,7 @@ static void riscv_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) { DisasContext *ctx = container_of(dcbase, DisasContext, base); CPURISCVState *env = cs->env_ptr; + RISCVCPU *cpu = RISCV_CPU(cs); ctx->pc_succ_insn = ctx->base.pc_first; ctx->mem_idx = ctx->base.tb->flags & TB_FLAGS_MMU_MASK; @@ -759,6 +761,7 @@ static void riscv_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) ctx->priv_ver = env->priv_ver; ctx->misa = env->misa; ctx->frm = -1; /* unknown rounding mode */ + ctx->ext_ifencei = cpu->cfg.ext_ifencei; } static void riscv_tr_tb_start(DisasContextBase *db, CPUState *cpu) |