A segment load performs nf independent eew-sized accesses, so PMP checks
each field on its own.  Probing the whole nf * eew segment as one range
instead reports a fault whenever a PMP boundary falls inside a segment.

Signed-off-by: Max Chou <[email protected]>
---
 tests/tcg/riscv64/Makefile.softmmu-target |  21 +++-
 tests/tcg/riscv64/test-rvv-ldst-seg-pmp.S | 141 ++++++++++++++++++++++
 2 files changed, 160 insertions(+), 2 deletions(-)
 create mode 100644 tests/tcg/riscv64/test-rvv-ldst-seg-pmp.S

diff --git a/tests/tcg/riscv64/Makefile.softmmu-target 
b/tests/tcg/riscv64/Makefile.softmmu-target
index 93c4e58e0c2..aea1e7fcb15 100644
--- a/tests/tcg/riscv64/Makefile.softmmu-target
+++ b/tests/tcg/riscv64/Makefile.softmmu-target
@@ -87,7 +87,8 @@ test-vle32ff: CFLAGS += -march=rv64gcv
 
 RVV_LDST_MARCH = -march=rv64gcv
 RVV_LDST_TESTS = test-rvv-ldst-ff-pmp test-rvv-ldst-us-pmp \
-       test-rvv-ldst-ff-page
+       test-rvv-ldst-ff-page \
+       test-rvv-ldst-seg-pmp
 CLEANFILES += $(RVV_LDST_TESTS)
 
 $(RVV_LDST_TESTS): %: %.S rvv-ldst.inc $(LINK_SCRIPT)
@@ -95,7 +96,8 @@ $(RVV_LDST_TESTS): %: %.S rvv-ldst.inc $(LINK_SCRIPT)
        $(LD) $(LDFLAGS) [email protected] -o $@
 
 EXTRA_RUNS += run-test-rvv-ldst-ff-pmp run-test-rvv-ldst-us-pmp \
-       run-test-rvv-ldst-ff-page
+       run-test-rvv-ldst-ff-page \
+       run-test-rvv-ldst-seg-pmp
 
 run-test-rvv-ldst-ff-pmp: test-rvv-ldst-ff-pmp
        $(call run-test, $<, $(QEMU) -cpu 
rv64$(comma)v=true$(comma)vlen=128$(comma)elen=64$(comma)vext_spec=v1.0$(comma)rvv_ta_all_1s=true$(comma)rvv_ma_all_1s=true
 $(QEMU_OPTS)$<)
@@ -106,5 +108,20 @@ run-test-rvv-ldst-us-pmp: test-rvv-ldst-us-pmp
 run-test-rvv-ldst-ff-page: test-rvv-ldst-ff-page
        $(call run-test, $<, $(QEMU) -cpu 
rv64$(comma)v=true$(comma)vlen=128$(comma)elen=64$(comma)vext_spec=v1.0 
$(QEMU_OPTS)$<)
 
+run-test-rvv-ldst-seg-pmp: test-rvv-ldst-seg-pmp
+       $(call run-test, $<, $(QEMU) -cpu 
rv64$(comma)v=true$(comma)vlen=128$(comma)elen=64$(comma)vext_spec=v1.0 
$(QEMU_OPTS)$<)
+
+PMP_TESTS = test-pmp-interior-entry
+CLEANFILES += $(PMP_TESTS)
+
+$(PMP_TESTS): %: %.S rvv-ldst.inc $(LINK_SCRIPT)
+       $(CC) $(CFLAGS) -march=rv64gc_zicboz $< -Wa,--noexecstack -c -o [email protected]
+       $(LD) $(LDFLAGS) [email protected] -o $@
+
+EXTRA_RUNS += run-test-pmp-interior-entry
+
+run-test-pmp-interior-entry: test-pmp-interior-entry
+       $(call run-test, $<, $(QEMU) -cpu 
rv64$(comma)zicboz=true$(comma)cboz_blocksize=64 $(QEMU_OPTS)$<)
+
 # We don't currently support the multiarch system tests
 undefine MULTIARCH_TESTS
