diff options
author | Peter Maydell | 2020-03-03 12:06:39 +0100 |
---|---|---|
committer | Peter Maydell | 2020-03-03 12:06:39 +0100 |
commit | 2ac031d171ccd18c973014d9978b4a63f0ad5fb0 (patch) | |
tree | d0c01e70238eb9c69730dbbe06e8691a3aa75501 /target/riscv/csr.c | |
parent | Merge remote-tracking branch 'remotes/kraxel/tags/vga-20200302-pull-request' ... (diff) | |
parent | hw/riscv: Provide rdtime callback for TCG in CLINT emulation (diff) | |
download | qemu-2ac031d171ccd18c973014d9978b4a63f0ad5fb0.tar.gz qemu-2ac031d171ccd18c973014d9978b4a63f0ad5fb0.tar.xz qemu-2ac031d171ccd18c973014d9978b4a63f0ad5fb0.zip |
Merge remote-tracking branch 'remotes/palmer/tags/riscv-for-master-5.0-sf3' into staging
RISC-V Patches for the 5.0 Soft Freeze, Part 3
This pull request is almost entirely an implementation of the draft hypervisor
extension. This extension is still in draft and is expected to have
incompatible changes before being frozen, but we've had good luck managing
other RISC-V draft extensions in QEMU so far.
Additionally, there's a fix to PCI addressing and some improvements to the
M-mode timer.
This boots linux and passes make check for me.
# gpg: Signature made Tue 03 Mar 2020 00:23:20 GMT
# gpg: using RSA key 2B3C3747446843B24A943A7A2E1319F35FBB1889
# gpg: issuer "palmer@dabbelt.com"
# gpg: Good signature from "Palmer Dabbelt <palmer@dabbelt.com>" [unknown]
# gpg: aka "Palmer Dabbelt <palmer@sifive.com>" [unknown]
# gpg: aka "Palmer Dabbelt <palmerdabbelt@google.com>" [unknown]
# gpg: WARNING: This key is not certified with a trusted signature!
# gpg: There is no indication that the signature belongs to the owner.
# Primary key fingerprint: 00CE 76D1 8349 60DF CE88 6DF8 EF4C A150 2CCB AB41
# Subkey fingerprint: 2B3C 3747 4468 43B2 4A94 3A7A 2E13 19F3 5FBB 1889
* remotes/palmer/tags/riscv-for-master-5.0-sf3: (38 commits)
hw/riscv: Provide rdtime callback for TCG in CLINT emulation
target/riscv: Emulate TIME CSRs for privileged mode
riscv: virt: Allow PCI address 0
target/riscv: Allow enabling the Hypervisor extension
target/riscv: Add the MSTATUS_MPV_ISSET helper macro
target/riscv: Add support for the 32-bit MSTATUSH CSR
target/riscv: Set htval and mtval2 on execptions
target/riscv: Raise the new execptions when 2nd stage translation fails
target/riscv: Implement second stage MMU
target/riscv: Allow specifying MMU stage
target/riscv: Respect MPRV and SPRV for floating point ops
target/riscv: Mark both sstatus and msstatus_hs as dirty
target/riscv: Disable guest FP support based on virtual status
target/riscv: Only set TB flags with FP status if enabled
target/riscv: Remove the hret instruction
target/riscv: Add hfence instructions
target/riscv: Add Hypervisor trap return support
target/riscv: Add hypvervisor trap support
target/riscv: Generate illegal instruction on WFI when V=1
target/ricsv: Flush the TLB on virtulisation mode changes
...
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'target/riscv/csr.c')
-rw-r--r-- | target/riscv/csr.c | 455 |
1 files changed, 438 insertions, 17 deletions
diff --git a/target/riscv/csr.c b/target/riscv/csr.c index 0e34c292c5..11d184cd16 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -98,6 +98,20 @@ static int smode(CPURISCVState *env, int csrno) return -!riscv_has_ext(env, RVS); } +static int hmode(CPURISCVState *env, int csrno) +{ + if (riscv_has_ext(env, RVS) && + riscv_has_ext(env, RVH)) { + /* Hypervisor extension is supported */ + if ((env->priv == PRV_S && !riscv_cpu_virt_enabled(env)) || + env->priv == PRV_M) { + return 0; + } + } + + return -1; +} + static int pmp(CPURISCVState *env, int csrno) { return -!riscv_feature(env, RISCV_FEATURE_PMP); @@ -224,13 +238,42 @@ static int read_timeh(CPURISCVState *env, int csrno, target_ulong *val) #else /* CONFIG_USER_ONLY */ +static int read_time(CPURISCVState *env, int csrno, target_ulong *val) +{ + uint64_t delta = riscv_cpu_virt_enabled(env) ? env->htimedelta : 0; + + if (!env->rdtime_fn) { + return -1; + } + + *val = env->rdtime_fn() + delta; + return 0; +} + +#if defined(TARGET_RISCV32) +static int read_timeh(CPURISCVState *env, int csrno, target_ulong *val) +{ + uint64_t delta = riscv_cpu_virt_enabled(env) ? env->htimedelta : 0; + + if (!env->rdtime_fn) { + return -1; + } + + *val = (env->rdtime_fn() + delta) >> 32; + return 0; +} +#endif + /* Machine constants */ -#define M_MODE_INTERRUPTS (MIP_MSIP | MIP_MTIP | MIP_MEIP) -#define S_MODE_INTERRUPTS (MIP_SSIP | MIP_STIP | MIP_SEIP) +#define M_MODE_INTERRUPTS (MIP_MSIP | MIP_MTIP | MIP_MEIP) +#define S_MODE_INTERRUPTS (MIP_SSIP | MIP_STIP | MIP_SEIP) +#define VS_MODE_INTERRUPTS (MIP_VSSIP | MIP_VSTIP | MIP_VSEIP) -static const target_ulong delegable_ints = S_MODE_INTERRUPTS; -static const target_ulong all_ints = M_MODE_INTERRUPTS | S_MODE_INTERRUPTS; +static const target_ulong delegable_ints = S_MODE_INTERRUPTS | + VS_MODE_INTERRUPTS; +static const target_ulong all_ints = M_MODE_INTERRUPTS | S_MODE_INTERRUPTS | + VS_MODE_INTERRUPTS; static const target_ulong delegable_excps = (1ULL << (RISCV_EXCP_INST_ADDR_MIS)) | (1ULL << (RISCV_EXCP_INST_ACCESS_FAULT)) | @@ -242,11 +285,14 @@ static const target_ulong delegable_excps = (1ULL << (RISCV_EXCP_STORE_AMO_ACCESS_FAULT)) | (1ULL << (RISCV_EXCP_U_ECALL)) | (1ULL << (RISCV_EXCP_S_ECALL)) | - (1ULL << (RISCV_EXCP_H_ECALL)) | + (1ULL << (RISCV_EXCP_VS_ECALL)) | (1ULL << (RISCV_EXCP_M_ECALL)) | (1ULL << (RISCV_EXCP_INST_PAGE_FAULT)) | (1ULL << (RISCV_EXCP_LOAD_PAGE_FAULT)) | - (1ULL << (RISCV_EXCP_STORE_PAGE_FAULT)); + (1ULL << (RISCV_EXCP_STORE_PAGE_FAULT)) | + (1ULL << (RISCV_EXCP_INST_GUEST_PAGE_FAULT)) | + (1ULL << (RISCV_EXCP_LOAD_GUEST_ACCESS_FAULT)) | + (1ULL << (RISCV_EXCP_STORE_GUEST_AMO_ACCESS_FAULT)); static const target_ulong sstatus_v1_9_mask = SSTATUS_SIE | SSTATUS_SPIE | SSTATUS_UIE | SSTATUS_UPIE | SSTATUS_SPP | SSTATUS_FS | SSTATUS_XS | SSTATUS_SUM | SSTATUS_SD; @@ -254,6 +300,8 @@ static const target_ulong sstatus_v1_10_mask = SSTATUS_SIE | SSTATUS_SPIE | SSTATUS_UIE | SSTATUS_UPIE | SSTATUS_SPP | SSTATUS_FS | SSTATUS_XS | SSTATUS_SUM | SSTATUS_MXR | SSTATUS_SD; static const target_ulong sip_writable_mask = SIP_SSIP | MIP_USIP | MIP_UEIP; +static const target_ulong hip_writable_mask = MIP_VSSIP | MIP_VSTIP | MIP_VSEIP; +static const target_ulong vsip_writable_mask = MIP_VSSIP; #if defined(TARGET_RISCV32) static const char valid_vm_1_09[16] = { @@ -349,6 +397,27 @@ static int write_mstatus(CPURISCVState *env, int csrno, target_ulong val) return 0; } +#ifdef TARGET_RISCV32 +static int read_mstatush(CPURISCVState *env, int csrno, target_ulong *val) +{ + *val = env->mstatush; + return 0; +} + +static int write_mstatush(CPURISCVState *env, int csrno, target_ulong val) +{ + if ((val ^ env->mstatush) & (MSTATUS_MPV)) { + tlb_flush(env_cpu(env)); + } + + val &= MSTATUS_MPV | MSTATUS_MTL; + + env->mstatush = val; + + return 0; +} +#endif + static int read_misa(CPURISCVState *env, int csrno, target_ulong *val) { *val = env->misa; @@ -428,6 +497,9 @@ static int read_mideleg(CPURISCVState *env, int csrno, target_ulong *val) static int write_mideleg(CPURISCVState *env, int csrno, target_ulong val) { env->mideleg = (env->mideleg & ~delegable_ints) | (val & delegable_ints); + if (riscv_has_ext(env, RVH)) { + env->mideleg |= VS_MODE_INTERRUPTS; + } return 0; } @@ -607,13 +679,27 @@ static int write_sstatus(CPURISCVState *env, int csrno, target_ulong val) static int read_sie(CPURISCVState *env, int csrno, target_ulong *val) { - *val = env->mie & env->mideleg; + if (riscv_cpu_virt_enabled(env)) { + /* Tell the guest the VS bits, shifted to the S bit locations */ + *val = (env->mie & env->mideleg & VS_MODE_INTERRUPTS) >> 1; + } else { + *val = env->mie & env->mideleg; + } return 0; } static int write_sie(CPURISCVState *env, int csrno, target_ulong val) { - target_ulong newval = (env->mie & ~env->mideleg) | (val & env->mideleg); + target_ulong newval; + + if (riscv_cpu_virt_enabled(env)) { + /* Shift the guests S bits to VS */ + newval = (env->mie & ~VS_MODE_INTERRUPTS) | + ((val << 1) & VS_MODE_INTERRUPTS); + } else { + newval = (env->mie & ~S_MODE_INTERRUPTS) | (val & S_MODE_INTERRUPTS); + } + return write_mie(env, CSR_MIE, newval); } @@ -704,8 +790,19 @@ static int write_sbadaddr(CPURISCVState *env, int csrno, target_ulong val) static int rmw_sip(CPURISCVState *env, int csrno, target_ulong *ret_value, target_ulong new_value, target_ulong write_mask) { - int ret = rmw_mip(env, CSR_MSTATUS, ret_value, new_value, + int ret; + + if (riscv_cpu_virt_enabled(env)) { + /* Shift the new values to line up with the VS bits */ + ret = rmw_mip(env, CSR_MSTATUS, ret_value, new_value << 1, + (write_mask & sip_writable_mask) << 1 & env->mideleg); + ret &= vsip_writable_mask; + ret >>= 1; + } else { + ret = rmw_mip(env, CSR_MSTATUS, ret_value, new_value, write_mask & env->mideleg & sip_writable_mask); + } + *ret_value &= env->mideleg; return ret; } @@ -753,6 +850,291 @@ static int write_satp(CPURISCVState *env, int csrno, target_ulong val) return 0; } +/* Hypervisor Extensions */ +static int read_hstatus(CPURISCVState *env, int csrno, target_ulong *val) +{ + *val = env->hstatus; + return 0; +} + +static int write_hstatus(CPURISCVState *env, int csrno, target_ulong val) +{ + env->hstatus = val; + return 0; +} + +static int read_hedeleg(CPURISCVState *env, int csrno, target_ulong *val) +{ + *val = env->hedeleg; + return 0; +} + +static int write_hedeleg(CPURISCVState *env, int csrno, target_ulong val) +{ + env->hedeleg = val; + return 0; +} + +static int read_hideleg(CPURISCVState *env, int csrno, target_ulong *val) +{ + *val = env->hideleg; + return 0; +} + +static int write_hideleg(CPURISCVState *env, int csrno, target_ulong val) +{ + env->hideleg = val; + return 0; +} + +static int rmw_hip(CPURISCVState *env, int csrno, target_ulong *ret_value, + target_ulong new_value, target_ulong write_mask) +{ + int ret = rmw_mip(env, 0, ret_value, new_value, + write_mask & hip_writable_mask); + + return ret; +} + +static int read_hie(CPURISCVState *env, int csrno, target_ulong *val) +{ + *val = env->mie & VS_MODE_INTERRUPTS; + return 0; +} + +static int write_hie(CPURISCVState *env, int csrno, target_ulong val) +{ + target_ulong newval = (env->mie & ~VS_MODE_INTERRUPTS) | (val & VS_MODE_INTERRUPTS); + return write_mie(env, CSR_MIE, newval); +} + +static int read_hcounteren(CPURISCVState *env, int csrno, target_ulong *val) +{ + *val = env->hcounteren; + return 0; +} + +static int write_hcounteren(CPURISCVState *env, int csrno, target_ulong val) +{ + env->hcounteren = val; + return 0; +} + +static int read_htval(CPURISCVState *env, int csrno, target_ulong *val) +{ + *val = env->htval; + return 0; +} + +static int write_htval(CPURISCVState *env, int csrno, target_ulong val) +{ + env->htval = val; + return 0; +} + +static int read_htinst(CPURISCVState *env, int csrno, target_ulong *val) +{ + *val = env->htinst; + return 0; +} + +static int write_htinst(CPURISCVState *env, int csrno, target_ulong val) +{ + env->htinst = val; + return 0; +} + +static int read_hgatp(CPURISCVState *env, int csrno, target_ulong *val) +{ + *val = env->hgatp; + return 0; +} + +static int write_hgatp(CPURISCVState *env, int csrno, target_ulong val) +{ + env->hgatp = val; + return 0; +} + +static int read_htimedelta(CPURISCVState *env, int csrno, target_ulong *val) +{ + if (!env->rdtime_fn) { + return -1; + } + +#if defined(TARGET_RISCV32) + *val = env->htimedelta & 0xffffffff; +#else + *val = env->htimedelta; +#endif + return 0; +} + +static int write_htimedelta(CPURISCVState *env, int csrno, target_ulong val) +{ + if (!env->rdtime_fn) { + return -1; + } + +#if defined(TARGET_RISCV32) + env->htimedelta = deposit64(env->htimedelta, 0, 32, (uint64_t)val); +#else + env->htimedelta = val; +#endif + return 0; +} + +#if defined(TARGET_RISCV32) +static int read_htimedeltah(CPURISCVState *env, int csrno, target_ulong *val) +{ + if (!env->rdtime_fn) { + return -1; + } + + *val = env->htimedelta >> 32; + return 0; +} + +static int write_htimedeltah(CPURISCVState *env, int csrno, target_ulong val) +{ + if (!env->rdtime_fn) { + return -1; + } + + env->htimedelta = deposit64(env->htimedelta, 32, 32, (uint64_t)val); + return 0; +} +#endif + +/* Virtual CSR Registers */ +static int read_vsstatus(CPURISCVState *env, int csrno, target_ulong *val) +{ + *val = env->vsstatus; + return 0; +} + +static int write_vsstatus(CPURISCVState *env, int csrno, target_ulong val) +{ + env->vsstatus = val; + return 0; +} + +static int rmw_vsip(CPURISCVState *env, int csrno, target_ulong *ret_value, + target_ulong new_value, target_ulong write_mask) +{ + int ret = rmw_mip(env, 0, ret_value, new_value, + write_mask & env->mideleg & vsip_writable_mask); + return ret; +} + +static int read_vsie(CPURISCVState *env, int csrno, target_ulong *val) +{ + *val = env->mie & env->mideleg & VS_MODE_INTERRUPTS; + return 0; +} + +static int write_vsie(CPURISCVState *env, int csrno, target_ulong val) +{ + target_ulong newval = (env->mie & ~env->mideleg) | (val & env->mideleg & MIP_VSSIP); + return write_mie(env, CSR_MIE, newval); +} + +static int read_vstvec(CPURISCVState *env, int csrno, target_ulong *val) +{ + *val = env->vstvec; + return 0; +} + +static int write_vstvec(CPURISCVState *env, int csrno, target_ulong val) +{ + env->vstvec = val; + return 0; +} + +static int read_vsscratch(CPURISCVState *env, int csrno, target_ulong *val) +{ + *val = env->vsscratch; + return 0; +} + +static int write_vsscratch(CPURISCVState *env, int csrno, target_ulong val) +{ + env->vsscratch = val; + return 0; +} + +static int read_vsepc(CPURISCVState *env, int csrno, target_ulong *val) +{ + *val = env->vsepc; + return 0; +} + +static int write_vsepc(CPURISCVState *env, int csrno, target_ulong val) +{ + env->vsepc = val; + return 0; +} + +static int read_vscause(CPURISCVState *env, int csrno, target_ulong *val) +{ + *val = env->vscause; + return 0; +} + +static int write_vscause(CPURISCVState *env, int csrno, target_ulong val) +{ + env->vscause = val; + return 0; +} + +static int read_vstval(CPURISCVState *env, int csrno, target_ulong *val) +{ + *val = env->vstval; + return 0; +} + +static int write_vstval(CPURISCVState *env, int csrno, target_ulong val) +{ + env->vstval = val; + return 0; +} + +static int read_vsatp(CPURISCVState *env, int csrno, target_ulong *val) +{ + *val = env->vsatp; + return 0; +} + +static int write_vsatp(CPURISCVState *env, int csrno, target_ulong val) +{ + env->vsatp = val; + return 0; +} + +static int read_mtval2(CPURISCVState *env, int csrno, target_ulong *val) +{ + *val = env->mtval2; + return 0; +} + +static int write_mtval2(CPURISCVState *env, int csrno, target_ulong val) +{ + env->mtval2 = val; + return 0; +} + +static int read_mtinst(CPURISCVState *env, int csrno, target_ulong *val) +{ + *val = env->mtinst; + return 0; +} + +static int write_mtinst(CPURISCVState *env, int csrno, target_ulong val) +{ + env->mtinst = val; + return 0; +} + /* Physical Memory Protection */ static int read_pmpcfg(CPURISCVState *env, int csrno, target_ulong *val) { @@ -798,12 +1180,22 @@ int riscv_csrrw(CPURISCVState *env, int csrno, target_ulong *ret_value, /* check privileges and return -1 if check fails */ #if !defined(CONFIG_USER_ONLY) - int csr_priv = get_field(csrno, 0x300); + int effective_priv = env->priv; int read_only = get_field(csrno, 0xC00) == 3; - if ((!env->debugger) && (env->priv < csr_priv)) { - return -1; + + if (riscv_has_ext(env, RVH) && + env->priv == PRV_S && + !riscv_cpu_virt_enabled(env)) { + /* + * We are in S mode without virtualisation, therefore we are in HS Mode. + * Add 1 to the effective privledge level to allow us to access the + * Hypervisor CSRs. + */ + effective_priv++; } - if (write_mask && read_only) { + + if ((write_mask && read_only) || + (!env->debugger && (effective_priv < get_field(csrno, 0x300)))) { return -1; } #endif @@ -886,14 +1278,12 @@ static riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = { [CSR_INSTRETH] = { ctr, read_instreth }, #endif - /* User-level time CSRs are only available in linux-user - * In privileged mode, the monitor emulates these CSRs */ -#if defined(CONFIG_USER_ONLY) + /* In privileged mode, the monitor will have to emulate TIME CSRs only if + * rdtime callback is not provided by machine/platform emulation */ [CSR_TIME] = { ctr, read_time }, #if defined(TARGET_RISCV32) [CSR_TIMEH] = { ctr, read_timeh }, #endif -#endif #if !defined(CONFIG_USER_ONLY) /* Machine Timers and Counters */ @@ -919,6 +1309,10 @@ static riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = { [CSR_MTVEC] = { any, read_mtvec, write_mtvec }, [CSR_MCOUNTEREN] = { any, read_mcounteren, write_mcounteren }, +#if defined(TARGET_RISCV32) + [CSR_MSTATUSH] = { any, read_mstatush, write_mstatush }, +#endif + /* Legacy Counter Setup (priv v1.9.1) */ [CSR_MUCOUNTEREN] = { any, read_mucounteren, write_mucounteren }, [CSR_MSCOUNTEREN] = { any, read_mscounteren, write_mscounteren }, @@ -946,6 +1340,33 @@ static riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = { /* Supervisor Protection and Translation */ [CSR_SATP] = { smode, read_satp, write_satp }, + [CSR_HSTATUS] = { hmode, read_hstatus, write_hstatus }, + [CSR_HEDELEG] = { hmode, read_hedeleg, write_hedeleg }, + [CSR_HIDELEG] = { hmode, read_hideleg, write_hideleg }, + [CSR_HIP] = { hmode, NULL, NULL, rmw_hip }, + [CSR_HIE] = { hmode, read_hie, write_hie }, + [CSR_HCOUNTEREN] = { hmode, read_hcounteren, write_hcounteren }, + [CSR_HTVAL] = { hmode, read_htval, write_htval }, + [CSR_HTINST] = { hmode, read_htinst, write_htinst }, + [CSR_HGATP] = { hmode, read_hgatp, write_hgatp }, + [CSR_HTIMEDELTA] = { hmode, read_htimedelta, write_htimedelta }, +#if defined(TARGET_RISCV32) + [CSR_HTIMEDELTAH] = { hmode, read_htimedeltah, write_htimedeltah}, +#endif + + [CSR_VSSTATUS] = { hmode, read_vsstatus, write_vsstatus }, + [CSR_VSIP] = { hmode, NULL, NULL, rmw_vsip }, + [CSR_VSIE] = { hmode, read_vsie, write_vsie }, + [CSR_VSTVEC] = { hmode, read_vstvec, write_vstvec }, + [CSR_VSSCRATCH] = { hmode, read_vsscratch, write_vsscratch }, + [CSR_VSEPC] = { hmode, read_vsepc, write_vsepc }, + [CSR_VSCAUSE] = { hmode, read_vscause, write_vscause }, + [CSR_VSTVAL] = { hmode, read_vstval, write_vstval }, + [CSR_VSATP] = { hmode, read_vsatp, write_vsatp }, + + [CSR_MTVAL2] = { hmode, read_mtval2, write_mtval2 }, + [CSR_MTINST] = { hmode, read_mtinst, write_mtinst }, + /* Physical Memory Protection */ [CSR_PMPCFG0 ... CSR_PMPADDR9] = { pmp, read_pmpcfg, write_pmpcfg }, [CSR_PMPADDR0 ... CSR_PMPADDR15] = { pmp, read_pmpaddr, write_pmpaddr }, |