aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2022-12-16 13:52:28 +0000
committerPeter Maydell <peter.maydell@linaro.org>2022-12-16 13:52:28 +0000
commit5b6fc3606b96f858479c2d7ac1b1fd296b762f12 (patch)
tree079d4d9b4ac101be7bb6d644d270cd63731f227e
parent1702168b2d58e246511800b07ae272282c6ab48d (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--Makefile2
-rw-r--r--armv7m.h1
-rwxr-xr-xruntests.sh1
-rw-r--r--test15.c232
4 files changed, 236 insertions, 0 deletions
diff --git a/Makefile b/Makefile
index e423eba..3b408a2 100644
--- a/Makefile
+++ b/Makefile
@@ -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
diff --git a/armv7m.h b/armv7m.h
index 36955f8..e17f765 100644
--- a/armv7m.h
+++ b/armv7m.h
@@ -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.");
+}