]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/bcm/trap.c
pc, pc64: make sure write combining is supported in MTRR's before setting it
[plan9front.git] / sys / src / 9 / bcm / trap.c
1 /*
2  * traps, exceptions, interrupts, system calls.
3  */
4 #include "u.h"
5 #include "../port/lib.h"
6 #include "mem.h"
7 #include "dat.h"
8 #include "fns.h"
9 #include "io.h"
10 #include "ureg.h"
11 #include "../port/error.h"
12
13 #include "arm.h"
14
15 enum {
16         Nvec = 8,               /* # of vectors at start of lexception.s */
17 };
18
19 /*
20  *   Layout at virtual address KZERO (double mapped at HVECTORS).
21  */
22 typedef struct Vpage0 {
23         void    (*vectors[Nvec])(void);
24         u32int  vtable[Nvec];
25 } Vpage0;
26
27 static char *trapnames[PsrMask+1] = {
28         [ PsrMusr ] "user mode",
29         [ PsrMfiq ] "fiq interrupt",
30         [ PsrMirq ] "irq interrupt",
31         [ PsrMsvc ] "svc/swi exception",
32         [ PsrMabt ] "prefetch abort/data abort",
33         [ PsrMabt+1 ] "data abort",
34         [ PsrMund ] "undefined instruction",
35         [ PsrMsys ] "sys trap",
36 };
37
38 extern int irq(Ureg*);
39 extern int notify(Ureg*);
40
41 /*
42  *  set up for exceptions
43  */
44 void
45 trapinit(void)
46 {
47         Vpage0 *vpage0;
48
49         intrcpushutdown();
50         if (m->machno == 0) {
51                 /* disable everything */
52                 intrsoff();
53                 /* set up the exception vectors */
54                 vpage0 = (Vpage0*)HVECTORS;
55                 memmove(vpage0->vectors, vectors, sizeof(vpage0->vectors));
56                 memmove(vpage0->vtable, vtable, sizeof(vpage0->vtable));
57                 cacheuwbinv();
58                 l2cacheuwbinv();
59         }
60
61         /* set up the stacks for the interrupt modes */
62         setr13(PsrMfiq, (u32int*)(FIQSTKTOP));
63         setr13(PsrMirq, m->sirq);
64         setr13(PsrMabt, m->sabt);
65         setr13(PsrMund, m->sund);
66         setr13(PsrMsys, m->ssys);
67
68         coherence();
69 }
70
71 static char *
72 trapname(int psr)
73 {
74         char *s;
75
76         s = trapnames[psr & PsrMask];
77         if(s == nil)
78                 s = "unknown trap number in psr";
79         return s;
80 }
81
82 /*
83  *  called by trap to handle access faults
84  */
85 static void
86 faultarm(Ureg *ureg, uintptr va, int user, int read)
87 {
88         int n, insyscall;
89         char buf[ERRMAX];
90
91         if(up == nil) {
92                 dumpregs(ureg);
93                 panic("fault: nil up in faultarm, accessing %#p", va);
94         }
95         insyscall = up->insyscall;
96         up->insyscall = 1;
97         n = fault(va, ureg->pc, read);
98         if(n < 0){
99                 if(!user){
100                         dumpregs(ureg);
101                         panic("fault: kernel accessing %#p", va);
102                 }
103                 /* don't dump registers; programs suicide all the time */
104                 snprint(buf, sizeof buf, "sys: trap: fault %s va=%#p",
105                         read? "read": "write", va);
106                 postnote(up, 1, buf, NDebug);
107         }
108         up->insyscall = insyscall;
109 }
110
111 /*
112  *  returns 1 if the instruction writes memory, 0 otherwise
113  */
114 int
115 writetomem(ulong inst)
116 {
117         /* swap always write memory */
118         if((inst & 0x0FC00000) == 0x01000000)
119                 return 1;
120
121         /* loads and stores are distinguished by bit 20 */
122         if(inst & (1<<20))
123                 return 0;
124
125         return 1;
126 }
127
128 /*
129  *  here on all exceptions other than syscall (SWI) and fiq
130  */
131 void
132 trap(Ureg *ureg)
133 {
134         int clockintr, user, x, rv, rem;
135         ulong inst, fsr;
136         uintptr va;
137         char buf[ERRMAX];
138
139         assert(!islo());
140         if(up != nil)
141                 rem = ((char*)ureg)-up->kstack;
142         else
143                 rem = ((char*)ureg)-((char*)m+sizeof(Mach));
144         if(rem < 256) {
145                 iprint("trap: %d stack bytes left, up %#p ureg %#p at pc %#lux\n",
146                         rem, up, ureg, ureg->pc);
147                 delay(1000);
148                 dumpstack();
149                 panic("trap: %d stack bytes left, up %#p ureg %#p at pc %#lux",
150                         rem, up, ureg, ureg->pc);
151         }
152
153         user = (ureg->psr & PsrMask) == PsrMusr;
154         if(user){
155                 up->dbgreg = ureg;
156                 cycles(&up->kentry);
157         }
158
159         /*
160          * All interrupts/exceptions should be resumed at ureg->pc-4,
161          * except for Data Abort which resumes at ureg->pc-8.
162          */
163         if(ureg->type == (PsrMabt+1))
164                 ureg->pc -= 8;
165         else
166                 ureg->pc -= 4;
167
168         clockintr = 0;          /* if set, may call sched() before return */
169         switch(ureg->type){
170         default:
171                 panic("unknown trap; type %#lux, psr mode %#lux", ureg->type,
172                         ureg->psr & PsrMask);
173                 break;
174         case PsrMirq:
175                 clockintr = irq(ureg);
176                 break;
177         case PsrMabt:                   /* prefetch fault */
178                 x = ifsrget();
179                 fsr = (x>>7) & 0x8 | x & 0x7;
180                 switch(fsr){
181                 case 0x02:              /* instruction debug event (BKPT) */
182                         if(user){
183                                 snprint(buf, sizeof buf, "sys: breakpoint");
184                                 postnote(up, 1, buf, NDebug);
185                         }else{
186                                 iprint("kernel bkpt: pc %#lux inst %#ux\n",
187                                         ureg->pc, *(u32int*)ureg->pc);
188                                 panic("kernel bkpt");
189                         }
190                         break;
191                 default:
192                         faultarm(ureg, ureg->pc, user, 1);
193                         break;
194                 }
195                 break;
196         case PsrMabt+1:                 /* data fault */
197                 va = farget();
198                 inst = *(ulong*)(ureg->pc);
199                 /* bits 12 and 10 have to be concatenated with status */
200                 x = fsrget();
201                 fsr = (x>>7) & 0x20 | (x>>6) & 0x10 | x & 0xf;
202                 switch(fsr){
203                 default:
204                 case 0xa:               /* ? was under external abort */
205                         panic("unknown data fault, 6b fsr %#lux", fsr);
206                         break;
207                 case 0x0:
208                         panic("vector exception at %#lux", ureg->pc);
209                         break;
210                 case 0x1:               /* alignment fault */
211                 case 0x3:               /* access flag fault (section) */
212                         if(user){
213                                 snprint(buf, sizeof buf,
214                                         "sys: alignment: pc %#lux va %#p\n",
215                                         ureg->pc, va);
216                                 postnote(up, 1, buf, NDebug);
217                         } else
218                                 panic("kernel alignment: pc %#lux va %#p", ureg->pc, va);
219                         break;
220                 case 0x2:
221                         panic("terminal exception at %#lux", ureg->pc);
222                         break;
223                 case 0x4:               /* icache maint fault */
224                 case 0x6:               /* access flag fault (page) */
225                 case 0x8:               /* precise external abort, non-xlat'n */
226                 case 0x28:
227                 case 0xc:               /* l1 translation, precise ext. abort */
228                 case 0x2c:
229                 case 0xe:               /* l2 translation, precise ext. abort */
230                 case 0x2e:
231                 case 0x16:              /* imprecise ext. abort, non-xlt'n */
232                 case 0x36:
233                         panic("external abort %#lux pc %#lux addr %#p",
234                                 fsr, ureg->pc, va);
235                         break;
236                 case 0x1c:              /* l1 translation, precise parity err */
237                 case 0x1e:              /* l2 translation, precise parity err */
238                 case 0x18:              /* imprecise parity or ecc err */
239                         panic("translation parity error %#lux pc %#lux addr %#p",
240                                 fsr, ureg->pc, va);
241                         break;
242                 case 0x5:               /* translation fault, no section entry */
243                 case 0x7:               /* translation fault, no page entry */
244                         faultarm(ureg, va, user, !writetomem(inst));
245                         break;
246                 case 0x9:
247                 case 0xb:
248                         /* domain fault, accessing something we shouldn't */
249                         if(user){
250                                 snprint(buf, sizeof buf,
251                                         "sys: access violation: pc %#lux va %#p\n",
252                                         ureg->pc, va);
253                                 postnote(up, 1, buf, NDebug);
254                         } else
255                                 panic("kernel access violation: pc %#lux va %#p",
256                                         ureg->pc, va);
257                         break;
258                 case 0xd:
259                 case 0xf:
260                         /* permission error, copy on write or real permission error */
261                         faultarm(ureg, va, user, !writetomem(inst));
262                         break;
263                 }
264                 break;
265         case PsrMund:                   /* undefined instruction */
266                 if(user){
267                         if(seg(up, ureg->pc, 0) != nil &&
268                            *(u32int*)ureg->pc == 0xD1200070)
269                                 postnote(up, 1, "sys: breakpoint", NDebug);
270                         else{
271                                 /* look for floating point instructions to interpret */
272                                 rv = fpuemu(ureg);
273                                 if(rv == 0){
274                                         snprint(buf, sizeof buf,
275                                                 "undefined instruction: pc %#lux\n",
276                                                 ureg->pc);
277                                         postnote(up, 1, buf, NDebug);
278                                 }
279                         }
280                 }else{
281                         if (ureg->pc & 3) {
282                                 iprint("rounding fault pc %#lux down to word\n",
283                                         ureg->pc);
284                                 ureg->pc &= ~3;
285                         }
286                         iprint("undefined instruction: pc %#lux inst %#ux\n",
287                                 ureg->pc, *(u32int*)ureg->pc);
288                         panic("undefined instruction");
289                 }
290                 break;
291         }
292         splhi();
293
294         /* delaysched set because we held a lock or because our quantum ended */
295         if(up && up->delaysched && clockintr){
296                 sched();                /* can cause more traps */
297                 splhi();
298         }
299
300         if(user){
301                 if(up->procctl || up->nnote)
302                         notify(ureg);
303                 kexit(ureg);
304         }
305 }
306
307 int
308 isvalidaddr(void *v)
309 {
310         return (uintptr)v >= KZERO;
311 }
312
313 static void
314 dumplongs(char *msg, ulong *v, int n)
315 {
316         int i, l;
317
318         l = 0;
319         iprint("%s at %.8p: ", msg, v);
320         for(i=0; i<n; i++){
321                 if(l >= 4){
322                         iprint("\n    %.8p: ", v);
323                         l = 0;
324                 }
325                 if(isvalidaddr(v)){
326                         iprint(" %.8lux", *v++);
327                         l++;
328                 }else{
329                         iprint(" invalid");
330                         break;
331                 }
332         }
333         iprint("\n");
334 }
335
336 static void
337 dumpstackwithureg(Ureg *ureg)
338 {
339         uintptr l, i, v, estack;
340         u32int *p;
341         char *s;
342
343         if((s = getconf("*nodumpstack")) != nil && strcmp(s, "0") != 0){
344                 iprint("dumpstack disabled\n");
345                 return;
346         }
347         iprint("ktrace /kernel/path %#.8lux %#.8lux %#.8lux # pc, sp, link\n",
348                 ureg->pc, ureg->sp, ureg->r14);
349         delay(2000);
350         i = 0;
351         if(up != nil && (uintptr)&l <= (uintptr)up->kstack+KSTACK)
352                 estack = (uintptr)up->kstack+KSTACK;
353         else if((uintptr)&l >= (uintptr)m->stack
354              && (uintptr)&l <= (uintptr)m+MACHSIZE)
355                 estack = (uintptr)m+MACHSIZE;
356         else{
357                 if(up != nil)
358                         iprint("&up->kstack %#p &l %#p\n", up->kstack, &l);
359                 else
360                         iprint("&m %#p &l %#p\n", m, &l);
361                 return;
362         }
363         for(l = (uintptr)&l; l < estack; l += sizeof(uintptr)){
364                 v = *(uintptr*)l;
365                 if(KTZERO < v && v < (uintptr)etext && !(v & 3)){
366                         v -= sizeof(u32int);            /* back up an instr */
367                         p = (u32int*)v;
368                         if((*p & 0x0f000000) == 0x0b000000){    /* BL instr? */
369                                 iprint("%#8.8lux=%#8.8lux ", l, v);
370                                 i++;
371                         }
372                 }
373                 if(i == 4){
374                         i = 0;
375                         iprint("\n");
376                 }
377         }
378         if(i)
379                 iprint("\n");
380 }
381
382 /*
383  * Fill in enough of Ureg to get a stack trace, and call a function.
384  * Used by debugging interface rdb.
385  */
386 void
387 callwithureg(void (*fn)(Ureg*))
388 {
389         Ureg ureg;
390
391         ureg.pc = getcallerpc(&fn);
392         ureg.sp = (uintptr)&fn;
393         fn(&ureg);
394 }
395
396 void
397 dumpstack(void)
398 {
399         callwithureg(dumpstackwithureg);
400 }
401
402 void
403 dumpregs(Ureg* ureg)
404 {
405         int s;
406
407         if (ureg == nil) {
408                 iprint("trap: no user process\n");
409                 return;
410         }
411         s = splhi();
412         iprint("trap: %s", trapname(ureg->type));
413         if(ureg != nil && (ureg->psr & PsrMask) != PsrMsvc)
414                 iprint(" in %s", trapname(ureg->psr));
415         iprint("\n");
416         iprint("psr %8.8lux type %2.2lux pc %8.8lux link %8.8lux\n",
417                 ureg->psr, ureg->type, ureg->pc, ureg->link);
418         iprint("R14 %8.8lux R13 %8.8lux R12 %8.8lux R11 %8.8lux R10 %8.8lux\n",
419                 ureg->r14, ureg->r13, ureg->r12, ureg->r11, ureg->r10);
420         iprint("R9  %8.8lux R8  %8.8lux R7  %8.8lux R6  %8.8lux R5  %8.8lux\n",
421                 ureg->r9, ureg->r8, ureg->r7, ureg->r6, ureg->r5);
422         iprint("R4  %8.8lux R3  %8.8lux R2  %8.8lux R1  %8.8lux R0  %8.8lux\n",
423                 ureg->r4, ureg->r3, ureg->r2, ureg->r1, ureg->r0);
424         iprint("stack is at %#p\n", ureg);
425         iprint("pc %#lux link %#lux\n", ureg->pc, ureg->link);
426
427         if(up)
428                 iprint("user stack: %#p-%#p\n", up->kstack, up->kstack+KSTACK-4);
429         else
430                 iprint("kernel stack: %8.8lux-%8.8lux\n",
431                         (ulong)(m+1), (ulong)m+BY2PG-4);
432         dumplongs("stack", (ulong *)(ureg + 1), 16);
433         delay(2000);
434         dumpstack();
435         splx(s);
436 }