Extend the SMMPT system-test coverage to the two larger RV64 memory
protection schemes: Smmpt52 (4-level MPT, 52-bit SPA) and Smmpt64
(5-level MPT, 64-bit SPA with a 32 KiB / 32 KiB-aligned root table).
Both tests reuse the mode-independent harness in smmpt-common.S and only
differ in the number of radix levels and, for Smmpt64, the root-table
size and alignment. They exercise the same permission and structural
checks (all XWR encodings for load and store, V=0 and reserved-bit
leaves, and NAPOT leaves with a valid and a reserved G field) and are
wired into the Makefile as run-test-smmpt52 and run-test-smmpt64.
Signed-off-by: LIU Zhiwei <zhiwei_liu@linux.alibaba.com>
---
tests/tcg/riscv64/Makefile.softmmu-target | 8 ++
tests/tcg/riscv64/test-smmpt52.S | 91 +++++++++++++++++++++
tests/tcg/riscv64/test-smmpt64.S | 98 +++++++++++++++++++++++
3 files changed, 197 insertions(+)
create mode 100644 tests/tcg/riscv64/test-smmpt52.S
create mode 100644 tests/tcg/riscv64/test-smmpt64.S
diff --git a/tests/tcg/riscv64/Makefile.softmmu-target b/tests/tcg/riscv64/Makefile.softmmu-target
index 18da9c6299..6bbec02ed2 100644
--- a/tests/tcg/riscv64/Makefile.softmmu-target
+++ b/tests/tcg/riscv64/Makefile.softmmu-target
@@ -45,5 +45,13 @@ EXTRA_RUNS += run-test-smmpt
run-test-smmpt: test-smmpt
$(call run-test, $<, $(QEMU) -cpu rv64$(comma)x-smmpt=true $(QEMU_OPTS)$<)
+EXTRA_RUNS += run-test-smmpt52
+run-test-smmpt52: test-smmpt52
+ $(call run-test, $<, $(QEMU) -cpu rv64$(comma)x-smmpt=true $(QEMU_OPTS)$<)
+
+EXTRA_RUNS += run-test-smmpt64
+run-test-smmpt64: test-smmpt64
+ $(call run-test, $<, $(QEMU) -cpu rv64$(comma)x-smmpt=true $(QEMU_OPTS)$<)
+
# We don't currently support the multiarch system tests
undefine MULTIARCH_TESTS
diff --git a/tests/tcg/riscv64/test-smmpt52.S b/tests/tcg/riscv64/test-smmpt52.S
new file mode 100644
index 0000000000..445ba50d22
--- /dev/null
+++ b/tests/tcg/riscv64/test-smmpt52.S
@@ -0,0 +1,91 @@
+/*
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * Test for the Smmpt52 (Supervisor Memory Protection Table) extension,
+ * per SMMTT specification v0.4.9.
+ *
+ * Smmpt52 uses a 4-level MPT with 8-byte entries (16 pages per leaf,
+ * pi = SPA[15:12], pn[i] 9 bits at SPA[16 + i*9 +: 9]). It shares the MPTE
+ * formats and the permission-lookup algorithm with Smmpt43, only adding one
+ * more radix level. See smmpt-common.S for the MPRV trick, the shared
+ * address layout and the exit-code convention.
+ *
+ * For the low (< 4 GiB) addresses exercised here pn[3] and pn[2] are 0, so
+ * the upper levels are single-entry chains:
+ *
+ * L3 (root) @ 0x8040_0000 : entry[0] -> non-leaf, PPN(L2)=0x80410
+ * L2 @ 0x8041_0000 : entry[0] -> non-leaf, PPN(L1)=0x80420
+ * L1 @ 0x8042_0000 : entry[64] -> non-leaf, PPN(L0)=0x80430
+ * L0 @ 0x8043_0000 :
+ * entry[80] -> non-NAPOT leaf (LEAF_ALL_XWR) covering 0x8050_0000+
+ * entry[81] -> V=0 (invalid) covering 0x8051_0000
+ * entry[82] -> leaf with a reserved bit set covering 0x8052_0000
+ * entry[96] -> NAPOT leaf, G=4, XWR=RW covering 0x8060_0000
+ * entry[128] -> NAPOT leaf, reserved G=5 covering 0x8080_0000
+ *
+ * mmpt = MODE(2=Smmpt52)<<60 | 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). */
+ /* L3[0] = non-leaf -> L2 (PPN 0x80410) */
+ li t0, 0x80400000
+ li t1, 0x20104001
+ sd t1, 0(t0)
+ /* L2[0] = non-leaf -> L1 (PPN 0x80420) */
+ li t0, 0x80410000
+ li t1, 0x20108001
+ sd t1, 0(t0)
+ /* L1[64] = non-leaf -> L0 (PPN 0x80430) */
+ li t0, 0x80420000
+ li t1, 0x2010C001
+ sd t1, 0x200(t0) /* 64 * 8 = 0x200 */
+
+ li t0, 0x80430000
+ /* L0[80] = non-NAPOT leaf carrying all XWR encodings (pi0..pi7) */
+ li t1, LEAF_ALL_XWR
+ sd t1, 0x280(t0) /* 80 * 8 = 0x280 */
+ /* L0[81] = 0: invalid entry (V=0) */
+ sd x0, 0x288(t0) /* 81 * 8 = 0x288 */
+ /* L0[82] = leaf with reserved bit 3 set */
+ li t1, 0x30B
+ sd t1, 0x290(t0) /* 82 * 8 = 0x290 */
+ /* L0[96] = NAPOT leaf: V|L|N | XWR=RW | G=4 */
+ li t1, 0x4307
+ sd t1, 0x300(t0) /* 96 * 8 = 0x300 */
+ /* L0[128] = NAPOT leaf with reserved G=5 */
+ li t1, 0x5307
+ sd t1, 0x400(t0) /* 128 * 8 = 0x400 */
+
+ /* Program mmpt: MODE=2 (Smmpt52), PPN = 0x80400 */
+ li t0, 0x2000000000080400
+ 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
diff --git a/tests/tcg/riscv64/test-smmpt64.S b/tests/tcg/riscv64/test-smmpt64.S
new file mode 100644
index 0000000000..d67035aabb
--- /dev/null
+++ b/tests/tcg/riscv64/test-smmpt64.S
@@ -0,0 +1,98 @@
+/*
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * Test for the Smmpt64 (Supervisor Memory Protection Table) extension,
+ * per SMMTT specification v0.4.9.
+ *
+ * Smmpt64 uses a 5-level MPT with 8-byte entries. Unlike the other RV64
+ * modes its root table is 32 KiB (2^12 entries, pn[4] = SPA[63:52], 12 bits)
+ * and must be aligned to a 32 KiB boundary; the non-root levels are the usual
+ * 4 KiB / 9-bit tables (16 pages per leaf, pi = SPA[15:12]). See
+ * smmpt-common.S for the MPRV trick, the shared address layout and the
+ * exit-code convention.
+ *
+ * For the low (< 4 GiB) addresses exercised here pn[4], pn[3] and pn[2] are
+ * 0, so the upper levels are single-entry chains:
+ *
+ * L4 (root) @ 0x8040_0000 : entry[0] -> non-leaf, PPN(L3)=0x80410
+ * (32 KiB / 32 KiB-aligned)
+ * L3 @ 0x8041_0000 : entry[0] -> non-leaf, PPN(L2)=0x80420
+ * L2 @ 0x8042_0000 : entry[0] -> non-leaf, PPN(L1)=0x80430
+ * L1 @ 0x8043_0000 : entry[64] -> non-leaf, PPN(L0)=0x80440
+ * L0 @ 0x8044_0000 :
+ * entry[80] -> non-NAPOT leaf (LEAF_ALL_XWR) covering 0x8050_0000+
+ * entry[81] -> V=0 (invalid) covering 0x8051_0000
+ * entry[82] -> leaf with a reserved bit set covering 0x8052_0000
+ * entry[96] -> NAPOT leaf, G=4, XWR=RW covering 0x8060_0000
+ * entry[128] -> NAPOT leaf, reserved G=5 covering 0x8080_0000
+ *
+ * mmpt = MODE(3=Smmpt64)<<60 | PPN(0x80400) (PPN[2:0] must be 0)
+ */
+
+#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). */
+ /* L4[0] = non-leaf -> L3 (PPN 0x80410); root is 32 KiB aligned */
+ li t0, 0x80400000
+ li t1, 0x20104001
+ sd t1, 0(t0)
+ /* L3[0] = non-leaf -> L2 (PPN 0x80420) */
+ li t0, 0x80410000
+ li t1, 0x20108001
+ sd t1, 0(t0)
+ /* L2[0] = non-leaf -> L1 (PPN 0x80430) */
+ li t0, 0x80420000
+ li t1, 0x2010C001
+ sd t1, 0(t0)
+ /* L1[64] = non-leaf -> L0 (PPN 0x80440) */
+ li t0, 0x80430000
+ li t1, 0x20110001
+ sd t1, 0x200(t0) /* 64 * 8 = 0x200 */
+
+ li t0, 0x80440000
+ /* L0[80] = non-NAPOT leaf carrying all XWR encodings (pi0..pi7) */
+ li t1, LEAF_ALL_XWR
+ sd t1, 0x280(t0) /* 80 * 8 = 0x280 */
+ /* L0[81] = 0: invalid entry (V=0) */
+ sd x0, 0x288(t0) /* 81 * 8 = 0x288 */
+ /* L0[82] = leaf with reserved bit 3 set */
+ li t1, 0x30B
+ sd t1, 0x290(t0) /* 82 * 8 = 0x290 */
+ /* L0[96] = NAPOT leaf: V|L|N | XWR=RW | G=4 */
+ li t1, 0x4307
+ sd t1, 0x300(t0) /* 96 * 8 = 0x300 */
+ /* L0[128] = NAPOT leaf with reserved G=5 */
+ li t1, 0x5307
+ sd t1, 0x400(t0) /* 128 * 8 = 0x400 */
+
+ /* Program mmpt: MODE=3 (Smmpt64), PPN = 0x80400 */
+ li t0, 0x3000000000080400
+ 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