]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/zynq/trap.c
audiohda: fix syntax error
[plan9front.git] / sys / src / 9 / zynq / trap.c
1 #include "u.h"
2 #include <ureg.h>
3 #include "../port/lib.h"
4 #include "mem.h"
5 #include "dat.h"
6 #include "fns.h"
7 #include "io.h"
8 #include "../port/error.h"
9 #include "tos.h"
10
11 static void
12 _dumpstack(Ureg *ureg)
13 {
14         uintptr l, v, i, estack;
15         extern ulong etext;
16         int x;
17         char *s;
18
19         if((s = getconf("*nodumpstack")) != nil && strcmp(s, "0") != 0){
20                 iprint("dumpstack disabled\n");
21                 return;
22         }
23         iprint("cpu%d: dumpstack\n", m->machno);
24
25         x = 0;
26         x += iprint("ktrace /arm/9zynq %.8lux %.8lux %.8lux <<EOF\n", ureg->pc, ureg->sp, ureg->r14);
27         i = 0;
28         if(up
29         && (uintptr)&l >= (uintptr)up->kstack
30         && (uintptr)&l <= (uintptr)up->kstack+KSTACK)
31                 estack = (uintptr)up->kstack+KSTACK;
32         else if((uintptr)&l >= (uintptr)m->stack
33         && (uintptr)&l <= (uintptr)m+MACHSIZE)
34                 estack = (uintptr)m+MACHSIZE;
35         else
36                 return;
37         x += iprint("estackx %p\n", estack);
38
39         for(l = (uintptr)&l; l < estack; l += sizeof(uintptr)){
40                 v = *(uintptr*)l;
41                 if((KTZERO < v && v < (uintptr)&etext) || estack-l < 32){
42                         x += iprint("%.8p=%.8p ", l, v);
43                         i++;
44                 }
45                 if(i == 4){
46                         i = 0;
47                         x += iprint("\n");
48                 }
49         }
50         if(i)
51                 iprint("\n");
52         iprint("EOF\n");
53 }
54
55 static char*
56 faulterr[0x20] = {
57 [0x01]  "alignement fault",
58 [0x02]  "debug event",
59 [0x04]  "fault on instruction cache maintenance",
60 [0x08]  "synchronous external abort",
61 [0x0C]  "synchronous external abort on translation table walk L1",
62 [0x0E]  "synchronous external abort on translation table walk L2",
63 [0x10]  "tlb conflict abort",
64 [0x16]  "asynchronous external abort",
65 [0x19]  "synchronous parity error on memory access",
66 [0x1C]  "synchronous parity error on translation table walk L1",
67 [0x1E]  "synchronous parity error on translation table walk L2",
68 };
69
70 static void
71 faultarm(Ureg *ureg, ulong fsr, uintptr addr)
72 {
73         int user, insyscall, read;
74         static char buf[ERRMAX];
75         char *err;
76
77         read = (fsr & (1<<11)) == 0;
78         user = userureg(ureg);
79         if(!user){
80                 if(addr >= USTKTOP || up == nil)
81                         _dumpstack(ureg);
82                 if(addr >= USTKTOP)
83                         panic("kernel fault: bad address pc=%#.8lux addr=%#.8lux fsr=%#.8lux", ureg->pc, addr, fsr);
84                 if(up == nil)
85                         panic("kernel fault: no user process pc=%#.8lux addr=%#.8lux fsr=%#.8lux", ureg->pc, addr, fsr);
86         }
87         if(up == nil)
88                 panic("user fault: up=nil pc=%#.8lux addr=%#.8lux fsr=%#.8lux", ureg->pc, addr, fsr);
89
90         insyscall = up->insyscall;
91         up->insyscall = 1;
92         switch(fsr & 0x1F){
93         case 0x05:      /* translation fault L1 */
94         case 0x07:      /* translation fault L2 */
95         case 0x03:      /* access flag fault L1 */
96         case 0x06:      /* access flag fault L2 */
97         case 0x09:      /* domain fault L1 */
98         case 0x0B:      /* domain fault L2 */
99         case 0x0D:      /* permission fault L1 */
100         case 0x0F:      /* permission fault L2 */
101                 if(fault(addr, ureg->pc, read) == 0)
102                         break;
103                 /* wet floor */
104         default:
105                 err = faulterr[fsr & 0x1F];
106                 if(err == nil)
107                         err = "fault";
108                 if(!user){
109                         dumpregs(ureg);
110                         _dumpstack(ureg);
111                         panic("kernel %s: pc=%#.8lux addr=%#.8lux fsr=%#.8lux", err, ureg->pc, addr, fsr);
112                 }
113                 sprint(buf, "sys: trap: %s %s addr=%#.8lux", err, read ? "read" : "write", addr);
114                 postnote(up, 1, buf, NDebug);
115         }
116         up->insyscall = insyscall;
117 }
118
119 static void
120 mathtrap(Ureg *, ulong)
121 {
122         int s;
123
124         if((up->fpstate & FPillegal) != 0){
125                 postnote(up, 1, "sys: floating point in note handler", NDebug);
126                 return;
127         }
128         switch(up->fpstate){
129         case FPinit:
130                 s = splhi();
131                 fpinit();
132                 up->fpstate = FPactive;
133                 splx(s);
134                 break;
135         case FPinactive:
136                 s = splhi();
137                 fprestore(up->fpsave);
138                 up->fpstate = FPactive;
139                 splx(s);
140                 break;
141         case FPactive:
142                 postnote(up, 1, "sys: floating point error", NDebug);
143                 break;
144         }
145 }
146
147 void
148 trap(Ureg *ureg)
149 {
150         int user;
151         ulong opc, cp;
152
153         user = kenter(ureg);
154         switch(ureg->type){
155         case PsrMund:
156                 ureg->pc -= 4;
157                 if(user){
158                         spllo();
159                         if(okaddr(ureg->pc, 4, 0)){
160                                 opc = *(ulong*)ureg->pc;
161                                 if((opc & 0x0f000000) == 0x0e000000 || (opc & 0x0e000000) == 0x0c000000){
162                                         cp = opc >> 8 & 15;
163                                         if(cp == 10 || cp == 11){
164                                                 mathtrap(ureg, opc);
165                                                 break;
166                                         }
167                                 }
168                         }
169                         postnote(up, 1, "sys: trap: invalid opcode", NDebug);
170                         break;
171                 }
172                 dumpregs(ureg);
173                 panic("invalid opcode at pc=%#.8lux lr=%#.8lux", ureg->pc, ureg->r14);
174                 break;
175         case PsrMiabt:
176                 ureg->pc -= 4;
177                 faultarm(ureg, getifsr(), getifar());
178                 break;
179         case PsrMabt:
180                 ureg->pc -= 8;
181                 faultarm(ureg, getdfsr(), getdfar());
182                 break;
183         case PsrMirq:
184                 ureg->pc -= 4;
185                 intr(ureg);
186                 break;
187         default:
188                 iprint("cpu%d: unknown trap type %ulx\n", m->machno, ureg->type);
189         }
190         splhi();
191         if(user){
192                 if(up->procctl || up->nnote)
193                         notify(ureg);
194                 kexit(ureg);
195         }
196 }
197
198 #include "../port/systab.h"
199
200 void
201 syscall(Ureg *ureg)
202 {
203         char *e;
204         uintptr sp;
205         long ret;
206         int i, s;
207         ulong scallnr;
208         vlong startns, stopns;
209         
210         if(!kenter(ureg))
211                 panic("syscall: pc=%#.8lux", ureg->pc);
212         
213         m->syscall++;
214         up->insyscall = 1;
215         up->pc = ureg->pc;
216         
217         sp = ureg->sp;
218         up->scallnr = scallnr = ureg->r0;
219
220         spllo();
221         
222         up->nerrlab = 0;
223         ret = -1;
224         if(!waserror()){
225                 if(sp < USTKTOP - BY2PG || sp > USTKTOP - sizeof(Sargs) - BY2WD){
226                         validaddr(sp, sizeof(Sargs)+BY2WD, 0);
227                         evenaddr(sp);
228                 }
229                 up->s = *((Sargs*) (sp + BY2WD));
230                 
231                 if(up->procctl == Proc_tracesyscall){
232                         syscallfmt(scallnr, ureg->pc, (va_list) up->s.args);
233                         s = splhi();
234                         up->procctl = Proc_stopme;
235                         procctl();
236                         splx(s);
237                         startns = todget(nil);
238                 }
239                 
240                 if(scallnr >= nsyscall || systab[scallnr] == 0){
241                         pprint("bad sys call number %lud pc %lux", scallnr, ureg->pc);
242                         postnote(up, 1, "sys: bad sys call", NDebug);
243                         error(Ebadarg);
244                 }
245                 up->psstate = sysctab[scallnr];
246                 ret = systab[scallnr]((va_list)up->s.args);
247                 poperror();
248         }else{
249                 e = up->syserrstr;
250                 up->syserrstr = up->errstr;
251                 up->errstr = e;
252         }
253         if(up->nerrlab){
254                 print("bad errstack [%lud]: %d extra\n", scallnr, up->nerrlab);
255                 for(i = 0; i < NERR; i++)
256                         print("sp=%lux pc=%lux\n", up->errlab[i].sp, up->errlab[i].pc);
257                 panic("error stack");
258         }
259         
260         ureg->r0 = ret;
261         if(up->procctl == Proc_tracesyscall){
262                 stopns = todget(nil);
263                 sysretfmt(scallnr, (va_list) up->s.args, ret, startns, stopns);
264                 s = splhi();
265                 up->procctl = Proc_stopme;
266                 procctl();
267                 splx(s);
268         }
269         
270         up->insyscall = 0;
271         up->psstate = 0;
272         if(scallnr == NOTED)
273                 noted(ureg, *((ulong *) up->s.args));
274
275         if(scallnr != RFORK && (up->procctl || up->nnote)){
276                 splhi();
277                 notify(ureg);
278         }
279         if(up->delaysched)
280                 sched();
281         kexit(ureg);
282         splhi();
283 }
284
285 int
286 notify(Ureg *ureg)
287 {
288         int l;
289         ulong s, sp;
290         Note *n;
291
292         if(up->procctl)
293                 procctl();
294         if(up->nnote == 0)
295                 return 0;
296
297         if(up->fpstate == FPactive){
298                 fpsave(up->fpsave);
299                 up->fpstate = FPinactive;
300         }
301         up->fpstate |= FPillegal;
302
303         s = spllo();
304         qlock(&up->debug);
305         up->notepending = 0;
306         n = &up->note[0];
307         if(strncmp(n->msg, "sys:", 4) == 0){
308                 l = strlen(n->msg);
309                 if(l > ERRMAX-15)       /* " pc=0x12345678\0" */
310                         l = ERRMAX-15;
311                 sprint(n->msg+l, " pc=0x%.8lux", ureg->pc);
312         }
313
314         if(n->flag!=NUser && (up->notified || up->notify==0)){
315                 qunlock(&up->debug);
316                 if(n->flag == NDebug)
317                         pprint("suicide: %s\n", n->msg);
318                 pexit(n->msg, n->flag!=NDebug);
319         }
320
321         if(up->notified){
322                 qunlock(&up->debug);
323                 splhi();
324                 return 0;
325         }
326
327         if(!up->notify){
328                 qunlock(&up->debug);
329                 pexit(n->msg, n->flag!=NDebug);
330         }
331         sp = ureg->sp;
332         sp -= 256;      /* debugging: preserve context causing problem */
333         sp -= sizeof(Ureg);
334
335         if(!okaddr((uintptr)up->notify, 1, 0)
336         || !okaddr(sp-ERRMAX-4*BY2WD, sizeof(Ureg)+ERRMAX+4*BY2WD, 1)
337         || ((uintptr) up->notify & 3) != 0
338         || (sp & 3) != 0){
339                 qunlock(&up->debug);
340                 pprint("suicide: bad address in notify\n");
341                 pexit("Suicide", 0);
342         }
343
344         memmove((Ureg*)sp, ureg, sizeof(Ureg));
345         *(Ureg**)(sp-BY2WD) = up->ureg; /* word under Ureg is old up->ureg */
346         up->ureg = (void*)sp;
347         sp -= BY2WD+ERRMAX;
348         memmove((char*)sp, up->note[0].msg, ERRMAX);
349         sp -= 3*BY2WD;
350         *(ulong*)(sp+2*BY2WD) = sp+3*BY2WD;
351         *(ulong*)(sp+1*BY2WD) = (ulong)up->ureg;
352         ureg->r0 = (uintptr) up->ureg;
353         ureg->sp = sp;
354         ureg->pc = (uintptr) up->notify;
355         ureg->r14 = 0;
356         up->notified = 1;
357         up->nnote--;
358         memmove(&up->lastnote, &up->note[0], sizeof(Note));
359         memmove(&up->note[0], &up->note[1], up->nnote*sizeof(Note));
360
361         qunlock(&up->debug);
362         splx(s);
363         return 1;
364 }
365
366 void
367 noted(Ureg *ureg, ulong arg0)
368 {
369         Ureg *nureg;
370         ulong oureg, sp;
371         
372         qlock(&up->debug);
373         if(arg0 != NRSTR && !up->notified){
374                 qunlock(&up->debug);
375                 pprint("call to noted() when not notified\n");
376                 pexit("Suicide", 0);
377         }
378         up->notified = 0;
379         
380         nureg = up->ureg;
381         up->fpstate &= ~FPillegal;
382         
383         oureg = (ulong) nureg;
384         if(!okaddr(oureg - BY2WD, BY2WD + sizeof(Ureg), 0) || (oureg & 3) != 0){
385                 qunlock(&up->debug);
386                 pprint("bad ureg in noted or call to noted when not notified\n");
387                 pexit("Suicide", 0);
388         }
389         
390         nureg->psr = nureg->psr & 0xf80f0000 | ureg->psr & 0x07f0ffff;
391         
392         memmove(ureg, nureg, sizeof(Ureg));
393         
394         switch(arg0){
395         case NCONT: case NRSTR:
396                 if(!okaddr(nureg->pc, BY2WD, 0) || !okaddr(nureg->sp, BY2WD, 0) ||
397                                 (nureg->pc & 3) != 0 || (nureg->sp & 3) != 0){
398                         qunlock(&up->debug);
399                         pprint("suicide: trap in noted\n");
400                         pexit("Suicide", 0);
401                 }
402                 up->ureg = (Ureg *) (*(ulong *) (oureg - BY2WD));
403                 qunlock(&up->debug);
404                 break;
405         
406         case NSAVE:
407                 if(!okaddr(nureg->pc, BY2WD, 0) || !okaddr(nureg->sp, BY2WD, 0) ||
408                                 (nureg->pc & 3) != 0 || (nureg->sp & 3) != 0){
409                         qunlock(&up->debug);
410                         pprint("suicide: trap in noted\n");
411                         pexit("Suicide", 0);
412                 }
413                 qunlock(&up->debug);
414                 sp = oureg - 4 * BY2WD - ERRMAX;
415                 splhi();
416                 ureg->sp = sp;
417                 ureg->r0 = (uintptr) oureg;
418                 ((ulong *) sp)[1] = oureg;
419                 ((ulong *) sp)[0] = 0;
420                 break;
421         
422         default:
423                 up->lastnote.flag = NDebug;
424         
425         case NDFLT:
426                 qunlock(&up->debug);
427                 if(up->lastnote.flag == NDebug)
428                         pprint("suicide: %s\n", up->lastnote.msg);
429                 pexit(up->lastnote.msg, up->lastnote.flag != NDebug);
430         }
431 }
432
433
434 void
435 dumpstack(void)
436 {
437         callwithureg(_dumpstack);
438 }
439
440 void
441 dumpregs(Ureg *ureg)
442 {
443         iprint("trap: %lux psr %8.8lux type %2.2lux pc %8.8lux link %8.8lux\n",
444                 ureg->type, ureg->psr, ureg->type, ureg->pc, ureg->link);
445         iprint("R14 %8.8lux R13 %8.8lux R12 %8.8lux R11 %8.8lux R10 %8.8lux\n",
446                 ureg->r14, ureg->r13, ureg->r12, ureg->r11, ureg->r10);
447         iprint("R9  %8.8lux R8  %8.8lux R7  %8.8lux R6  %8.8lux R5  %8.8lux\n",
448                 ureg->r9, ureg->r8, ureg->r7, ureg->r6, ureg->r5);
449         iprint("R4  %8.8lux R3  %8.8lux R2  %8.8lux R1  %8.8lux R0  %8.8lux\n",
450                 ureg->r4, ureg->r3, ureg->r2, ureg->r1, ureg->r0);
451         iprint("pc %#lux link %#lux\n", ureg->pc, ureg->link);
452 }
453
454 void
455 setkernur(Ureg *ureg, Proc *p)
456 {
457         ureg->pc = p->sched.pc;
458         ureg->sp = p->sched.sp + 4;
459         ureg->r14 = (uintptr) sched;
460 }
461
462 void
463 setregisters(Ureg* ureg, char* pureg, char* uva, int n)
464 {
465         ulong v;
466
467         v = ureg->psr;
468         memmove(pureg, uva, n);
469         ureg->psr = ureg->psr & 0xf80f0000 | v & 0x07f0ffff;
470 }
471
472 void
473 callwithureg(void (*f) (Ureg *))
474 {
475         Ureg u;
476         
477         u.pc = getcallerpc(&f);
478         u.sp = (uintptr) &f - 4;
479         f(&u);
480 }
481
482 uintptr
483 userpc(void)
484 {
485         Ureg *ur;
486         
487         ur = up->dbgreg;
488         return ur->pc;
489 }
490
491 uintptr
492 dbgpc(Proc *)
493 {
494         Ureg *ur;
495         
496         ur = up->dbgreg;
497         if(ur == nil)
498                 return 0;
499         return ur->pc;
500 }
501
502 void
503 procsave(Proc *p)
504 {
505         if(p->fpstate == FPactive){
506                 if(p->state == Moribund)
507                         fpclear();
508                 else
509                         fpsave(p->fpsave);
510                 p->fpstate = FPinactive;
511         }
512         l1switch(&m->l1, 0);
513 }
514
515 void
516 procrestore(Proc *p)
517 {
518 }
519
520 void
521 kprocchild(Proc *p, void (*entry)(void))
522 {
523         p->sched.pc = (uintptr) entry;
524         p->sched.sp = (uintptr) p->kstack + KSTACK;
525 }
526
527 void
528 forkchild(Proc *p, Ureg *ureg)
529 {
530         Ureg *cureg;
531
532         p->sched.pc = (uintptr) forkret;
533         p->sched.sp = (uintptr) p->kstack + KSTACK - sizeof(Ureg);
534
535         cureg = (Ureg*) p->sched.sp;
536         memmove(cureg, ureg, sizeof(Ureg));
537         cureg->r0 = 0;
538 }
539
540 uintptr
541 execregs(uintptr entry, ulong ssize, ulong nargs)
542 {
543         ulong *sp;
544         Ureg *ureg;
545
546         sp = (ulong*)(USTKTOP - ssize);
547         *--sp = nargs;
548
549         ureg = up->dbgreg;
550         ureg->sp = (uintptr) sp;
551         ureg->pc = entry;
552         ureg->r14 = 0;
553         return USTKTOP-sizeof(Tos);
554 }