diff options
Diffstat (limited to 'target/riscv/csr.c')
-rw-r--r-- | target/riscv/csr.c | 75 |
1 files changed, 47 insertions, 28 deletions
diff --git a/target/riscv/csr.c b/target/riscv/csr.c index 4451bd1263..58499b5afc 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -82,6 +82,10 @@ static RISCVException fs(CPURISCVState *env, int csrno) !riscv_cpu_cfg(env)->ext_zfinx) { return RISCV_EXCP_ILLEGAL_INST; } + + if (!env->debugger && !riscv_cpu_fp_enabled(env)) { + return smstateen_acc_ok(env, 0, SMSTATEEN0_FCSR); + } #endif return RISCV_EXCP_NONE; } @@ -1324,8 +1328,15 @@ static RISCVException write_mstatus(CPURISCVState *env, int csrno, mstatus = set_field(mstatus, MSTATUS64_SXL, xl); } env->mstatus = mstatus; - env->xl = cpu_recompute_xl(env); + /* + * Except in debug mode, UXL/SXL can only be modified by higher + * privilege mode. So xl will not be changed in normal mode. + */ + if (env->debugger) { + env->xl = cpu_recompute_xl(env); + riscv_cpu_update_mask(env); + } return RISCV_EXCP_NONE; } @@ -1387,39 +1398,18 @@ static RISCVException read_misa(CPURISCVState *env, int csrno, static RISCVException write_misa(CPURISCVState *env, int csrno, target_ulong val) { + RISCVCPU *cpu = env_archcpu(env); + uint32_t orig_misa_ext = env->misa_ext; + Error *local_err = NULL; + if (!riscv_cpu_cfg(env)->misa_w) { /* drop write to misa */ return RISCV_EXCP_NONE; } - /* 'I' or 'E' must be present */ - if (!(val & (RVI | RVE))) { - /* It is not, drop write to misa */ - return RISCV_EXCP_NONE; - } - - /* 'E' excludes all other extensions */ - if (val & RVE) { - /* - * when we support 'E' we can do "val = RVE;" however - * for now we just drop writes if 'E' is present. - */ - return RISCV_EXCP_NONE; - } - - /* - * misa.MXL writes are not supported by QEMU. - * Drop writes to those bits. - */ - /* Mask extensions that are not supported by this hart */ val &= env->misa_ext_mask; - /* 'D' depends on 'F', so clear 'D' if 'F' is not present */ - if ((val & RVD) && !(val & RVF)) { - val &= ~RVD; - } - /* * Suppress 'C' if next instruction is not aligned * TODO: this should check next_pc @@ -1428,18 +1418,36 @@ static RISCVException write_misa(CPURISCVState *env, int csrno, val &= ~RVC; } + /* Disable RVG if any of its dependencies are disabled */ + if (!(val & RVI && val & RVM && val & RVA && + val & RVF && val & RVD)) { + val &= ~RVG; + } + /* If nothing changed, do nothing. */ if (val == env->misa_ext) { return RISCV_EXCP_NONE; } - if (!(val & RVF)) { + env->misa_ext = val; + riscv_cpu_validate_set_extensions(cpu, &local_err); + if (local_err != NULL) { + /* Rollback on validation error */ + qemu_log_mask(LOG_GUEST_ERROR, "Unable to write MISA ext value " + "0x%x, keeping existing MISA ext 0x%x\n", + env->misa_ext, orig_misa_ext); + + env->misa_ext = orig_misa_ext; + + return RISCV_EXCP_NONE; + } + + if (!(env->misa_ext & RVF)) { env->mstatus &= ~MSTATUS_FS; } /* flush translation cache */ tb_flush(env_cpu(env)); - env->misa_ext = val; env->xl = riscv_cpu_mxl(env); return RISCV_EXCP_NONE; } @@ -2100,6 +2108,9 @@ static RISCVException write_mstateen0(CPURISCVState *env, int csrno, target_ulong new_val) { uint64_t wr_mask = SMSTATEEN_STATEEN | SMSTATEEN0_HSENVCFG; + if (!riscv_has_ext(env, RVF)) { + wr_mask |= SMSTATEEN0_FCSR; + } return write_mstateen(env, csrno, wr_mask, new_val); } @@ -2173,6 +2184,10 @@ static RISCVException write_hstateen0(CPURISCVState *env, int csrno, { uint64_t wr_mask = SMSTATEEN_STATEEN | SMSTATEEN0_HSENVCFG; + if (!riscv_has_ext(env, RVF)) { + wr_mask |= SMSTATEEN0_FCSR; + } + return write_hstateen(env, csrno, wr_mask, new_val); } @@ -2259,6 +2274,10 @@ static RISCVException write_sstateen0(CPURISCVState *env, int csrno, { uint64_t wr_mask = SMSTATEEN_STATEEN | SMSTATEEN0_HSENVCFG; + if (!riscv_has_ext(env, RVF)) { + wr_mask |= SMSTATEEN0_FCSR; + } + return write_sstateen(env, csrno, wr_mask, new_val); } |