aboutsummaryrefslogtreecommitdiff
path: root/test11-buserr.c
diff options
context:
space:
mode:
authorMichael Davidsaver <mdavidsaver@gmail.com>2015-11-27 08:47:21 -0500
committerMichael Davidsaver <mdavidsaver@gmail.com>2015-11-27 08:47:21 -0500
commit7cffccf095501426f995d3d0a9397c45eccffdd2 (patch)
tree19356ee6eb1eba2dc4ef8305ef36778d30ac5b31 /test11-buserr.c
parent92eb4d2c1296a2b8b88ecaaf69ae63839d5d8898 (diff)
add test11
Diffstat (limited to 'test11-buserr.c')
-rw-r--r--test11-buserr.c338
1 files changed, 338 insertions, 0 deletions
diff --git a/test11-buserr.c b/test11-buserr.c
new file mode 100644
index 0000000..fcc3b3e
--- /dev/null
+++ b/test11-buserr.c
@@ -0,0 +1,338 @@
+/* See how various faults are reported and recovered
+ */
+#include "armv7m.h"
+
+void inst_skip(uint32_t *sp);
+
+static
+volatile unsigned fault_type;
+
+static
+void check_fault(unsigned expect)
+{
+ unsigned actual = fault_type;
+ puts("# Fault: ");
+ switch(actual) {
+ case 0: puts("None\n"); break;
+ case 1: puts("Mem\n"); break;
+ case 2: puts("Bus\n"); break;
+ case 3: puts("Usage\n"); break;
+ default: puthex(actual);
+ }
+
+ if(expect!=actual)
+ puts("not ");
+ puts("ok - ");
+ puthex(actual);
+ puts(" = ");
+ puthex(expect);
+ putc('\n');
+ fault_type = 0;
+}
+
+static
+void set_fault(unsigned actual)
+{
+ if(fault_type) {
+ puts("Secondary fault ");
+ puthex(actual);
+ putc('\n');
+ abort();
+ }
+ fault_type = actual;
+}
+
+static
+void hard(void)
+{
+ puts("Unexpected HardFault\n");
+ abort();
+}
+
+void bus(uint32_t *sp)
+{
+ uint32_t sts, addr;
+
+ set_fault(2);
+
+ sts = in32(SCB(0xd28));
+ addr= in32(SCB(0xd38));
+
+ out32(SCB(0xd28), 0xff00); /* W1C */
+ out32(SCB(0xd38), 0);
+
+ puts("BusFault: ");
+ puthex(sts);
+ putc(' ');
+ if(sts&0x8000) {
+ puthex(addr);
+ putc(' ');
+ }
+ if(sts&0x1000)
+ puts("STKERR ");
+ if(sts&0x0800)
+ puts("UNSTKERR ");
+ if(sts&0x0400)
+ puts("IMPRECISERR ");
+ if(sts&0x0200)
+ puts("PRECISERR ");
+ if(sts&0x0100)
+ puts("IBUSERR ");
+
+ putc('\n');
+
+ if(sts&0x0200) {
+ /* precise faults would return to the faulting
+ * instruction, which would then fault again
+ * since we change nothing, so skip it.
+ */
+ puts("From: ");
+ puthex(sp[6]);
+ if(sp[6]<0xfffffff0)
+ inst_skip(sp);
+ } else {
+ puts("From before: ");
+ puthex(sp[6]);
+ }
+ putc('\n');
+
+ if(sp[6]>=0xfffffff0) {
+ /* evil hack since we know this was a bx instruction */
+ sp[6] = sp[5]&~1; /* jump to LR */
+ }
+}
+
+static __attribute__((naked))
+void bus_entry(void)
+{
+ asm("mov r0, sp");
+ asm("b bus");
+}
+
+void mem(uint32_t *sp)
+{
+ uint32_t sts, addr;
+
+ set_fault(1);
+
+ sts = in32(SCB(0xd28));
+ addr= in32(SCB(0xd34));
+
+ out32(SCB(0xd28), 0xff); /* W1C */
+
+ puts("MemFault: ");
+ puthex(sts);
+ putc(' ');
+ if(sts&0x80) {
+ puthex(addr);
+ putc(' ');
+ }
+ if(sts&0x08)
+ puts("MSTKERR ");
+ if(sts&0x04)
+ puts("MUNSTKERR ");
+ if(sts&0x02)
+ puts("DACCVIOL ");
+ if(sts&0x01)
+ puts("IACCVIOL ");
+
+ putc('\n');
+
+ puts("From: ");
+ puthex(sp[6]);
+ putc('\n');
+
+ if(sp[6]>=0xfffffff0) {
+ /* evil hack since we know this was a bx instruction */
+ sp[6] = sp[5]&~1; /* jump to LR */
+ } else {
+ inst_skip(sp);
+ }
+}
+
+static __attribute__((naked))
+void mem_entry(void)
+{
+ asm("mov r0, sp");
+ asm("b mem");
+}
+
+
+void usage(uint32_t *sp)
+{
+ uint32_t sts;
+
+ set_fault(1);
+
+ sts = in32(SCB(0xd28));
+
+ out32(SCB(0xd28), 0xffff0000); /* W1C */
+
+ puts("UsageFault: ");
+ if(sts&0x2000000)
+ puts("DIVBYZERO ");
+ if(sts&0x1000000)
+ puts("UNALIGNED ");
+ if(sts&0x80000)
+ puts("NOCP ");
+ if(sts&0x40000)
+ puts("INVPC ");
+ if(sts&0x20000)
+ puts("INVSTATE ");
+ if(sts&0x10000)
+ puts("UNDEFINSTR ");
+
+ putc('\n');
+
+ puts("From: ");
+ puthex(sp[6]);
+ putc('\n');
+
+ if(sts&0x20000) {
+ abort(); /* attempt to execute ARM mode */
+ }
+
+ inst_skip(sp);
+}
+
+static __attribute__((naked))
+void usage_entry(void)
+{
+ asm("mov r0, sp");
+ asm("b usage");
+}
+
+static __attribute__((naked))
+void jumpff(uint32_t x)
+{
+ (void)x;
+ /* evilness
+ * 'blx' would fault before updating 'lr' anyway, so use 'bx'
+ * to be clear.
+ * We will return using the link register from our caller.
+ */
+ asm("bx r0");
+ asm("jumpstuck: b jumpstuck");
+}
+
+void main(void)
+{
+ run_table.bus = bus_entry;
+ run_table.mem = mem_entry;
+ run_table.usage = usage_entry;
+ run_table.hard = hard;
+
+ out32(SCB(0xd24), 0x70000); /* Enable Bus, Mem, and Usage Faults */
+
+ puts("# w/o MPU, hits background mapping\n");
+
+ puts("1. Cause BusFault 0xe100ffff\n");
+ out32((void*)0xe100ffff, 0);
+ check_fault(2);
+ puts("Back in Main\n");
+
+ puts("2. Another BusFault 0x10000000\n");
+ out32((void*)0x10000000, 0);
+ check_fault(2);
+ puts("Back in Main\n");
+
+ puts("3. Another BusFault 0x01000000\n");
+ out32((void*)0x01000000, 0);
+ check_fault(2);
+ puts("Back in Main\n");
+
+ puts("4. Another BusFault 0xfffffffe\n");
+ out32((void*)0xfffffffe, 0);
+ check_fault(2);
+ puts("Back in Main\n");
+
+// this jump works, and TI has hidden so data here
+// puts("5. MemFault (jump to 0x01000001)\n");
+// jumpff(0x01000001);
+// check_fault(1);
+// puts("Back in Main\n");
+
+ puts("5. MemFault (jump to 0xfffffff9)\n");
+ jumpff(0xfffffff9);
+ check_fault(1);
+ puts("Back in Main\n");
+
+ puts("# Enable MPU, but not for privlaged"
+ " still hits background mapping\n");
+ enable_mpu(1,0,0);
+
+ puts("6. Cause BusFault 0xe100ffff\n");
+ out32((void*)0xe100ffff, 0);
+ check_fault(2);
+ puts("Back in Main\n");
+
+ puts("7. Another BusFault 0x10000000\n");
+ out32((void*)0x10000000, 0);
+ check_fault(2);
+ puts("Back in Main\n");
+
+ puts("8. Another BusFault 0x01000000\n");
+ out32((void*)0x01000000, 0);
+ check_fault(2);
+ puts("Back in Main\n");
+
+ puts("9. Another BusFault 0xfffffffe\n");
+ out32((void*)0xfffffffe, 0);
+ check_fault(2);
+ puts("Back in Main\n");
+
+// this jump works, and TI has hidden so data here
+// puts("5. MemFault (jump to 0x01000001)\n");
+// jumpff(0x01000001);
+// check_fault(1);
+// puts("Back in Main\n");
+
+ puts("10. MemFault (jump to 0xfffffff9)\n");
+ jumpff(0xfffffff9);
+ check_fault(1);
+ puts("Back in Main\n");
+
+ // ROM region is made larger than actual rom to pass through 0x05000000
+ set_mpu(0, 0x00000000, 0x08000000, MPU_NORMAL|MPU_RORO);
+ set_mpu(1, 0x20000000, 0x00080000, MPU_NORMAL|MPU_RWRW|MPU_XN);
+ set_mpu(2, 0x400fe000, 0x00100000, MPU_DEVICE|MPU_RWRW|MPU_XN);
+ set_mpu(3, 0xe000e000, 0x00001000, MPU_DEVICE|MPU_RWRW|MPU_XN);
+ // Allow through access to unconnected address space
+ set_mpu(4, 0xe100e000, 0x00020000, MPU_DEVICE|MPU_RWRW|MPU_XN);
+
+ puts("# Enable MPU, including privlaged\n");
+ enable_mpu(1,1,0);
+
+ // MPU allows through, but no one is home == BusFault
+ puts("11. Cause BusFault 0xe100ffff\n");
+ out32((void*)0xe100ffff, 0);
+ check_fault(2);
+ puts("Back in Main\n");
+
+ puts("12. Another MemFault 0x10000000\n");
+ out32((void*)0x10000000, 0);
+ check_fault(1);
+ puts("Back in Main\n");
+
+ // MPU allows through, no one is home, but still MemFault...?
+ puts("13. Another MemFault 0x05000000\n");
+ out32((void*)0x05000000, 0);
+ check_fault(1);
+ puts("Back in Main\n");
+
+ puts("14. Another MemFault 0xfffffffe\n");
+ out32((void*)0xfffffffe, 0);
+ check_fault(1);
+ puts("Back in Main\n");
+
+// this jump works, and TI has hidden so data here
+// puts("5. MemFault (jump to 0x01000001)\n");
+// jumpff(0x01000001);
+// check_fault(1);
+// puts("Back in Main\n");
+
+ puts("15. MemFault (jump to 0xfffffff9)\n");
+ jumpff(0xfffffff9);
+ check_fault(1);
+ puts("Back in Main\n");
+}