diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2022-12-16 13:52:28 +0000 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2022-12-16 13:52:28 +0000 |
commit | 5b6fc3606b96f858479c2d7ac1b1fd296b762f12 (patch) | |
tree | 079d4d9b4ac101be7bb6d644d270cd63731f227e | |
parent | 1702168b2d58e246511800b07ae272282c6ab48d (diff) |
Add test15 to test small MPU regions
Add a test which checks the functionality of MPU regions
which are smaller than 1K in size.
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | armv7m.h | 1 | ||||
-rwxr-xr-x | runtests.sh | 1 | ||||
-rw-r--r-- | test15.c | 232 |
4 files changed, 236 insertions, 0 deletions
@@ -27,6 +27,7 @@ all: test11-kern.bin all: test12-kern.bin all: test13-kern.bin all: test14-kern.bin +all: test15-kern.bin test1-kern.elf: cortexm.ld common.ld setup.o armv7m.o init-m.o testme.o test1.o test3-kern.elf: cortexm.ld common.ld setup.o armv7m.o init-m.o testme.o test3.o @@ -41,6 +42,7 @@ test11-kern.elf:cortexm.ld common.ld setup.o armv7m.o init-m.o testme.o test11-b test12-kern.elf:cortexm.ld common.ld setup.o test12.o test13-kern.elf:cortexm.ld common.ld setup.o armv7m.o init-m.o test13-undef.o inst_skip.o testme.o test14-kern.elf: cortexm.ld common.ld setup.o armv7m.o init-m.o testme.o test14.o +test15-kern.elf: cortexm.ld common.ld setup.o armv7m.o init-m.o testme.o test15.o inst_skip.o clean: rm -f *.o *.elf *.map *.bin *.img @@ -3,6 +3,7 @@ #include <stdint.h> #include <stdarg.h> +#include <inttypes.h> #define UART(N) ((N)+(void*)0x4000c000) #define UART_DATA UART(0) diff --git a/runtests.sh b/runtests.sh index 4a11c2b..7c68637 100755 --- a/runtests.sh +++ b/runtests.sh @@ -63,4 +63,5 @@ dotest test7-kern.bin dotest test14-kern.bin dotest test8-kern.bin dotest test11-kern.bin +dotest test15-kern.bin exit $RET diff --git a/test15.c b/test15.c new file mode 100644 index 0000000..7f3b37e --- /dev/null +++ b/test15.c @@ -0,0 +1,232 @@ +/* Test MPU small memory regions + */ +#include "armv7m.h" +#include "testme.h" + +static inline void test_equal(const char *m, uint32_t expect, uint32_t actual) +{ + testEqI(expect, actual, "%s", m); +} + +char __end_rom, __after_all_load; + +char testpage[1024] __attribute__((aligned(1024))); + +static +void try(volatile char *p) +{ + uint32_t tval = 0; + testDiag("Try %" PRIx32, (uint32_t)p); + __asm__ ("mov %r0, #'X'; ldr %r0, [%r1]" : "+r"(tval) : "r"(p) :); + testDiag("Got %" PRIx32, tval); +} + +#define EXPECT_NO_FAULT 1 +#define EXPECT_MEMFAULT 2 +#define EXPECT_TAKEN_MEMFAULT 3 +#define EXPECT_HARDFAULT 10 +#define EXPECT_TAKEN_HARDFAULT 11 + +static volatile unsigned expect_fault = EXPECT_NO_FAULT; + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) + +static const char *expect_fault_name[] = { + [EXPECT_NO_FAULT] = "no fault", + [EXPECT_MEMFAULT] = "MemManage fault", + [EXPECT_TAKEN_MEMFAULT] = "MemManage fault taken", + [EXPECT_HARDFAULT] = "HardFault", + [EXPECT_TAKEN_HARDFAULT] = "HardFault taken", +}; + +const char *faultname(unsigned int f) +{ + if (f > ARRAY_SIZE(expect_fault_name) || !expect_fault_name[f]) { + /* This would be a test case code error */ + testDiag("faultname passed bad expect_fault state 0x%x", f); + abort(); + } + return expect_fault_name[f]; +} + +static +void checkfault(unsigned v) +{ + if (v == expect_fault) { + testPass("%s as expected", faultname(v)); + } else { + int curstate = expect_fault; + + /* If expect_fault is still EXPECT_MEMFAULT or EXPECT_HARDFAULT + * then we didn't actually take a fault, so report that as + * "no fault". + */ + if (curstate == EXPECT_MEMFAULT || curstate == EXPECT_HARDFAULT) { + curstate = EXPECT_NO_FAULT; + } + + testFail("expected %s but %s", faultname(v), faultname(curstate)); + } +} + +void hard(uint32_t *sp) +{ + testDiag("In HardFault handler"); + if(expect_fault==EXPECT_HARDFAULT) { + sp = get_src_stack(sp); + inst_skip(sp); + expect_fault = EXPECT_TAKEN_HARDFAULT; + return; + } + testDiag("Unexpected HardFault!!"); + abort(); +} + +static __attribute__((naked)) +void hard_entry(void) +{ + asm("mov r0, sp"); + asm("b hard"); +} + +void mem(uint32_t *sp) +{ + uint32_t addr; + + sp = get_src_stack(sp); + inst_skip(sp); + addr = in32((void*)0xe000ed34); + testDiag("In MemFault, Addr 0x%" PRIx32 ", from 0x%" PRIx32, addr, sp[6]); + + switch(expect_fault) { + case EXPECT_MEMFAULT: + expect_fault = EXPECT_TAKEN_MEMFAULT; + break; + case EXPECT_NO_FAULT: + testDiag("Unexpected MemFault!!"); + abort(); + default: + testDiag("Unexpected state 0x%x", expect_fault); + abort(); + } +} + +static __attribute__((naked)) +void mem_entry(void) +{ + asm("mov r0, sp"); + asm("b mem"); +} + +static inline +void drop_priv(void) +{ + uint32_t val; + __asm__ ("mrs %0, CONTROL" : "=r"(val) ::); + val |= 1; + __asm__ ("msr CONTROL, %0" :: "r"(val) :); +} + +void svc(void *sp) +{ + int num; + sp = get_src_stack(sp); + num = get_svc(sp); + if(num<0) { + testDiag("SVC but not looking at an SVC insn??\n"); + abort(); + } else { + testDiag("SVC 0x%x", num); + } + switch(num) { + case 1: /* restore privlage */ + { + uint32_t val; + __asm__ ("mrs %0, CONTROL" : "=r"(val) ::); + val &= ~1; + __asm__ ("msr CONTROL, %0" :: "r"(val) :); + } + break; + case 2: + abort(); + default: + testDiag("Unknown SVC request value"); + abort(); + } +} + +static __attribute__((naked)) +void svc_entry(void) +{ + asm("mov r0, sp"); + asm("b svc"); +} + +void main(void) +{ + int has_mpu; + uint32_t mpu_type; + + run_table.hard = &hard_entry; + run_table.svc = &svc_entry; + run_table.mem = &mem_entry; + + mpu_type = in32(SCB(0xD90)); + has_mpu = ((mpu_type >> 8) & 0xff) != 0; + + testInit(4); + + if (!has_mpu) { + testDiag("No MPU present: nothing to test here"); + testDiag("Done."); + return; + } + + out32(SCB(0xd24), 1<<16); // enable MemFault with SHCSR + + testDiag("In Main"); + expect_fault = EXPECT_NO_FAULT; + + /* priority of entries is highest to lowest (0 checked last) */ + + set_mpu(0, 0x00000000, (uint32_t)&__end_rom, MPU_NORMAL|MPU_RORO); + set_mpu(1, 0x20000000, 0x00080000, MPU_NORMAL|MPU_RWRW|MPU_XN); + set_mpu(2, 0x4000c000, 0x00001000, MPU_DEVICE|MPU_RWRW|MPU_XN); + set_mpu(3, 0xe000e000, 0x00001000, MPU_DEVICE|MPU_RWRW|MPU_XN); + + /* Create several small regions inside testpage: + * accessible in the middle, surrounded by regions which + * are not accessible. + */ + 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); + set_mpu(6, (uint32_t)testpage + 768, 256, + MPU_XN|MPU_NORMAL|MPU_NANA); + + testDiag("Enable MPU"); + enable_mpu(1,1,0); + + testDiag("Access the accessible small page (should not fault)"); + expect_fault = EXPECT_NO_FAULT; + try(testpage + 600); + checkfault(EXPECT_NO_FAULT); + + expect_fault = EXPECT_MEMFAULT; + testDiag("Access the preceding small page (should fault)"); + try(testpage + 256); + checkfault(EXPECT_TAKEN_MEMFAULT); + + expect_fault = EXPECT_MEMFAULT; + testDiag("Access following small page (should fault)"); + try(testpage + 768); + checkfault(EXPECT_TAKEN_MEMFAULT); + + expect_fault = EXPECT_NO_FAULT; + testDiag("Access the accessible small page again (should not fault)"); + try(testpage + 600); + checkfault(EXPECT_NO_FAULT); + + testDiag("Done."); +} |