summaryrefslogtreecommitdiff
path: root/os/mpc/faultpower.c
diff options
context:
space:
mode:
Diffstat (limited to 'os/mpc/faultpower.c')
-rw-r--r--os/mpc/faultpower.c49
1 files changed, 49 insertions, 0 deletions
diff --git a/os/mpc/faultpower.c b/os/mpc/faultpower.c
new file mode 100644
index 00000000..6d3b163b
--- /dev/null
+++ b/os/mpc/faultpower.c
@@ -0,0 +1,49 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "ureg.h"
+#include "io.h"
+
+enum
+{
+ MC_IFETCH = (1<<30),
+ MC_STORE = (1<<11), /* bit 23 if X-form, bit 3 if D-form => write */
+ DSI_STORE = (1<<25),
+ DSI_PROT = (1<<27),
+};
+
+void
+faultpower(Ureg *ur)
+{
+ ulong addr;
+ char buf[ERRMAX];
+ int read, i;
+
+ addr = ur->pc; /* assume instr. exception */
+ read = 1;
+ i = ur->cause >> 8;
+ if(i == CDSI || i == CDTLBE || i == CMCHECK && (ur->status&MC_IFETCH) == 0) { /* data access error including machine check load/store */
+ addr = getdar();
+ if(getdsisr() & (DSI_STORE|MC_STORE))
+ read = 0;
+ } else if(i == CDMISS) /* DTLB miss */
+ addr = getdepn() & ~0x3FF; /* can't distinguish read/write, but Inferno doesn't care */
+/*
+print("fault %lux %lux %lux %d\n", ur->pc, ur->cause, addr, read);
+print("imiss %lux dmiss %lux hash1 %lux dcmp %lux hash2 %lux\n",
+ getimiss(), getdmiss(), gethash1(), getdcmp(), gethash2());
+print("up %lux %lux %lux\n", m->upage, m->upage->virt, m->upage->phys);
+*/
+
+ up->dbgreg = ur; /* For remote ACID */
+
+ spllo();
+ sprint(buf, "trap: fault %s pc=0x%lux addr=0x%lux",
+ read ? "read" : "write", ur->pc, addr);
+ if(up->type == Interp)
+ disfault(ur, buf);
+ dumpregs(ur);
+ panic("fault: %s\n", buf);
+}