diff --git a/tests/tcg/riscv64/test-rvv-ldst-seg-pmp.S 
b/tests/tcg/riscv64/test-rvv-ldst-seg-pmp.S
new file mode 100644
index 00000000000..9b3703ba338
--- /dev/null
+++ b/tests/tcg/riscv64/test-rvv-ldst-seg-pmp.S
@@ -0,0 +1,141 @@
+/*
+ * RISC-V vector segment load spanning two PMP regions
+ *
+ * A segment load performs nf independent eew-sized accesses, so each
+ * field is checked against PMP on its own. A probe that presents the
+ * whole nf * eew segment as one range instead reports a fault whenever
+ * a PMP boundary falls inside the segment, even though every access the
+ * instruction actually performs is permitted.
+ *
+ * PMP layout (locked entries, lowest number wins; everything outside
+ * the test page is unmatched and so fully accessible from M-mode):
+ *   pmp0: NA4   buf+0,     L, R--   field 0 readable
+ *   pmp1: NA4   buf+4,     L, R--   field 1 readable, adjacent to pmp0
+ *   pmp2: NAPOT test page, L, RW-   lower-priority page allow
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+    #include "rvv-ldst.inc"
+
+    .text
+    .global _start
+_start:
+    RVV_ENABLE
+    lla    t0, trap_handler
+    csrw   mtvec, t0
+
+    /*
+     * Trap handler protocol:
+     *   s0: expected mcause (0: no trap expected)
+     *   s1: expected mtval  (-1: any mtval accepted)
+     *   s2: traps taken     s3: vstart seen at last trap
+     *   s4: traps expected  s5: mtval seen at last trap
+     */
+    li      s0, 0
+    li      s1, 0
+    li      s2, 0
+    li      s3, -1
+    li      s4, 0
+
+    /* Program the locked PMP entries; single locking cfg write last. */
+    lla     t0, buf
+    srli    t0, t0, 2
+    csrw    pmpaddr0, t0
+    lla     t0, buf + 4
+    srli    t0, t0, 2
+    csrw    pmpaddr1, t0
+    lla     t0, pmp_page
+    srli    t0, t0, 2
+    ori     t0, t0, 0x1ff
+    csrw    pmpaddr2, t0
+    li      t0, 0x9b9191
+    csrw    pmpcfg0, t0
+
+    /* Case 1: a 4-byte load fully inside pmp0 is granted. */
+    CASE    1
+    lla         t1, buf
+    lw          t0, 0(t1)
+    CHECK_NO_TRAP
+    ASSERT_EQ   t0, 0x00dd0000
+
+    /* Case 2: a 4-byte load fully inside pmp1 is granted. */
+    CASE    2
+    lla         t1, buf
+    lw          t0, 4(t1)
+    CHECK_NO_TRAP
+    ASSERT_EQ   t0, 0x00dd0001
+
+    /*
+     * Case 3: control.  One 8-byte access covers both entries and is
+     * contained by neither, so it must fault however permissive the
+     * two entries are on their own.
+     */
+    CASE    3
+    li          s0, 5
+    lla         s1, buf
+    lla         t1, buf
+    ld          t0, 0(t1)
+    CHECK_TRAP
+
+    /*
+     * Case 4: vlseg2e32.v performs one 4-byte access per field, each
+     * contained by its own entry, so the segment must load.  A probe
+     * covering the whole 8-byte segment reports a load access fault
+     * here instead.
+     */
+    CASE    4
+    PREFILL
+    vsetivli    zero, 1, e32, m1, ta, ma
+    lla         a0, buf
+    vlseg2e32.v v2, (a0)
+    CHECK_NO_TRAP
+    CHECK_VELEM v2, 0, 0x00dd0000
+    CHECK_VELEM v3, 0, 0x00dd0001
+
+    /*
+     * Case 5: the same on the fault-only-first path, which must not
+     * truncate vl either.
+     */
+    CASE    5
+    PREFILL
+    vsetivli    zero, 1, e32, m1, ta, ma
+    lla         a0, buf
+    vlseg2e32ff.v v2, (a0)
+    csrr        t2, vl
+    CHECK_NO_TRAP
+    ASSERT_EQ   t2, 1
+    CHECK_VELEM v2, 0, 0x00dd0000
+    CHECK_VELEM v3, 0, 0x00dd0001
+
+    li    a0, 0
+exit:
+    SEMI_EXIT
+    FAIL
+
+    .balign 4
+trap_handler:
+    csrr    t5, mcause
+    bne     t5, s0, fail
+    csrr    s5, mtval
+    li      t5, -1
+    beq     s1, t5, 1f
+    bne     s5, s1, fail
+1:
+    csrr    s3, vstart
+    addi    s2, s2, 1
+    csrw    vstart, zero
+    csrr    t5, mepc
+    addi    t5, t5, 4
+    csrw    mepc, t5
+    mret
+
+    .data
+    .balign 16
+semiargs: .space 16
+
+    /* One dedicated page governed by the locked NAPOT RW entry. */
+    .balign 4096
+pmp_page:
+buf:
+    .word   0x00dd0000, 0x00dd0001, 0x00dd0002, 0x00dd0003
+    .skip   4080
-- 
2.43.0


Reply via email to