Add a regression test to verify that MEPC properly masks the lower
bits when an address with mode bits is written to it, as required by
the RISC-V Privileged Architecture specification.
The test sets STVEC to an address with bit 0 set (vectored mode),
triggers an illegal instruction exception, copies STVEC to MEPC in the
trap handler, and verifies that MEPC masks bits [1:0] correctly for
IALIGN=32.
Without the fix, MEPC retains the mode bits (returns non-zero/FAIL).
With the fix, MEPC clears bits [1:0] (returns 0/PASS).
Signed-off-by: Charalampos Mitrodimas <charmitro@posteo.net>
---
tests/tcg/riscv64/Makefile.softmmu-target | 4 ++
tests/tcg/riscv64/test-mepc-masking.S | 73 +++++++++++++++++++++++
2 files changed, 77 insertions(+)
create mode 100644 tests/tcg/riscv64/test-mepc-masking.S
diff --git a/tests/tcg/riscv64/Makefile.softmmu-target b/tests/tcg/riscv64/Makefile.softmmu-target
index 7c1d44d3f4..3ca595335d 100644
--- a/tests/tcg/riscv64/Makefile.softmmu-target
+++ b/tests/tcg/riscv64/Makefile.softmmu-target
@@ -20,5 +20,9 @@ EXTRA_RUNS += run-issue1060
run-issue1060: issue1060
$(call run-test, $<, $(QEMU) $(QEMU_OPTS)$<)
+EXTRA_RUNS += run-test-mepc-masking
+run-test-mepc-masking: test-mepc-masking
+ $(call run-test, $<, $(QEMU) $(QEMU_OPTS)$<)
+
# We don't currently support the multiarch system tests
undefine MULTIARCH_TESTS
diff --git a/tests/tcg/riscv64/test-mepc-masking.S b/tests/tcg/riscv64/test-mepc-masking.S
new file mode 100644
index 0000000000..fccd2a7ac4
--- /dev/null
+++ b/tests/tcg/riscv64/test-mepc-masking.S
@@ -0,0 +1,73 @@
+/*
+ * Test for MEPC masking bug fix
+ *
+ * This test verifies that MEPC properly masks the lower bits according
+ * to the RISC-V specification when vectored mode bits from STVEC are
+ * written to MEPC.
+ */
+
+ .option norvc
+
+ .text
+ .global _start
+_start:
+ /* Set up machine trap vector */
+ lla t0, machine_trap_handler
+ csrw mtvec, t0
+
+ /* Set STVEC with vectored mode (mode bits = 01) */
+ li t0, 0x80004001
+ csrw stvec, t0
+
+ /* Clear medeleg to handle exceptions in M-mode */
+ csrw medeleg, zero
+
+ /* Trigger illegal instruction exception */
+ .word 0xffffffff
+
+test_completed:
+ /* Exit with result in a0 */
+ /* a0 = 0: success (bits [1:0] were masked) */
+ /* a0 != 0: failure (some bits were not masked) */
+ j _exit
+
+machine_trap_handler:
+ /* Check if illegal instruction (mcause = 2) */
+ csrr t0, mcause
+ li t1, 2
+ bne t0, t1, skip_test
+
+ /* Test: Copy STVEC (with mode bits) to MEPC */
+ csrr t0, stvec /* t0 = 0x80004001 */
+ csrw mepc, t0 /* Write to MEPC */
+ csrr t1, mepc /* Read back MEPC */
+
+ /* Check if bits [1:0] are masked (IALIGN=32 without RVC) */
+ andi a0, t1, 3 /* a0 = 0 if both bits masked correctly */
+
+ /* Set correct return address */
+ lla t0, test_completed
+ csrw mepc, t0
+
+skip_test:
+ mret
+
+/* Exit with semihosting */
+_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 8
+semiargs:
+ .space 16
--
2.47.2
On 7/3/25 3:21 PM, Charalampos Mitrodimas wrote: > Add a regression test to verify that MEPC properly masks the lower > bits when an address with mode bits is written to it, as required by > the RISC-V Privileged Architecture specification. > > The test sets STVEC to an address with bit 0 set (vectored mode), > triggers an illegal instruction exception, copies STVEC to MEPC in the > trap handler, and verifies that MEPC masks bits [1:0] correctly for > IALIGN=32. > > Without the fix, MEPC retains the mode bits (returns non-zero/FAIL). > With the fix, MEPC clears bits [1:0] (returns 0/PASS). > > Signed-off-by: Charalampos Mitrodimas <charmitro@posteo.net> > --- The additional test is appreciated. Thanks! Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> > tests/tcg/riscv64/Makefile.softmmu-target | 4 ++ > tests/tcg/riscv64/test-mepc-masking.S | 73 +++++++++++++++++++++++ > 2 files changed, 77 insertions(+) > create mode 100644 tests/tcg/riscv64/test-mepc-masking.S > > diff --git a/tests/tcg/riscv64/Makefile.softmmu-target b/tests/tcg/riscv64/Makefile.softmmu-target > index 7c1d44d3f4..3ca595335d 100644 > --- a/tests/tcg/riscv64/Makefile.softmmu-target > +++ b/tests/tcg/riscv64/Makefile.softmmu-target > @@ -20,5 +20,9 @@ EXTRA_RUNS += run-issue1060 > run-issue1060: issue1060 > $(call run-test, $<, $(QEMU) $(QEMU_OPTS)$<) > > +EXTRA_RUNS += run-test-mepc-masking > +run-test-mepc-masking: test-mepc-masking > + $(call run-test, $<, $(QEMU) $(QEMU_OPTS)$<) > + > # We don't currently support the multiarch system tests > undefine MULTIARCH_TESTS > diff --git a/tests/tcg/riscv64/test-mepc-masking.S b/tests/tcg/riscv64/test-mepc-masking.S > new file mode 100644 > index 0000000000..fccd2a7ac4 > --- /dev/null > +++ b/tests/tcg/riscv64/test-mepc-masking.S > @@ -0,0 +1,73 @@ > +/* > + * Test for MEPC masking bug fix > + * > + * This test verifies that MEPC properly masks the lower bits according > + * to the RISC-V specification when vectored mode bits from STVEC are > + * written to MEPC. > + */ > + > + .option norvc > + > + .text > + .global _start > +_start: > + /* Set up machine trap vector */ > + lla t0, machine_trap_handler > + csrw mtvec, t0 > + > + /* Set STVEC with vectored mode (mode bits = 01) */ > + li t0, 0x80004001 > + csrw stvec, t0 > + > + /* Clear medeleg to handle exceptions in M-mode */ > + csrw medeleg, zero > + > + /* Trigger illegal instruction exception */ > + .word 0xffffffff > + > +test_completed: > + /* Exit with result in a0 */ > + /* a0 = 0: success (bits [1:0] were masked) */ > + /* a0 != 0: failure (some bits were not masked) */ > + j _exit > + > +machine_trap_handler: > + /* Check if illegal instruction (mcause = 2) */ > + csrr t0, mcause > + li t1, 2 > + bne t0, t1, skip_test > + > + /* Test: Copy STVEC (with mode bits) to MEPC */ > + csrr t0, stvec /* t0 = 0x80004001 */ > + csrw mepc, t0 /* Write to MEPC */ > + csrr t1, mepc /* Read back MEPC */ > + > + /* Check if bits [1:0] are masked (IALIGN=32 without RVC) */ > + andi a0, t1, 3 /* a0 = 0 if both bits masked correctly */ > + > + /* Set correct return address */ > + lla t0, test_completed > + csrw mepc, t0 > + > +skip_test: > + mret > + > +/* Exit with semihosting */ > +_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 8 > +semiargs: > + .space 16
© 2016 - 2026 Red Hat, Inc.