]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/sgi/faultmips.c
usbehci: catch interrupt in tsleep
[plan9front.git] / sys / src / 9 / sgi / faultmips.c
1 #include        "u.h"
2 #include        "../port/lib.h"
3 #include        "mem.h"
4 #include        "dat.h"
5 #include        "fns.h"
6 #include        "ureg.h"
7 #include        "../port/error.h"
8 #include        "io.h"
9
10 enum {
11         Debug = 0,
12 };
13
14 typedef struct Fault Fault;
15 struct Fault {
16         uintptr va;
17         ulong   pid;
18         uintptr pc;
19         int     cnt;
20         char    *prog;
21         int     code;
22 };
23
24 extern char *excname[];
25
26 static Fault lflt, maxflt;
27
28 ulong*
29 reg(Ureg *ur, int regno)
30 {
31         ulong *l;
32
33         switch(regno) {
34         case 31: return &ur->r31;
35         case 30: return &ur->r30;
36         case 29: return &ur->sp;
37         default:
38                 l = &ur->r1;
39                 return &l[regno-1];
40         }
41 }
42
43 /*
44  * Ask if the instruction at EPC could have cause this badvaddr
45  */
46 int
47 tstbadvaddr(Ureg *ur)
48 {
49         int rn;
50         ulong iw, off, ea;
51
52         iw = ur->pc;
53         if(ur->cause & BD)
54                 iw += 4;
55
56         if(seg(up, iw, 0) == 0)
57                 return 0;
58
59         iw = *(ulong*)iw;
60
61 /*      print("iw: %#lux\n", iw);       /**/
62
63         switch((iw>>26) & 0x3f) {
64         default:
65                 return 1;
66         case 0x20:      /* LB */
67         case 0x24:      /* LBU */
68                         /* LD */
69         case 0x35:
70         case 0x36:
71         case 0x37:      /* LDCz */
72         case 0x1A:      /* LDL */
73         case 0x1B:      /* LDR */
74         case 0x21:      /* LH */
75         case 0x25:      /* LHU */
76         case 0x30:      /* LL */
77         case 0x34:      /* LLD */
78         case 0x23:      /* LW */
79         case 0x31:
80         case 0x32:      /* LWCz possible 0x33 */
81         case 0x27:      /* LWU */
82         case 0x22:      /* LWL */
83         case 0x26:      /* LWR */
84                 break;
85
86         case 0x28:      /* SB */
87         case 0x38:      /* SC */
88         case 0x3C:      /* SCD */
89         case 0x3D:
90         case 0x3E:
91         case 0x3F:      /* SDCz */
92         case 0x2C:      /* SDL */
93         case 0x2D:      /* SDR */
94         case 0x29:      /* SH */
95         case 0x2B:      /* SW */
96         case 0x39:
97         case 0x3A:      /* SWCz */
98         case 0x2A:      /* SWL */
99         case 0x2E:      /* SWR */
100                 break;
101         }
102
103         off = iw & 0xffff;
104         if(off & 0x8000)
105                 off |= ~0xffff;
106
107         rn = (iw>>21) & 0x1f;
108         ea = *reg(ur, rn);
109         if(rn == 0)
110                 ea = 0;
111         ea += off;
112
113         /* print("ea %#lux %#lux(R%d) bv %#lux pc %#lux\n", ea, off, rn, ur->badvaddr, ur->pc); /**/
114
115         if(ur->badvaddr == ea)
116                 return 0;
117
118         return 1;
119 }
120
121 /*
122  * we think we get consecutive page faults from unlucky combinations of
123  * scheduling and stlb hashes, and they only happen with 16K pages.
124  * however, we also get page faults while servicing the exact same fault.
125  * more than 5 consecutive faults is unusual, now that we have a better
126  * hash function.
127  *
128  * this can be helpful during mmu and cache debugging.
129  */
130 static int
131 ckfaultstuck(Ureg *ur, int read, int code)
132 {
133         uintptr pc, va;
134
135         va = ur->badvaddr;
136         pc = ur->pc;
137         if (va != lflt.va || up->pid != lflt.pid || pc != lflt.pc ||
138             code != lflt.code) {
139                 /* at least one address or cause is different from last time */
140                 lflt.cnt = 1;
141                 lflt.va = va;
142                 lflt.pid = up->pid;
143                 lflt.pc = pc;
144                 lflt.code = code;
145                 return 0;
146         }
147         ++lflt.cnt;
148         if (lflt.cnt >= 1000)   /* fixfault() isn't fixing underlying cause? */
149                 panic("fault: %d consecutive faults for va %#p", lflt.cnt, va);
150         if (lflt.cnt > maxflt.cnt) {
151                 maxflt.cnt = lflt.cnt;
152                 maxflt.va = va;
153                 maxflt.pid = up->pid;
154                 maxflt.pc = pc;
155                 kstrdup(&maxflt.prog, up->text);
156         }
157
158         /* we're servicing that fault now! */
159         /* adjust the threshold and program name to suit */
160         if (lflt.cnt < 5 || strncmp(up->text, "8l", 2) != 0)
161                 return 0;
162         iprint("%d consecutive faults for va %#p at pc %#p in %s "
163                 "pid %ld\n", lflt.cnt, lflt.va, pc, up->text, lflt.pid);
164         iprint("\t%s: %s%s r31 %#lux tlbvirt %#lux\n",
165                 excname[code], va == pc? "[instruction] ": "",
166                 (read? "read": "write"), ur->r31, tlbvirt());
167         return 0;
168 }
169
170 char *
171 faultsprint(char *p, char *ep)
172 {
173         if (Debug)
174                 p = seprint(p, ep,
175                         "max consecutive faults %d for va %#p in %s\n",
176                         maxflt.cnt, maxflt.va, maxflt.prog);
177         return p;
178 }
179
180 /*
181  *  find out fault address and type of access.
182  *  Call common fault handler.
183  */
184 void
185 faultmips(Ureg *ur, int user, int code)
186 {
187         int read;
188         ulong addr;
189         char *p, buf[ERRMAX];
190
191         addr = ur->badvaddr;
192         addr &= ~(BY2PG-1);
193
194         read = !(code==CTLBM || code==CTLBS);
195
196 /*      print("fault: %s code %d va %#p pc %#p r31 %#lux tlbvirt %#lux\n",
197                 up->text, code, ur->badvaddr, ur->pc, ur->r31, tlbvirt());/**/
198
199         if (Debug && ckfaultstuck(ur, read, code) || fault(addr, read) == 0)
200                 return;
201
202         if(user) {
203                 p = "store";
204                 if(read)
205                         p = "load";
206                 snprint(buf, sizeof buf, "sys: trap: fault %s addr=%#lux r31=%#lux",
207                         p, ur->badvaddr, ur->r31);
208                 postnote(up, 1, buf, NDebug);
209                 return;
210         }
211
212         splhi();
213         serialoq = nil;
214         print("kernel %s vaddr=%#lux\n", excname[code], ur->badvaddr);
215         print("st=%#lux pc=%#lux r31=%#lux sp=%#lux\n",
216                 ur->status, ur->pc, ur->r31, ur->sp);
217         dumpregs(ur);
218         panic("fault");
219 }
220
221 /*
222  * called in syscallfmt.c, sysfile.c, sysproc.c
223  */
224 void
225 validalign(uintptr addr, unsigned align)
226 {
227         /*
228          * Plan 9 is a 32-bit O/S, and the hardware it runs on
229          * does not usually have instructions which move 64-bit
230          * quantities directly, synthesizing the operations
231          * with 32-bit move instructions. Therefore, the compiler
232          * (and hardware) usually only enforce 32-bit alignment,
233          * if at all.
234          *
235          * Take this out if the architecture warrants it.
236          */
237         if(align == sizeof(vlong))
238                 align = sizeof(long);
239
240         /*
241          * Check align is a power of 2, then addr alignment.
242          */
243         if((align != 0 && !(align & (align-1))) && !(addr & (align-1)))
244                 return;
245         postnote(up, 1, "sys: odd address", NDebug);
246         error(Ebadarg);
247         /*NOTREACHED*/
248 }