diff --git a/hw/riscv/sifive_e.c b/hw/riscv/sifive_e.c index 0d37adc542..87d9602383 100644 --- a/hw/riscv/sifive_e.c +++ b/hw/riscv/sifive_e.c @@ -225,7 +225,7 @@ static void sifive_e_soc_realize(DeviceState *dev, Error **errp) RISCV_ACLINT_SWI_SIZE, RISCV_ACLINT_DEFAULT_MTIMER_SIZE, 0, ms->smp.cpus, RISCV_ACLINT_DEFAULT_MTIMECMP, RISCV_ACLINT_DEFAULT_MTIME, - RISCV_ACLINT_DEFAULT_TIMEBASE_FREQ, false); + SIFIVE_E_LFCLK_DEFAULT_FREQ, false); sifive_e_prci_create(memmap[SIFIVE_E_DEV_PRCI].base); /* AON */ diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index c7fc97e273..d2eac24156 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -962,7 +962,6 @@ static void create_fdt_uart(RISCVVirtState *s, const MemMapEntry *memmap, qemu_fdt_setprop_cells(ms->fdt, name, "interrupts", UART0_IRQ, 0x4); } - qemu_fdt_add_subnode(ms->fdt, "/chosen"); qemu_fdt_setprop_string(ms->fdt, "/chosen", "stdout-path", name); g_free(name); } @@ -1023,11 +1022,29 @@ static void create_fdt_fw_cfg(RISCVVirtState *s, const MemMapEntry *memmap) g_free(nodename); } +static void finalize_fdt(RISCVVirtState *s) +{ + uint32_t phandle = 1, irq_mmio_phandle = 1, msi_pcie_phandle = 1; + uint32_t irq_pcie_phandle = 1, irq_virtio_phandle = 1; + + create_fdt_sockets(s, virt_memmap, &phandle, &irq_mmio_phandle, + &irq_pcie_phandle, &irq_virtio_phandle, + &msi_pcie_phandle); + + create_fdt_virtio(s, virt_memmap, irq_virtio_phandle); + + create_fdt_pcie(s, virt_memmap, irq_pcie_phandle, msi_pcie_phandle); + + create_fdt_reset(s, virt_memmap, &phandle); + + create_fdt_uart(s, virt_memmap, irq_mmio_phandle); + + create_fdt_rtc(s, virt_memmap, irq_mmio_phandle); +} + static void create_fdt(RISCVVirtState *s, const MemMapEntry *memmap) { MachineState *ms = MACHINE(s); - uint32_t phandle = 1, irq_mmio_phandle = 1, msi_pcie_phandle = 1; - uint32_t irq_pcie_phandle = 1, irq_virtio_phandle = 1; uint8_t rng_seed[32]; ms->fdt = create_device_tree(&s->fdt_size); @@ -1047,28 +1064,16 @@ static void create_fdt(RISCVVirtState *s, const MemMapEntry *memmap) qemu_fdt_setprop_cell(ms->fdt, "/soc", "#size-cells", 0x2); qemu_fdt_setprop_cell(ms->fdt, "/soc", "#address-cells", 0x2); - create_fdt_sockets(s, memmap, &phandle, &irq_mmio_phandle, - &irq_pcie_phandle, &irq_virtio_phandle, - &msi_pcie_phandle); - - create_fdt_virtio(s, memmap, irq_virtio_phandle); - - create_fdt_pcie(s, memmap, irq_pcie_phandle, msi_pcie_phandle); - - create_fdt_reset(s, memmap, &phandle); - - create_fdt_uart(s, memmap, irq_mmio_phandle); - - create_fdt_rtc(s, memmap, irq_mmio_phandle); - - create_fdt_flash(s, memmap); - create_fdt_fw_cfg(s, memmap); - create_fdt_pmu(s); + qemu_fdt_add_subnode(ms->fdt, "/chosen"); /* Pass seed to RNG */ qemu_guest_getrandom_nofail(rng_seed, sizeof(rng_seed)); qemu_fdt_setprop(ms->fdt, "/chosen", "rng-seed", rng_seed, sizeof(rng_seed)); + + create_fdt_flash(s, memmap); + create_fdt_fw_cfg(s, memmap); + create_fdt_pmu(s); } static inline DeviceState *gpex_pcie_init(MemoryRegion *sys_mem, @@ -1257,15 +1262,12 @@ static void virt_machine_done(Notifier *notifier, void *data) uint64_t kernel_entry = 0; BlockBackend *pflash_blk0; - /* load/create device tree */ - if (machine->dtb) { - machine->fdt = load_device_tree(machine->dtb, &s->fdt_size); - if (!machine->fdt) { - error_report("load_device_tree() failed"); - exit(1); - } - } else { - create_fdt(s, memmap); + /* + * An user provided dtb must include everything, including + * dynamic sysbus devices. Our FDT needs to be finalized. + */ + if (machine->dtb == NULL) { + finalize_fdt(s); } /* @@ -1541,6 +1543,17 @@ static void virt_machine_init(MachineState *machine) } virt_flash_map(s, system_memory); + /* load/create device tree */ + if (machine->dtb) { + machine->fdt = load_device_tree(machine->dtb, &s->fdt_size); + if (!machine->fdt) { + error_report("load_device_tree() failed"); + exit(1); + } + } else { + create_fdt(s, memmap); + } + s->machine_done.notify = virt_machine_done; qemu_add_machine_init_done_notifier(&s->machine_done); } diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 16ca5ea7b6..e384e14248 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -8808,6 +8808,8 @@ static int do_getdents64(abi_long dirfd, abi_long arg2, abi_long count) #define RISCV_HWPROBE_MISALIGNED_UNSUPPORTED (4 << 0) #define RISCV_HWPROBE_MISALIGNED_MASK (7 << 0) +#define RISCV_HWPROBE_KEY_ZICBOZ_BLOCK_SIZE 6 + struct riscv_hwprobe { abi_llong key; abi_ullong value; @@ -8860,6 +8862,10 @@ static void risc_hwprobe_fill_pairs(CPURISCVState *env, case RISCV_HWPROBE_KEY_CPUPERF_0: __put_user(RISCV_HWPROBE_MISALIGNED_FAST, &pair->value); break; + case RISCV_HWPROBE_KEY_ZICBOZ_BLOCK_SIZE: + value = cfg->ext_zicboz ? cfg->cboz_blocksize : 0; + __put_user(value, &pair->value); + break; default: __put_user(-1, &pair->key); break; diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c index b7af69de53..e7e23b34f4 100644 --- a/target/riscv/cpu_helper.c +++ b/target/riscv/cpu_helper.c @@ -1032,13 +1032,29 @@ restart: prot |= PAGE_WRITE; } if (pte & PTE_X) { - bool mxr; + bool mxr = false; - if (first_stage == true) { + /* + * Use mstatus for first stage or for the second stage without + * virt_enabled (MPRV+MPV) + */ + if (first_stage || !env->virt_enabled) { mxr = get_field(env->mstatus, MSTATUS_MXR); - } else { - mxr = get_field(env->vsstatus, MSTATUS_MXR); } + + /* MPRV+MPV case, check VSSTATUS */ + if (first_stage && two_stage && !env->virt_enabled) { + mxr |= get_field(env->vsstatus, MSTATUS_MXR); + } + + /* + * Setting MXR at HS-level overrides both VS-stage and G-stage + * execute-only permissions + */ + if (env->virt_enabled) { + mxr |= get_field(env->mstatus_hs, MSTATUS_MXR); + } + if (mxr) { prot |= PAGE_READ; } @@ -1143,47 +1159,31 @@ static void raise_mmu_exception(CPURISCVState *env, target_ulong address, bool two_stage_indirect) { CPUState *cs = env_cpu(env); - int page_fault_exceptions, vm; - uint64_t stap_mode; - - if (riscv_cpu_mxl(env) == MXL_RV32) { - stap_mode = SATP32_MODE; - } else { - stap_mode = SATP64_MODE; - } - - if (first_stage) { - vm = get_field(env->satp, stap_mode); - } else { - vm = get_field(env->hgatp, stap_mode); - } - - page_fault_exceptions = vm != VM_1_10_MBARE && !pmp_violation; switch (access_type) { case MMU_INST_FETCH: if (env->virt_enabled && !first_stage) { cs->exception_index = RISCV_EXCP_INST_GUEST_PAGE_FAULT; } else { - cs->exception_index = page_fault_exceptions ? - RISCV_EXCP_INST_PAGE_FAULT : RISCV_EXCP_INST_ACCESS_FAULT; + cs->exception_index = pmp_violation ? + RISCV_EXCP_INST_ACCESS_FAULT : RISCV_EXCP_INST_PAGE_FAULT; } break; case MMU_DATA_LOAD: if (two_stage && !first_stage) { cs->exception_index = RISCV_EXCP_LOAD_GUEST_ACCESS_FAULT; } else { - cs->exception_index = page_fault_exceptions ? - RISCV_EXCP_LOAD_PAGE_FAULT : RISCV_EXCP_LOAD_ACCESS_FAULT; + cs->exception_index = pmp_violation ? + RISCV_EXCP_LOAD_ACCESS_FAULT : RISCV_EXCP_LOAD_PAGE_FAULT; } break; case MMU_DATA_STORE: if (two_stage && !first_stage) { cs->exception_index = RISCV_EXCP_STORE_GUEST_AMO_ACCESS_FAULT; } else { - cs->exception_index = page_fault_exceptions ? - RISCV_EXCP_STORE_PAGE_FAULT : - RISCV_EXCP_STORE_AMO_ACCESS_FAULT; + cs->exception_index = pmp_violation ? + RISCV_EXCP_STORE_AMO_ACCESS_FAULT : + RISCV_EXCP_STORE_PAGE_FAULT; } break; default: diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c index 08adad304d..8a35683a34 100644 --- a/target/riscv/tcg/tcg-cpu.c +++ b/target/riscv/tcg/tcg-cpu.c @@ -250,6 +250,15 @@ static void riscv_cpu_disable_priv_spec_isa_exts(RISCVCPU *cpu) for (edata = isa_edata_arr; edata && edata->name; edata++) { if (isa_ext_is_enabled(cpu, edata->ext_enable_offset) && (env->priv_ver < edata->min_version)) { + /* + * These two extensions are always enabled as they were supported + * by QEMU before they were added as extensions in the ISA. + */ + if (!strcmp(edata->name, "zicntr") || + !strcmp(edata->name, "zihpm")) { + continue; + } + isa_ext_update_enabled(cpu, edata->ext_enable_offset, false); #ifndef CONFIG_USER_ONLY warn_report("disabling %s extension for hart 0x" TARGET_FMT_lx