write_misa() must use as much common logic as possible. We want to open
code just 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 realize(): validate the candidate misa_ext
val, then validate the configuration with the candidate misa_ext val,
and finally commit the changes to cpu->cfg.
If any of the validation steps fails simply ignore the write operation.
Let's keep write_misa() as experimental for now until this logic gains
enough mileage.
Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
---
target/riscv/cpu.c | 12 +++++-------
target/riscv/cpu.h | 6 ++++++
target/riscv/csr.c | 47 +++++++++++++++++++++-------------------------
3 files changed, 32 insertions(+), 33 deletions(-)
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 5bd92e1cda..4789a7b70d 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -1027,9 +1027,8 @@ static void riscv_cpu_disable_priv_spec_isa_exts(RISCVCPU
*cpu)
}
-static void riscv_cpu_validate_misa_ext(CPURISCVState *env,
- uint32_t misa_ext,
- Error **errp)
+void riscv_cpu_validate_misa_ext(CPURISCVState *env, uint32_t misa_ext,
+ Error **errp)
{
Error *local_err = NULL;
@@ -1134,9 +1133,8 @@ static void riscv_cpu_validate_misa_mxl(RISCVCPU *cpu,
Error **errp)
* candidate misa_ext value. No changes in env->misa_ext
* are made.
*/
-static void riscv_cpu_validate_extensions(RISCVCPU *cpu,
- uint32_t misa_ext,
- Error **errp)
+void riscv_cpu_validate_extensions(RISCVCPU *cpu, uint32_t misa_ext,
+ Error **errp)
{
if (cpu->cfg.epmp && !cpu->cfg.pmp) {
/*
@@ -1227,7 +1225,7 @@ static void riscv_cpu_validate_extensions(RISCVCPU *cpu,
}
}
-static void riscv_cpu_commit_cpu_cfg(RISCVCPU *cpu)
+void riscv_cpu_commit_cpu_cfg(RISCVCPU *cpu)
{
if (cpu->cfg.ext_zk) {
cpu->cfg.ext_zkn = true;
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index dbb4df9df0..ca2ba6a647 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -593,6 +593,12 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int
size,
char *riscv_isa_string(RISCVCPU *cpu);
void riscv_cpu_list(void);
+void riscv_cpu_validate_misa_ext(CPURISCVState *env, uint32_t misa_ext,
+ Error **errp);
+void riscv_cpu_validate_extensions(RISCVCPU *cpu, uint32_t misa_ext,
+ Error **errp);
+void riscv_cpu_commit_cpu_cfg(RISCVCPU *cpu);
+
#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 918d442ebd..6f26e7dbcd 100644
--- a/target/riscv/csr.c
+++ b/target/riscv/csr.c
@@ -1343,6 +1343,9 @@ static RISCVException read_misa(CPURISCVState *env, int
csrno,
static RISCVException write_misa(CPURISCVState *env, int csrno,
target_ulong val)
{
+ RISCVCPU *cpu = env_archcpu(env);
+ Error *local_err = NULL;
+
if (!riscv_cpu_cfg(env)->misa_w) {
/* drop write to misa */
return RISCV_EXCP_NONE;
@@ -1353,47 +1356,39 @@ 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.
+ * Suppress 'C' if next instruction is not aligned
+ * TODO: this should check next_pc
*/
+ if ((val & RVC) && (GETPC() & ~3) != 0) {
+ val &= ~RVC;
+ }
/* 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;
+ /* If nothing changed, do nothing. */
+ if (val == env->misa_ext) {
+ return RISCV_EXCP_NONE;
}
/*
- * Suppress 'C' if next instruction is not aligned
- * TODO: this should check next_pc
+ * This flow is similar to what riscv_cpu_realize() does,
+ * with the difference that we will update env->misa_ext
+ * value if everything is ok.
*/
- if ((val & RVC) && (GETPC() & ~3) != 0) {
- val &= ~RVC;
+ riscv_cpu_validate_misa_ext(env, val, &local_err);
+ if (local_err != NULL) {
+ return RISCV_EXCP_NONE;
}
- /* If nothing changed, do nothing. */
- if (val == env->misa_ext) {
+ riscv_cpu_validate_extensions(cpu, val, &local_err);
+ if (local_err != NULL) {
return RISCV_EXCP_NONE;
}
+ riscv_cpu_commit_cpu_cfg(cpu);
+