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 <[email protected]> --- 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
