diff options
Diffstat (limited to 'target/riscv/csr.c')
| -rw-r--r-- | target/riscv/csr.c | 171 |
1 files changed, 143 insertions, 28 deletions
diff --git a/target/riscv/csr.c b/target/riscv/csr.c index 6a96a01b1c..200001de74 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -51,7 +51,7 @@ static int fs(CPURISCVState *env, int csrno) return 0; } if (!env->debugger && !riscv_cpu_fp_enabled(env)) { - return -1; + return -RISCV_EXCP_ILLEGAL_INST; } #endif return 0; @@ -73,7 +73,62 @@ static int ctr(CPURISCVState *env, int csrno) if (!cpu->cfg.ext_counters) { /* The Counters extensions is not enabled */ - return -1; + return -RISCV_EXCP_ILLEGAL_INST; + } + + if (riscv_cpu_virt_enabled(env)) { + switch (csrno) { + case CSR_CYCLE: + if (!get_field(env->hcounteren, HCOUNTEREN_CY) && + get_field(env->mcounteren, HCOUNTEREN_CY)) { + return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT; + } + break; + case CSR_TIME: + if (!get_field(env->hcounteren, HCOUNTEREN_TM) && + get_field(env->mcounteren, HCOUNTEREN_TM)) { + return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT; + } + break; + case CSR_INSTRET: + if (!get_field(env->hcounteren, HCOUNTEREN_IR) && + get_field(env->mcounteren, HCOUNTEREN_IR)) { + return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT; + } + break; + case CSR_HPMCOUNTER3...CSR_HPMCOUNTER31: + if (!get_field(env->hcounteren, 1 << (csrno - CSR_HPMCOUNTER3)) && + get_field(env->mcounteren, 1 << (csrno - CSR_HPMCOUNTER3))) { + return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT; + } + break; +#if defined(TARGET_RISCV32) + case CSR_CYCLEH: + if (!get_field(env->hcounteren, HCOUNTEREN_CY) && + get_field(env->mcounteren, HCOUNTEREN_CY)) { + return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT; + } + break; + case CSR_TIMEH: + if (!get_field(env->hcounteren, HCOUNTEREN_TM) && + get_field(env->mcounteren, HCOUNTEREN_TM)) { + return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT; + } + break; + case CSR_INSTRETH: + if (!get_field(env->hcounteren, HCOUNTEREN_IR) && + get_field(env->mcounteren, HCOUNTEREN_IR)) { + return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT; + } + break; + case CSR_HPMCOUNTER3H...CSR_HPMCOUNTER31H: + if (!get_field(env->hcounteren, 1 << (csrno - CSR_HPMCOUNTER3H)) && + get_field(env->mcounteren, 1 << (csrno - CSR_HPMCOUNTER3H))) { + return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT; + } + break; +#endif + } } #endif return 0; @@ -98,10 +153,12 @@ static int hmode(CPURISCVState *env, int csrno) if ((env->priv == PRV_S && !riscv_cpu_virt_enabled(env)) || env->priv == PRV_M) { return 0; + } else { + return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT; } } - return -1; + return -RISCV_EXCP_ILLEGAL_INST; } static int pmp(CPURISCVState *env, int csrno) @@ -115,7 +172,7 @@ static int read_fflags(CPURISCVState *env, int csrno, target_ulong *val) { #if !defined(CONFIG_USER_ONLY) if (!env->debugger && !riscv_cpu_fp_enabled(env)) { - return -1; + return -RISCV_EXCP_ILLEGAL_INST; } #endif *val = riscv_cpu_get_fflags(env); @@ -126,7 +183,7 @@ static int write_fflags(CPURISCVState *env, int csrno, target_ulong val) { #if !defined(CONFIG_USER_ONLY) if (!env->debugger && !riscv_cpu_fp_enabled(env)) { - return -1; + return -RISCV_EXCP_ILLEGAL_INST; } env->mstatus |= MSTATUS_FS; #endif @@ -138,7 +195,7 @@ static int read_frm(CPURISCVState *env, int csrno, target_ulong *val) { #if !defined(CONFIG_USER_ONLY) if (!env->debugger && !riscv_cpu_fp_enabled(env)) { - return -1; + return -RISCV_EXCP_ILLEGAL_INST; } #endif *val = env->frm; @@ -149,7 +206,7 @@ static int write_frm(CPURISCVState *env, int csrno, target_ulong val) { #if !defined(CONFIG_USER_ONLY) if (!env->debugger && !riscv_cpu_fp_enabled(env)) { - return -1; + return -RISCV_EXCP_ILLEGAL_INST; } env->mstatus |= MSTATUS_FS; #endif @@ -161,7 +218,7 @@ static int read_fcsr(CPURISCVState *env, int csrno, target_ulong *val) { #if !defined(CONFIG_USER_ONLY) if (!env->debugger && !riscv_cpu_fp_enabled(env)) { - return -1; + return -RISCV_EXCP_ILLEGAL_INST; } #endif *val = (riscv_cpu_get_fflags(env) << FSR_AEXC_SHIFT) @@ -177,7 +234,7 @@ static int write_fcsr(CPURISCVState *env, int csrno, target_ulong val) { #if !defined(CONFIG_USER_ONLY) if (!env->debugger && !riscv_cpu_fp_enabled(env)) { - return -1; + return -RISCV_EXCP_ILLEGAL_INST; } env->mstatus |= MSTATUS_FS; #endif @@ -291,7 +348,7 @@ 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; + return -RISCV_EXCP_ILLEGAL_INST; } *val = env->rdtime_fn() + delta; @@ -304,7 +361,7 @@ 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; + return -RISCV_EXCP_ILLEGAL_INST; } *val = (env->rdtime_fn() + delta) >> 32; @@ -340,6 +397,7 @@ static const target_ulong delegable_excps = (1ULL << (RISCV_EXCP_STORE_PAGE_FAULT)) | (1ULL << (RISCV_EXCP_INST_GUEST_PAGE_FAULT)) | (1ULL << (RISCV_EXCP_LOAD_GUEST_ACCESS_FAULT)) | + (1ULL << (RISCV_EXCP_VIRT_INSTRUCTION_FAULT)) | (1ULL << (RISCV_EXCP_STORE_GUEST_AMO_ACCESS_FAULT)); static const target_ulong sstatus_v1_10_mask = SSTATUS_SIE | SSTATUS_SPIE | SSTATUS_UIE | SSTATUS_UPIE | SSTATUS_SPP | SSTATUS_FS | SSTATUS_XS | @@ -403,10 +461,10 @@ static int write_mstatus(CPURISCVState *env, int csrno, target_ulong val) MSTATUS_TW; #if defined(TARGET_RISCV64) /* - * RV32: MPV and MTL are not in mstatus. The current plan is to + * RV32: MPV and GVA are not in mstatus. The current plan is to * add them to mstatush. For now, we just don't support it. */ - mask |= MSTATUS_MTL | MSTATUS_MPV; + mask |= MSTATUS_MPV | MSTATUS_GVA; #endif mstatus = (mstatus & ~mask) | (val & mask); @@ -432,7 +490,7 @@ static int write_mstatush(CPURISCVState *env, int csrno, target_ulong val) tlb_flush(env_cpu(env)); } - val &= MSTATUS_MPV | MSTATUS_MTL; + val &= MSTATUS_MPV | MSTATUS_GVA; env->mstatush = val; @@ -570,7 +628,7 @@ static int write_mcounteren(CPURISCVState *env, int csrno, target_ulong val) static int read_mscounteren(CPURISCVState *env, int csrno, target_ulong *val) { if (env->priv_ver < PRIV_VERSION_1_11_0) { - return -1; + return -RISCV_EXCP_ILLEGAL_INST; } *val = env->mcounteren; return 0; @@ -580,7 +638,7 @@ static int read_mscounteren(CPURISCVState *env, int csrno, target_ulong *val) static int write_mscounteren(CPURISCVState *env, int csrno, target_ulong val) { if (env->priv_ver < PRIV_VERSION_1_11_0) { - return -1; + return -RISCV_EXCP_ILLEGAL_INST; } env->mcounteren = val; return 0; @@ -804,7 +862,7 @@ static int read_satp(CPURISCVState *env, int csrno, target_ulong *val) } if (env->priv == PRV_S && get_field(env->mstatus, MSTATUS_TVM)) { - return -1; + return -RISCV_EXCP_ILLEGAL_INST; } else { *val = env->satp; } @@ -821,7 +879,7 @@ static int write_satp(CPURISCVState *env, int csrno, target_ulong val) ((val ^ env->satp) & (SATP_MODE | SATP_ASID | SATP_PPN))) { if (env->priv == PRV_S && get_field(env->mstatus, MSTATUS_TVM)) { - return -1; + return -RISCV_EXCP_ILLEGAL_INST; } else { if((val ^ env->satp) & SATP_ASID) { tlb_flush(env_cpu(env)); @@ -836,12 +894,26 @@ static int write_satp(CPURISCVState *env, int csrno, target_ulong val) static int read_hstatus(CPURISCVState *env, int csrno, target_ulong *val) { *val = env->hstatus; +#ifdef TARGET_RISCV64 + /* We only support 64-bit VSXL */ + *val = set_field(*val, HSTATUS_VSXL, 2); +#endif + /* We only support little endian */ + *val = set_field(*val, HSTATUS_VSBE, 0); return 0; } static int write_hstatus(CPURISCVState *env, int csrno, target_ulong val) { env->hstatus = val; +#ifdef TARGET_RISCV64 + if (get_field(val, HSTATUS_VSXL) != 2) { + qemu_log_mask(LOG_UNIMP, "QEMU does not support mixed HSXLEN options."); + } +#endif + if (get_field(val, HSTATUS_VSBE) != 0) { + qemu_log_mask(LOG_UNIMP, "QEMU does not support big endian guests."); + } return 0; } @@ -869,12 +941,25 @@ static int write_hideleg(CPURISCVState *env, int csrno, target_ulong val) return 0; } +static int rmw_hvip(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); + + *ret_value &= hip_writable_mask; + + return ret; +} + 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); + *ret_value &= hip_writable_mask; + return ret; } @@ -902,6 +987,18 @@ static int write_hcounteren(CPURISCVState *env, int csrno, target_ulong val) return 0; } +static int read_hgeie(CPURISCVState *env, int csrno, target_ulong *val) +{ + qemu_log_mask(LOG_UNIMP, "No support for a non-zero GEILEN."); + return 0; +} + +static int write_hgeie(CPURISCVState *env, int csrno, target_ulong val) +{ + qemu_log_mask(LOG_UNIMP, "No support for a non-zero GEILEN."); + return 0; +} + static int read_htval(CPURISCVState *env, int csrno, target_ulong *val) { *val = env->htval; @@ -922,7 +1019,18 @@ static int read_htinst(CPURISCVState *env, int csrno, target_ulong *val) static int write_htinst(CPURISCVState *env, int csrno, target_ulong val) { - env->htinst = val; + return 0; +} + +static int read_hgeip(CPURISCVState *env, int csrno, target_ulong *val) +{ + qemu_log_mask(LOG_UNIMP, "No support for a non-zero GEILEN."); + return 0; +} + +static int write_hgeip(CPURISCVState *env, int csrno, target_ulong val) +{ + qemu_log_mask(LOG_UNIMP, "No support for a non-zero GEILEN."); return 0; } @@ -941,7 +1049,7 @@ static int write_hgatp(CPURISCVState *env, int csrno, target_ulong val) static int read_htimedelta(CPURISCVState *env, int csrno, target_ulong *val) { if (!env->rdtime_fn) { - return -1; + return -RISCV_EXCP_ILLEGAL_INST; } #if defined(TARGET_RISCV32) @@ -955,7 +1063,7 @@ static int read_htimedelta(CPURISCVState *env, int csrno, target_ulong *val) static int write_htimedelta(CPURISCVState *env, int csrno, target_ulong val) { if (!env->rdtime_fn) { - return -1; + return -RISCV_EXCP_ILLEGAL_INST; } #if defined(TARGET_RISCV32) @@ -970,7 +1078,7 @@ static int write_htimedelta(CPURISCVState *env, int csrno, target_ulong val) static int read_htimedeltah(CPURISCVState *env, int csrno, target_ulong *val) { if (!env->rdtime_fn) { - return -1; + return -RISCV_EXCP_ILLEGAL_INST; } *val = env->htimedelta >> 32; @@ -980,7 +1088,7 @@ static int read_htimedeltah(CPURISCVState *env, int csrno, target_ulong *val) static int write_htimedeltah(CPURISCVState *env, int csrno, target_ulong val) { if (!env->rdtime_fn) { - return -1; + return -RISCV_EXCP_ILLEGAL_INST; } env->htimedelta = deposit64(env->htimedelta, 32, 32, (uint64_t)val); @@ -1178,18 +1286,22 @@ int riscv_csrrw(CPURISCVState *env, int csrno, target_ulong *ret_value, if ((write_mask && read_only) || (!env->debugger && (effective_priv < get_field(csrno, 0x300)))) { - return -1; + return -RISCV_EXCP_ILLEGAL_INST; } #endif /* ensure the CSR extension is enabled. */ if (!cpu->cfg.ext_icsr) { - return -1; + return -RISCV_EXCP_ILLEGAL_INST; } /* check predicate */ - if (!csr_ops[csrno].predicate || csr_ops[csrno].predicate(env, csrno) < 0) { - return -1; + if (!csr_ops[csrno].predicate) { + return -RISCV_EXCP_ILLEGAL_INST; + } + ret = csr_ops[csrno].predicate(env, csrno); + if (ret < 0) { + return ret; } /* execute combined read/write operation if it exists */ @@ -1199,7 +1311,7 @@ int riscv_csrrw(CPURISCVState *env, int csrno, target_ulong *ret_value, /* if no accessor exists then return failure */ if (!csr_ops[csrno].read) { - return -1; + return -RISCV_EXCP_ILLEGAL_INST; } /* read old value */ @@ -1328,11 +1440,14 @@ static riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = { [CSR_HSTATUS] = { hmode, read_hstatus, write_hstatus }, [CSR_HEDELEG] = { hmode, read_hedeleg, write_hedeleg }, [CSR_HIDELEG] = { hmode, read_hideleg, write_hideleg }, + [CSR_HVIP] = { hmode, NULL, NULL, rmw_hvip }, [CSR_HIP] = { hmode, NULL, NULL, rmw_hip }, [CSR_HIE] = { hmode, read_hie, write_hie }, [CSR_HCOUNTEREN] = { hmode, read_hcounteren, write_hcounteren }, + [CSR_HGEIE] = { hmode, read_hgeie, write_hgeie }, [CSR_HTVAL] = { hmode, read_htval, write_htval }, [CSR_HTINST] = { hmode, read_htinst, write_htinst }, + [CSR_HGEIP] = { hmode, read_hgeip, write_hgeip }, [CSR_HGATP] = { hmode, read_hgatp, write_hgatp }, [CSR_HTIMEDELTA] = { hmode, read_htimedelta, write_htimedelta }, #if defined(TARGET_RISCV32) |