We should write transformed instruction encoding of the trapped
instruction in [m|h]tinst CSR at time of taking trap as defined
by the RISC-V privileged specification v1.12.
Reviewed-by: Alistair Francis
Signed-off-by: Anup Patel
---
target/riscv/cpu.h| 5 +
target/riscv/cpu_helper.c | 252 +-
target/riscv/instmap.h| 45 +++
3 files changed, 296 insertions(+), 6 deletions(-)
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 5c7acc055a..ffb1a18873 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -285,6 +285,11 @@ struct CPUArchState {
/* Signals whether the current exception occurred with two-stage address
translation active. */
bool two_stage_lookup;
+/*
+ * Signals whether the current exception occurred while doing two-stage
+ * address translation for the VS-stage page table walk.
+ */
+bool two_stage_indirect_lookup;
target_ulong scounteren;
target_ulong mcounteren;
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index be28615e23..c59cfddac2 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -22,6 +22,7 @@
#include "qemu/main-loop.h"
#include "cpu.h"
#include "exec/exec-all.h"
+#include "instmap.h"
#include "tcg/tcg-op.h"
#include "trace.h"
#include "semihosting/common-semi.h"
@@ -1057,7 +1058,8 @@ restart:
static void raise_mmu_exception(CPURISCVState *env, target_ulong address,
MMUAccessType access_type, bool pmp_violation,
-bool first_stage, bool two_stage)
+bool first_stage, bool two_stage,
+bool two_stage_indirect)
{
CPUState *cs = env_cpu(env);
int page_fault_exceptions, vm;
@@ -1107,6 +1109,7 @@ static void raise_mmu_exception(CPURISCVState *env,
target_ulong address,
}
env->badaddr = address;
env->two_stage_lookup = two_stage;
+env->two_stage_indirect_lookup = two_stage_indirect;
}
hwaddr riscv_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
@@ -1152,6 +1155,7 @@ void riscv_cpu_do_transaction_failed(CPUState *cs, hwaddr
physaddr,
env->badaddr = addr;
env->two_stage_lookup = riscv_cpu_virt_enabled(env) ||
riscv_cpu_two_stage_lookup(mmu_idx);
+env->two_stage_indirect_lookup = false;
cpu_loop_exit_restore(cs, retaddr);
}
@@ -1177,6 +1181,7 @@ void riscv_cpu_do_unaligned_access(CPUState *cs, vaddr
addr,
env->badaddr = addr;
env->two_stage_lookup = riscv_cpu_virt_enabled(env) ||
riscv_cpu_two_stage_lookup(mmu_idx);
+env->two_stage_indirect_lookup = false;
cpu_loop_exit_restore(cs, retaddr);
}
@@ -1192,6 +1197,7 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int
size,
bool pmp_violation = false;
bool first_stage_error = true;
bool two_stage_lookup = false;
+bool two_stage_indirect_error = false;
int ret = TRANSLATE_FAIL;
int mode = mmu_idx;
/* default TLB page size */
@@ -1229,6 +1235,7 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int
size,
*/
if (ret == TRANSLATE_G_STAGE_FAIL) {
first_stage_error = false;
+two_stage_indirect_error = true;
access_type = MMU_DATA_LOAD;
}
@@ -1312,12 +1319,218 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address,
int size,
raise_mmu_exception(env, address, access_type, pmp_violation,
first_stage_error,
riscv_cpu_virt_enabled(env) ||
-riscv_cpu_two_stage_lookup(mmu_idx));
+riscv_cpu_two_stage_lookup(mmu_idx),
+two_stage_indirect_error);
cpu_loop_exit_restore(cs, retaddr);
}
return true;
}
+
+static target_ulong riscv_transformed_insn(CPURISCVState *env,
+ target_ulong insn,
+ target_ulong taddr)
+{
+target_ulong xinsn = 0;
+target_ulong access_rs1 = 0, access_imm = 0, access_size = 0;
+
+/*
+ * Only Quadrant 0 and Quadrant 2 of RVC instruction space need to
+ * be uncompressed. The Quadrant 1 of RVC instruction space need
+ * not be transformed because these instructions won't generate
+ * any load/store trap.
+ */
+
+if ((insn & 0x3) != 0x3) {
+/* Transform 16bit instruction into 32bit instruction */
+switch (GET_C_OP(insn)) {
+case OPC_RISC_C_OP_QUAD0: /* Quadrant 0 */
+switch (GET_C_FUNC(insn)) {
+case OPC_RISC_C_FUNC_FLD_LQ:
+if (riscv_cpu_xlen(env) != 128) { /* C.FLD (RV32/64) */
+xinsn = OPC_RISC_FLD;
+xinsn = SET_RD(xinsn, GET_C_RS2S(insn));
+access_rs1 = GET_C_RS1S(insn);
+