From f96a0ffb75cbec8ea367c5ed0394a07d38afc34c Mon Sep 17 00:00:00 2001 From: Luke Wren Date: Sun, 29 May 2022 19:06:04 +0100 Subject: [PATCH] Add test for MPRV vs PMP --- test/sim/sw_testcases/pmp_mprv.c | 94 ++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 test/sim/sw_testcases/pmp_mprv.c diff --git a/test/sim/sw_testcases/pmp_mprv.c b/test/sim/sw_testcases/pmp_mprv.c new file mode 100644 index 0000000..b8053bb --- /dev/null +++ b/test/sim/sw_testcases/pmp_mprv.c @@ -0,0 +1,94 @@ +#include "tb_cxxrtl_io.h" +#include "hazard3_csr.h" +#include "pmp.h" + +// Check that PMP enforces U-mode read/write permissions in M-mode, if both +// MPRV=1 and MPP=U. Check that this does not affect execute permissions. +// Check MPRV is cleared when returning to U mode. + +#define MCAUSE_LOAD_FAULT 5 +#define MCAUSE_STORE_FAULT 7 +#define MCAUSE_ECALL_UMODE 8 + +/*EXPECTED-OUTPUT*************************************************************** + +Enabling MPRV, with MPP=M +Set MPP=U, then read memory +mcause = 5 // load fault +mstatus = 00021800 // MPRV = 1 MPP = M +mem[mepc] = 4108 // c.lw a0, (a0) +Set MPP=U, then write memory +mcause = 7 // store fault +mstatus = 00021800 // MPRV = 1 MPP = M +mem[mepc] = c108 // c.sw a0, (a0) + +*******************************************************************************/ + +volatile uint32_t scratch_word; + +#define MPRV (1u << 17) +#define MPP (3u << 11) + +int main() { + // Give U-mode RW permissions on testbench IO *only* (so any address >= + // 0x800 megabytes). This means we can always print and exit the test. + write_pmpcfg(0, PMPCFG_A_NAPOT << PMPCFG_A_LSB | PMPCFG_R_BITS | PMPCFG_W_BITS); + write_pmpaddr(0, (0x80000000u | 0x3fffffffu) >> 2); + + scratch_word = 0; + + tb_puts("Enabling MPRV, with MPP=M\n"); + set_csr(mstatus, MPP | MPRV); + // Effective privilege is still M mode, so we can do whatever we want. Go + // nuts. Read and write some memory. + scratch_word = 0x12345678u; + tb_assert(scratch_word == 0x12345678u, "Bad readback somehow\n"); + + write_csr(mcause, 0); + write_csr(mepc, 0); + + tb_puts("Set MPP=U, then read memory\n"); + asm ( + "la a0, 1f\n" + "csrw mtvec, a0\n" + "la a0, scratch_word\n" + "la a1, 0x1800\n" + + // Note the nop is to check that we have not lost X permissions. The + // trap should come from the lw. + "csrc mstatus, a1\n" + "nop\n" + "c.lw a0, (a0)\n" + + ".p2align 2\n" + "1:" + : : : "a0", "a1" + ); + // We should have instantly trapped, and set MPP back to M upon trapping, + // restoring read/write permissions. + tb_printf("mcause = %u\n", read_csr(mcause)); + tb_printf("mstatus = %08x\n", read_csr(mstatus)); + tb_printf("mem[mepc] = %04x\n", *(uint16_t*)read_csr(mepc)); + + // Same trick but writes. We should get a different mcause value. + tb_puts("Set MPP=U, then write memory\n"); + asm ( + "la a0, 1f\n" + "csrw mtvec, a0\n" + "la a0, scratch_word\n" + "la a1, 0x1800\n" + + "csrc mstatus, a1\n" + "nop\n" + "c.sw a0, (a0)\n" + + ".p2align 2\n" + "1:" + : : : "a0", "a1" + ); + tb_printf("mcause = %u\n", read_csr(mcause)); + tb_printf("mstatus = %08x\n", read_csr(mstatus)); + tb_printf("mem[mepc] = %04x\n", *(uint16_t*)read_csr(mepc)); + + return 0; +}