Add SMMPT system-test coverage for Smmpt34, the RV32-only memory
protection scheme (2-level MPT with 4-byte entries).
Smmpt34 requires a 32-bit CPU, but qemu-system-riscv64 can run a 32-bit
CPU (-cpu rv32), so the test lives in tests/tcg/riscv64 alongside the
RV64 Smmpt tests and shares the same harness (smmpt-common.S). It only
differs in the table geometry: 4-byte MPTEs, two radix levels, a 10-bit
level-0 index and the RV32 mmpt CSR layout (MODE in bits[31:30]). It
exercises the same permission and structural checks as the RV64 tests
(all XWR encodings for load and store, V=0 and reserved-bit leaves, and
NAPOT leaves with a valid and a reserved G field), using the same access
addresses. It is built for RV32 and run on qemu-system-riscv64 with
-cpu rv32.
Signed-off-by: LIU Zhiwei <zhiwei_liu@linux.alibaba.com>
---
tests/tcg/riscv64/test-smmpt34.S | 97 ++++++++++++++++++++++++++++++++
1 file changed, 97 insertions(+)
create mode 100644 tests/tcg/riscv64/test-smmpt34.S
diff --git a/tests/tcg/riscv64/test-smmpt34.S b/tests/tcg/riscv64/test-smmpt34.S
new file mode 100644
index 0000000000..92c8320999
--- /dev/null
+++ b/tests/tcg/riscv64/test-smmpt34.S
@@ -0,0 +1,97 @@
+/*
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * Test for the Smmpt34 (Supervisor Memory Protection Table) extension,
+ * per SMMTT specification v0.4.9. Smmpt34 is the RV32-only scheme.
+ *
+ * Although Smmpt34 requires a 32-bit CPU, the program is run on
+ * qemu-system-riscv64 with a 32-bit CPU (-cpu rv32), which lives in the
+ * same target as the RV64 Smmpt tests. It is therefore kept here in
+ * tests/tcg/riscv64 alongside the other Smmpt tests and shares the same
+ * harness (smmpt-common.S). Build it for RV32 and run it as:
+ *
+ * $CC -march=rv32ima_zicsr -mabi=ilp32 -I tests/tcg/riscv64 \
+ * tests/tcg/riscv64/test-smmpt34.S -Wa,--noexecstack -c -o smmpt34.o
+ * $LD -m elf32lriscv -T tests/tcg/riscv64/semihost.ld smmpt34.o -o smmpt34
+ * qemu-system-riscv64 -cpu rv32,x-smmpt=true -M virt -display none \
+ * -semihosting -device loader,file=smmpt34
+ *
+ * Smmpt34 uses a 2-level MPT with 4-byte entries (8 pages per leaf,
+ * pi = SPA[14:12]). The supervisor physical address is partitioned as
+ * pn[1] = SPA[33:25] (9-bit root index), pn[0] = SPA[24:15] (10-bit level-0
+ * index) and range offset SPA[14:0]. For the RAM addresses used here
+ * (0x8xxx_xxxx, < 4 GiB) pn[1] resolves to 64. See smmpt-common.S for the
+ * MPRV trick, the shared address layout and the exit-code convention.
+ *
+ * This test reuses the same shared harness and the same access addresses as
+ * the RV64 tests; only the table geometry (4-byte entries, 2 levels, 10-bit
+ * level-0 index) and the RV32 mmpt layout differ.
+ *
+ * MPT layout (Smmpt34, 2 levels, 4-byte entries):
+ *
+ * L1 (root) @ 0x8040_0000 : entry[64] -> non-leaf, PPN(L0)=0x80410
+ * L0 @ 0x8041_0000 :
+ * entry[160] -> non-NAPOT leaf (LEAF_ALL_XWR) covering 0x8050_0000+
+ * entry[162] -> V=0 (invalid) covering 0x8051_0000
+ * entry[164] -> leaf with a reserved bit set covering 0x8052_0000
+ * entry[192] -> NAPOT leaf, G=6, XWR=RW covering 0x8060_0000
+ * entry[256] -> NAPOT leaf, reserved G=0 covering 0x8080_0000
+ *
+ * mmpt = MODE(1=Smmpt34)<<30 | PPN(0x80400)
+ */
+
+#include "smmpt-common.S"
+
+ .option norvc
+
+ .text
+ .global _start
+_start:
+ /* Install the M-mode trap handler */
+ lla t0, mtrap
+ csrw mtvec, t0
+ csrw medeleg, zero
+
+ /* PMP entry 0: NAPOT covering the whole space, RWX. */
+ li t0, -1
+ csrw pmpaddr0, t0
+ li t0, 0x1f
+ csrw pmpcfg0, t0
+
+ /* Build the MPT tables (M-mode stores bypass the MPT). */
+ /* L1[64] = non-leaf -> L0 (PPN 0x80410): (0x80410 << 10) | V */
+ li t0, 0x80400000
+ li t1, 0x20104001
+ sw t1, 0x100(t0) /* 64 * 4 = 0x100 */
+
+ li t0, 0x80410000
+ /* L0[160] = non-NAPOT leaf carrying all XWR encodings (pi0..pi7) */
+ li t1, LEAF_ALL_XWR
+ sw t1, 0x280(t0) /* 160 * 4 = 0x280 */
+ /* L0[162] = 0: invalid entry (V=0) */
+ sw x0, 0x288(t0) /* 162 * 4 = 0x288 */
+ /* L0[164] = leaf with reserved bit 3 set (V|L|rsv|XWR[pi0]=RW) */
+ li t1, 0x30B
+ sw t1, 0x290(t0) /* 164 * 4 = 0x290 */
+ /* L0[192] = NAPOT leaf: V|L|N | XWR=RW(0x300) | G=6(0x6000) */
+ li t1, 0x6307
+ sw t1, 0x300(t0) /* 192 * 4 = 0x300 */
+ /* L0[256] = NAPOT leaf with reserved G=0: V|L|N | XWR=RW | G=0 */
+ li t1, 0x307
+ sw t1, 0x400(t0) /* 256 * 4 = 0x400 */
+
+ /* Program mmpt: MODE=1 (Smmpt34) at bits[31:30], PPN = 0x80400 */
+ li t0, 0x40080400
+ csrw 0x382, t0 /* CSR_MMPT */
+
+ /* mfence.pa must not fault in M-mode */
+ TEST_MFENCE_PA 1
+
+ /* Run the shared permission and structural checks */
+ RUN_LEAF_CHECKS
+
+ /* All tests passed */
+ li a0, 0
+ j _exit
+
+ SMMPT_HARNESS
--
2.43.0