helper_wrs_nto() may raise an illegal or virtual-instruction exception.
However, trans_wrs_nto() does not save the decoded opcode before calling
the helper. As a result, exception unwinding leaves env->bins stale and
trap handling reports an incorrect value in tval.

Call decode_save_opc() before the helper so the faulting instruction
encoding is restored for trap handling.

Add a TCG test that delegates the mstatus.TW-triggered illegal-instruction
exception to S-mode and checks scause, sepc and stval.

Fixes: b62e0ce76098 ("target/riscv: Raise exceptions on wrs.nto")
Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/4080
Signed-off-by: Zephyr Li <[email protected]>
---
 .../riscv/tcg/insn_trans/trans_rvzawrs.c.inc  |  2 +
 tests/tcg/riscv64/Makefile.softmmu-target     |  4 +
 tests/tcg/riscv64/test-zawrs-stval.S          | 87 +++++++++++++++++++
 3 files changed, 93 insertions(+)
 create mode 100644 tests/tcg/riscv64/test-zawrs-stval.S

diff --git a/target/riscv/tcg/insn_trans/trans_rvzawrs.c.inc 
b/target/riscv/tcg/insn_trans/trans_rvzawrs.c.inc
index 0eef033..ecebec0 100644
--- a/target/riscv/tcg/insn_trans/trans_rvzawrs.c.inc
+++ b/target/riscv/tcg/insn_trans/trans_rvzawrs.c.inc
@@ -54,6 +54,8 @@ static bool trans_wrs_nto(DisasContext *ctx, arg_wrs_nto *a)
      * exception, as handled by the wrs.nto helper.
      */
 #ifndef CONFIG_USER_ONLY
+    /* Save the opcode in case the helper raises an exception. */
+    decode_save_opc(ctx, 0);
     gen_helper_wrs_nto(tcg_env);
 #endif
 
diff --git a/tests/tcg/riscv64/Makefile.softmmu-target 
b/tests/tcg/riscv64/Makefile.softmmu-target
index 6a219c3..979df2c 100644
--- a/tests/tcg/riscv64/Makefile.softmmu-target
+++ b/tests/tcg/riscv64/Makefile.softmmu-target
@@ -20,6 +20,10 @@ EXTRA_RUNS += run-issue1060
 run-issue1060: issue1060
        $(call run-test, $<, $(QEMU) $(QEMU_OPTS)$<)
 
+EXTRA_RUNS += run-test-zawrs-stval
+run-test-zawrs-stval: test-zawrs-stval
+       $(call run-test, $<, $(QEMU) -cpu max $(QEMU_OPTS)$<)
+
 EXTRA_RUNS += run-test-mepc-masking
 run-test-mepc-masking: test-mepc-masking
        $(call run-test, $<, $(QEMU) $(QEMU_OPTS)$<)
diff --git a/tests/tcg/riscv64/test-zawrs-stval.S 
b/tests/tcg/riscv64/test-zawrs-stval.S
new file mode 100644
index 0000000..42a9901
--- /dev/null
+++ b/tests/tcg/riscv64/test-zawrs-stval.S
@@ -0,0 +1,87 @@
+/*
+ * Test that WRS.NTO writes the instruction encoding to stval when
+ * mstatus.TW causes an illegal-instruction exception in S-mode.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+       .option norvc
+
+       .text
+       .global _start
+_start:
+       /* Unexpected traps to M-mode fail the test. */
+       lla     t0, machine_trap
+       csrw    mtvec, t0
+
+       /* Delegate illegal-instruction exceptions to S-mode. */
+       li      t0, 1 << 2
+       csrs    medeleg, t0
+
+       lla     t0, supervisor_trap
+       csrw    stvec, t0
+
+       /* Give S-mode read, write and execute access to all memory. */
+       li      t0, -1
+       csrw    pmpaddr0, t0
+       li      t0, 0xf
+       csrw    pmpcfg0, t0
+
+       /* Set mstatus.TW and select S-mode for mret. */
+       li      t0, 3 << 11
+       csrc    mstatus, t0
+       li      t0, (1 << 21) | (1 << 11)
+       csrs    mstatus, t0
+
+       lla     t0, supervisor_start
+       csrw    mepc, t0
+       mret
+
+supervisor_start:
+       /* WRS.NTO must trap because mstatus.TW is set. */
+       li      a0, 1
+wrs_nto:
+       .word   0x00d00073
+       j       _exit
+
+machine_trap:
+       li      a0, 2
+       j       _exit
+
+supervisor_trap:
+       li      a0, 3
+
+       csrr    t0, scause
+       li      t1, 2
+       bne     t0, t1, _exit
+
+       csrr    t0, sepc
+       lla     t1, wrs_nto
+       bne     t0, t1, _exit
+
+       csrr    t1, stval
+       lwu     t2, 0(t0)
+       bne     t1, t2, _exit
+       li      t2, 0x00d00073
+       bne     t1, t2, _exit
+
+       li      a0, 0
+
+_exit:
+       lla     a1, semiargs
+       li      t0, 0x20026     /* ADP_Stopped_ApplicationExit */
+       sd      t0, 0(a1)
+       sd      a0, 8(a1)
+       li      a0, 0x20        /* TARGET_SYS_EXIT_EXTENDED */
+
+       /* Semihosting call sequence. */
+       .balign 16
+       slli    zero, zero, 0x1f
+       ebreak
+       srai    zero, zero, 0x7
+       j       .
+
+       .data
+       .balign 16
+semiargs:
+       .space  16
-- 
2.43.0


Reply via email to