aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2017-01-24 17:07:05 +0000
committerPeter Maydell <peter.maydell@linaro.org>2017-01-31 11:14:49 +0000
commit723ca7aadb53d5619349db025fbae5507f2abfba (patch)
tree49181643663efabdfbc50a9d7cecb97381964ee1
parent07770f0523e42368d8ffd6949fc42534a923e6dd (diff)
test13: New test for USAGEFAULT testing
Add a new test case test13 which handles checks for various kinds of USAGEFAULT. For the moment we only test a simple UDF (which passes) and a CDP (which fails since QEMU doesn't get the FSR bit right). Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r--Makefile2
-rwxr-xr-xruntests.sh1
-rw-r--r--test13-undef.c257
3 files changed, 260 insertions, 0 deletions
diff --git a/Makefile b/Makefile
index 478391b..bc825a9 100644
--- a/Makefile
+++ b/Makefile
@@ -25,6 +25,7 @@ all: test9-kern.bin
all: test10-kern.bin
all: test11-kern.bin
all: test12-kern.bin
+all: test13-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 test3.o
@@ -37,6 +38,7 @@ test9-kern.elf: cortexm.ld common.ld setup.o armv7m.o init-m-test9.o testme.o te
test10-kern.elf:cortexm.ld common.ld setup.o armv7m.o init-m.o testme.o test10.o
test11-kern.elf:cortexm.ld common.ld setup.o armv7m.o init-m.o test11-buserr.o inst_skip.o
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
clean:
rm -f *.o *.elf *.map *.bin *.img
diff --git a/runtests.sh b/runtests.sh
index 3e68052..bd398b2 100755
--- a/runtests.sh
+++ b/runtests.sh
@@ -38,4 +38,5 @@ dotest test9-kern.bin
dotest test10-kern.bin
dotest test4-kern.bin
dotest test5-kern.bin
+dotest test13-kern.bin
exit $RET
diff --git a/test13-undef.c b/test13-undef.c
new file mode 100644
index 0000000..cb7c35e
--- /dev/null
+++ b/test13-undef.c
@@ -0,0 +1,257 @@
+/* See how various faults are reported and recovered: UNDEF
+ */
+#include "armv7m.h"
+#include "testme.h"
+
+void inst_skip(uint32_t *sp);
+
+static
+volatile unsigned fault_type;
+
+static volatile unsigned fsr;
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
+const char *faultnames[] = {
+ "None",
+ "Mem",
+ "Bus",
+ "Usage",
+};
+
+typedef struct FSRMapEntry {
+ unsigned int bit;
+ const char *name;
+} FSRMapEntry;
+
+static const FSRMapEntry fsrmap[] = {
+ { 0x1, "IACCVIOL" },
+ { 0x2, "DACCVIOL" },
+ { 0x8, "MUNSTKERR" },
+ { 0x10, "MSTKERR" },
+ { 0x20, "MLSPERR" },
+ { 0x80, "MMARVALID" },
+ { 0x100, "IBUSERR" },
+ { 0x200, "PRECISERR" },
+ { 0x400, "IMPRECISERR" },
+ { 0x800, "UNSTKERR" },
+ { 0x1000, "STKERR" },
+ { 0x2000, "LSPERR" },
+ { 0x8000, "BFARVALID" },
+ { 0x10000, "UNDEFINSTR" },
+ { 0x20000, "INVSTATE" },
+ { 0x40000, "INVPC" },
+ { 0x80000, "NOCP" },
+ { 0x1000000, "UNALIGNED" },
+ { 0x2000000, "DIVBYZERO" },
+};
+
+/* Only reports the first set bit! */
+const char *fsrbit(unsigned int fsr)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(fsrmap); i++) {
+ if (fsr & fsrmap[i].bit) {
+ return fsrmap[i].name;
+ }
+ }
+ return "reserved";
+}
+
+const char *faultname(unsigned int faultnum)
+{
+ return faultnum < ARRAY_SIZE(faultnames) ? faultnames[faultnum] : "unknown";
+}
+
+static
+void check_fault(unsigned expect, unsigned expectfsr)
+{
+ unsigned actual = fault_type;
+
+ //testDiag("Fault: %s FSR: %x (%s)", faultname(actual), fsr, fsrbit(fsr));
+
+ testEqI(expect, actual, "fault type");
+ testEqI(expectfsr, fsr, "FSR");
+
+ fault_type = 0;
+ fsr = 0;
+}
+
+static
+void set_fault(unsigned actual, unsigned fsrval)
+{
+ testDiag("%sFault: %x (%s) FSR: %x (%s)",
+ fault_type ? "Secondary " : "",
+ actual, faultname(actual), fsrval, fsrbit(fsrval));
+
+ if (!fault_type) {
+ fault_type = actual;
+ fsr = fsrval;
+ }
+}
+
+static
+void hard(void)
+{
+ testDiag("Unexpected HardFault");
+ abort();
+}
+
+void bus(uint32_t *sp)
+{
+ uint32_t sts, addr;
+
+ sts = in32(SCB(0xd28));
+ set_fault(2, sts);
+
+ 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&0x0300) {
+ /* 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]>=0xf0000000) {
+ /* 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;
+
+ sts = in32(SCB(0xd28));
+
+ set_fault(1, sts);
+
+ 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]>=0xf0000000) {
+ /* 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;
+ sts = in32(SCB(0xd28));
+
+ set_fault(3, sts);
+
+ out32(SCB(0xd28), 0xffff0000); /* W1C */
+
+ 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");
+}
+
+void main(void)
+{
+ run_table.bus = bus_entry;
+ run_table.mem = mem_entry;
+ run_table.usage = usage_entry;
+ run_table.hard = hard;
+
+ testInit(4);
+
+ out32(SCB(0xd24), 0x70000); /* Enable Bus, Mem, and Usage Faults */
+
+ testDiag("Tests of USAGEFAULTs\n");
+
+ testDiag("1 USAGEFAULT for a random undefined insn should be UNDEFINSTR");
+ __asm__("UDF 0x24");
+ check_fault(3, 0x10000);
+
+ testDiag("2 USAGEFAULT for a cp insn should be NOCP");
+ __asm__("cdp 1, 0, c1, c2, c3, 4");
+ check_fault(3, 0x80000);
+
+ testDiag("Done.");
+}