write_misa() must use as much common logic as possible, only specifying
the bits that are exclusive to the CSR write operation and TCG
internals.

Rewrite write_misa() to work as follows:

- supress RVC right after verifying that we're not updating RVG;

- mask the write using misa_ext_mask to avoid enabling unsupported
  extensions;

- emulate the steps done by the cpu init() functions: set cpu->cfg using
  the desired misa value, validate it, and then commit;

- fallback if the validation step fails. We'll need to re-write cpu->cfg
  with the original misa_ext value for the hart.

Let's keep write_misa() as experimental for now until this logic gains
enough mileage.

Signed-off-by: Daniel Henrique Barboza <dbarb...@ventanamicro.com>
---
 target/riscv/cpu.c |  7 +++---
 target/riscv/cpu.h |  2 ++
 target/riscv/csr.c | 53 +++++++++++++++++++++-------------------------
 3 files changed, 29 insertions(+), 33 deletions(-)

diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 7be6a86305..4b2be32de3 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -281,8 +281,7 @@ static uint32_t 
riscv_get_misa_ext_with_cpucfg(RISCVCPUConfig *cfg)
     return ext;
 }
 
-static void riscv_set_cpucfg_with_misa(RISCVCPUConfig *cfg,
-                                       uint32_t misa_ext)
+static void riscv_set_cpucfg_with_misa(RISCVCPUConfig *cfg, uint32_t misa_ext)
 {
     cfg->ext_i = misa_ext & RVI;
     cfg->ext_e = misa_ext & RVE;
@@ -299,7 +298,7 @@ static void riscv_set_cpucfg_with_misa(RISCVCPUConfig *cfg,
     cfg->ext_g = misa_ext & RVG;
 }
 
-static void set_misa(CPURISCVState *env, RISCVMXL mxl, uint32_t ext)
+void set_misa(CPURISCVState *env, RISCVMXL mxl, uint32_t ext)
 {
     env->misa_mxl_max = env->misa_mxl = mxl;
     env->misa_ext_mask = env->misa_ext = ext;
@@ -995,7 +994,7 @@ static void riscv_cpu_disable_priv_spec_isa_exts(RISCVCPU 
*cpu)
  * Check consistency between chosen extensions while setting
  * cpu->cfg accordingly, doing a set_misa() in the end.
  */
-static void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, Error **errp)
+void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, Error **errp)
 {
     RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(cpu);
     CPUClass *cc = CPU_CLASS(mcc);
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 013a1389d6..d64d0f8dd6 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -591,6 +591,8 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int 
size,
                         bool probe, uintptr_t retaddr);
 char *riscv_isa_string(RISCVCPU *cpu);
 void riscv_cpu_list(void);
+void set_misa(CPURISCVState *env, RISCVMXL mxl, uint32_t ext);
+void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, Error **errp);
 
 #define cpu_list riscv_cpu_list
 #define cpu_mmu_index riscv_cpu_mmu_index
diff --git a/target/riscv/csr.c b/target/riscv/csr.c
index 02a5c2a5ca..2e75c75fcc 100644
--- a/target/riscv/csr.c
+++ b/target/riscv/csr.c
@@ -1342,6 +1342,11 @@ 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 hart_ext_mask = env->misa_ext_mask;
+    uint32_t hart_ext = env->misa_ext;
+    Error *local_err = NULL;
+
     if (!riscv_cpu_cfg(env)->misa_w) {
         /* drop write to misa */
         return RISCV_EXCP_NONE;
@@ -1352,34 +1357,6 @@ static RISCVException write_misa(CPURISCVState *env, int 
csrno,
         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
@@ -1388,18 +1365,36 @@ static RISCVException write_misa(CPURISCVState *env, 
int csrno,
         val &= ~RVC;
     }
 
+    /* Mask extensions that are not supported by this hart */
+    val &= hart_ext_mask;
+
     /* If nothing changed, do nothing. */
     if (val == env->misa_ext) {
         return RISCV_EXCP_NONE;
     }
 
+    /*
+     * Validate the new configuration. Rollback to previous
+     * values if something goes wrong.
+     */
+    set_misa(env, env->misa_mxl, val);
+    riscv_cpu_validate_set_extensions(cpu, &local_err);
+    if (local_err) {
+        set_misa(env, env->misa_mxl, hart_ext);
+        return RISCV_EXCP_NONE;
+    }
+
+    /*
+     * Keep the original misa_ext_mask from the hart.
+     */
+    env->misa_ext_mask = hart_ext_mask;
+
     if (!(val & 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;
 }
-- 
2.39.2


Reply via email to