Add test for MPRV vs PMP
This commit is contained in:
		
							parent
							
								
									71eff7649d
								
							
						
					
					
						commit
						f96a0ffb75
					
				| 
						 | 
					@ -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;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Loading…
	
		Reference in New Issue