From a0cd0b1d0bc78b8ffe3292fbb4f14e4a15e16b7b Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 16 Dec 2022 13:52:28 +0000 Subject: test15: Add execution tests from small MPU regions Add some tests of execution from small MPU regions. Signed-off-by: Peter Maydell --- test15.c | 90 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 84 insertions(+), 6 deletions(-) diff --git a/test15.c b/test15.c index 7f3b37e..7ecc846 100644 --- a/test15.c +++ b/test15.c @@ -69,6 +69,38 @@ void checkfault(unsigned v) } } +typedef int testfn(int); + +static int tryexec(volatile char *p) +{ + uint32_t tval = 0; + testfn *f = (testfn *)((uintptr_t)p | 1); + testDiag("Tryexec %" PRIx32, (uint32_t)p); + /* The assumption is that the code at the dest address is + * adds r0, #1; bx lr + * so we can call it, and it will increment our value for us. + * For non-executable code the exception handler will + * by-hand do the function return back to lr. + */ + tval = f(tval); + testDiag("Returned with %" PRIx32, tval); + if (expect_fault == EXPECT_NO_FAULT && tval != 1) { + testFail("expected code to return 1 but got %" PRId32 "\n", tval); + return 0; + } + return 1; +} + +static void write_exec_test_insns(volatile char *p) +{ + /* Write the "adds r0, #1; bx lr" sequence we'll use + * in tryexec(). + */ + volatile uint16_t *px = (uint16_t*)p; + px[0] = 0x3001; /* adds r0, 1 */ + px[1] = 0x4770; /* bx lr */ +} + void hard(uint32_t *sp) { testDiag("In HardFault handler"); @@ -91,12 +123,28 @@ void hard_entry(void) void mem(uint32_t *sp) { - uint32_t addr; + uint32_t cfsr = in32(SCB(0xd28)); + uint32_t addr = in32(SCB(0xd34)); + + out32(SCB(0xd28), 0xff); /* W1C the MMFSR bits */ sp = get_src_stack(sp); - inst_skip(sp); - addr = in32((void*)0xe000ed34); - testDiag("In MemFault, Addr 0x%" PRIx32 ", from 0x%" PRIx32, addr, sp[6]); + + testDiag("In MemFault, CFSR 0x%" PRIx32 ", from 0x%" PRIX32, cfsr, sp[6]); + if (cfsr & 0x80) { + testDiag("...MMARVALID set, MMFAR is 0x%" PRIx32, addr); + } + + if (cfsr & 0x1) { + /* IACCVIOL -- set PC to LR. Note that the LR will have the + * bit-0-means-Thumb convention but an exception frame PC slot + * has the "raw" PC. + */ + sp[6] = sp[5] & ~1; + } else { + /* DACCVIOL -- just skip offending insn */ + inst_skip(sp); + } switch(expect_fault) { case EXPECT_MEMFAULT: @@ -174,7 +222,7 @@ void main(void) mpu_type = in32(SCB(0xD90)); has_mpu = ((mpu_type >> 8) & 0xff) != 0; - testInit(4); + testInit(8); if (!has_mpu) { testDiag("No MPU present: nothing to test here"); @@ -201,10 +249,14 @@ void main(void) set_mpu(4, (uint32_t)testpage, 512, MPU_XN|MPU_NORMAL|MPU_NANA); set_mpu(5, (uint32_t)testpage + 512, 256, - MPU_XN|MPU_NORMAL|MPU_RWRW); + MPU_NORMAL|MPU_RWRW); set_mpu(6, (uint32_t)testpage + 768, 256, MPU_XN|MPU_NORMAL|MPU_NANA); + write_exec_test_insns(testpage + 256); + write_exec_test_insns(testpage + 600); + write_exec_test_insns(testpage + 768); + testDiag("Enable MPU"); enable_mpu(1,1,0); @@ -228,5 +280,31 @@ void main(void) try(testpage + 600); checkfault(EXPECT_NO_FAULT); + /* Try to execute from various parts of the small page */ + expect_fault = EXPECT_NO_FAULT; + testDiag("Execute from the accessible small page (should not fault)"); + // TODO we get a HardFault here... + if (tryexec(testpage + 600)) { + checkfault(EXPECT_NO_FAULT); + } + + expect_fault = EXPECT_MEMFAULT; + testDiag("Execute from the preceding small page (should fault)"); + if (tryexec(testpage + 256)) { + checkfault(EXPECT_TAKEN_MEMFAULT); + } + + expect_fault = EXPECT_MEMFAULT; + testDiag("Execute from the following small page (should fault)"); + if (tryexec(testpage + 768)) { + checkfault(EXPECT_TAKEN_MEMFAULT); + } + + expect_fault = EXPECT_NO_FAULT; + testDiag("Execute from the accessible small page again (should not fault)"); + if (tryexec(testpage + 600)) { + checkfault(EXPECT_NO_FAULT); + } + testDiag("Done."); } -- cgit v1.2.3