diff options
author | Michael Davidsaver <mdavidsaver@gmail.com> | 2015-11-27 08:47:21 -0500 |
---|---|---|
committer | Michael Davidsaver <mdavidsaver@gmail.com> | 2015-11-27 08:47:21 -0500 |
commit | 7cffccf095501426f995d3d0a9397c45eccffdd2 (patch) | |
tree | 19356ee6eb1eba2dc4ef8305ef36778d30ac5b31 /test11-buserr.c | |
parent | 92eb4d2c1296a2b8b88ecaaf69ae63839d5d8898 (diff) |
add test11
Diffstat (limited to 'test11-buserr.c')
-rw-r--r-- | test11-buserr.c | 338 |
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"); +} |