]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/zynq/trap.c
devip: implement ipv6 support in ipmux packet filter
[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 = userureg(ureg);
154         if(user){
155                 if(up == nil)
156                         panic("user trap: up=nil");
157                 up->dbgreg = ureg;
158                 cycles(&up->kentry);
159         }
160         switch(ureg->type){
161         case PsrMund:
162                 ureg->pc -= 4;
163                 if(user){
164                         spllo();
165                         if(okaddr(ureg->pc, 4, 0)){
166                                 opc = *(ulong*)ureg->pc;
167                                 if((opc & 0x0f000000) == 0x0e000000 || (opc & 0x0e000000) == 0x0c000000){
168                                         cp = opc >> 8 & 15;
169                                         if(cp == 10 || cp == 11){
170                                                 mathtrap(ureg, opc);
171                                                 break;
172                                         }
173                                 }
174                         }
175                         postnote(up, 1, "sys: trap: invalid opcode", NDebug);
176                         break;
177                 }
178                 dumpregs(ureg);
179                 panic("invalid opcode at pc=%#.8lux lr=%#.8lux", ureg->pc, ureg->r14);
180                 break;
181         case PsrMiabt:
182                 ureg->pc -= 4;
183                 faultarm(ureg, getifsr(), getifar());
184                 break;
185         case PsrMabt:
186                 ureg->pc -= 8;
187                 faultarm(ureg, getdfsr(), getdfar());
188                 break;
189         case PsrMirq:
190                 ureg->pc -= 4;
191                 intr(ureg);
192                 break;
193         default:
194                 iprint("cpu%d: unknown trap type %ulx\n", m->machno, ureg->type);
195         }
196         splhi();
197         if(user){
198                 if(up->procctl || up->nnote)
199                         notify(ureg);
200                 kexit(ureg);
201         }
202 }
203
204 #include "../port/systab.h"
205
206 void
207 syscall(Ureg *ureg)
208 {
209         char *e;
210         uintptr sp;
211         long ret;
212         int i, s;
213         ulong scallnr;
214         vlong startns, stopns;
215         
216         if(!userureg(ureg))
217                 panic("syscall: pc=%#.8lux", ureg->pc);
218         
219         cycles(&up->kentry);
220         
221         m->syscall++;
222         up->insyscall = 1;
223         up->pc = ureg->pc;
224         up->dbgreg = ureg;
225         
226         sp = ureg->sp;
227         up->scallnr = scallnr = ureg->r0;
228
229         spllo();
230         
231         up->nerrlab = 0;
232         ret = -1;
233         if(!waserror()){
234                 if(sp < USTKTOP - BY2PG || sp > USTKTOP - sizeof(Sargs) - BY2WD){
235                         validaddr(sp, sizeof(Sargs)+BY2WD, 0);
236                         evenaddr(sp);
237                 }
238                 up->s = *((Sargs*) (sp + BY2WD));
239                 
240                 if(up->procctl == Proc_tracesyscall){
241                         syscallfmt(scallnr, ureg->pc, (va_list) up->s.args);
242                         s = splhi();
243                         up->procctl = Proc_stopme;
244                         procctl();
245                         splx(s);
246                         startns = todget(nil);
247                 }
248                 
249                 if(scallnr >= nsyscall || systab[scallnr] == 0){
250                         pprint("bad sys call number %lud pc %lux", scallnr, ureg->pc);
251                         postnote(up, 1, "sys: bad sys call", NDebug);
252                         error(Ebadarg);
253                 }
254                 up->psstate = sysctab[scallnr];
255                 ret = systab[scallnr]((va_list)up->s.args);
256                 poperror();
257         }else{
258                 e = up->syserrstr;
259                 up->syserrstr = up->errstr;
260                 up->errstr = e;
261         }
262         if(up->nerrlab){
263                 print("bad errstack [%lud]: %d extra\n", scallnr, up->nerrlab);
264                 for(i = 0; i < NERR; i++)
265                         print("sp=%lux pc=%lux\n", up->errlab[i].sp, up->errlab[i].pc);
266                 panic("error stack");
267         }
268         
269         ureg->r0 = ret;
270         if(up->procctl == Proc_tracesyscall){
271                 stopns = todget(nil);
272                 sysretfmt(scallnr, (va_list) up->s.args, ret, startns, stopns);
273                 s = splhi();
274                 up->procctl = Proc_stopme;
275                 procctl();
276                 splx(s);
277         }
278         
279         up->insyscall = 0;
280         up->psstate = 0;
281         if(scallnr == NOTED)
282                 noted(ureg, *((ulong *) up->s.args));
283
284         if(scallnr != RFORK && (up->procctl || up->nnote)){
285                 splhi();
286                 notify(ureg);
287         }
288         if(up->delaysched)
289                 sched();
290         kexit(ureg);
291         splhi();
292 }
293
294 int
295 notify(Ureg *ureg)
296 {
297         int l;
298         ulong s, sp;
299         Note *n;
300
301         if(up->procctl)
302                 procctl();
303         if(up->nnote == 0)
304                 return 0;
305
306         if(up->fpstate == FPactive){
307                 fpsave(up->fpsave);
308                 up->fpstate = FPinactive;
309         }
310         up->fpstate |= FPillegal;
311
312         s = spllo();
313         qlock(&up->debug);
314         up->notepending = 0;
315         n = &up->note[0];
316         if(strncmp(n->msg, "sys:", 4) == 0){
317                 l = strlen(n->msg);
318                 if(l > ERRMAX-15)       /* " pc=0x12345678\0" */
319                         l = ERRMAX-15;
320                 sprint(n->msg+l, " pc=0x%.8lux", ureg->pc);
321         }
322
323         if(n->flag!=NUser && (up->notified || up->notify==0)){
324                 qunlock(&up->debug);
325                 if(n->flag == NDebug)
326                         pprint("suicide: %s\n", n->msg);
327                 pexit(n->msg, n->flag!=NDebug);
328         }
329
330         if(up->notified){
331                 qunlock(&up->debug);
332                 splhi();
333                 return 0;
334         }
335
336         if(!up->notify){
337                 qunlock(&up->debug);
338                 pexit(n->msg, n->flag!=NDebug);
339         }
340         sp = ureg->sp;
341         sp -= 256;      /* debugging: preserve context causing problem */
342         sp -= sizeof(Ureg);
343
344         if(!okaddr((uintptr)up->notify, 1, 0)
345         || !okaddr(sp-ERRMAX-4*BY2WD, sizeof(Ureg)+ERRMAX+4*BY2WD, 1)
346         || ((uintptr) up->notify & 3) != 0
347         || (sp & 3) != 0){
348                 qunlock(&up->debug);
349                 pprint("suicide: bad address in notify\n");
350                 pexit("Suicide", 0);
351         }
352
353         memmove((Ureg*)sp, ureg, sizeof(Ureg));
354         *(Ureg**)(sp-BY2WD) = up->ureg; /* word under Ureg is old up->ureg */
355         up->ureg = (void*)sp;
356         sp -= BY2WD+ERRMAX;
357         memmove((char*)sp, up->note[0].msg, ERRMAX);
358         sp -= 3*BY2WD;
359         *(ulong*)(sp+2*BY2WD) = sp+3*BY2WD;
360         *(ulong*)(sp+1*BY2WD) = (ulong)up->ureg;
361         ureg->r0 = (uintptr) up->ureg;
362         ureg->sp = sp;
363         ureg->pc = (uintptr) up->notify;
364         ureg->r14 = 0;
365         up->notified = 1;
366         up->nnote--;
367         memmove(&up->lastnote, &up->note[0], sizeof(Note));
368         memmove(&up->note[0], &up->note[1], up->nnote*sizeof(Note));
369
370         qunlock(&up->debug);
371         splx(s);
372         return 1;
373 }
374
375 void
376 noted(Ureg *ureg, ulong arg0)
377 {
378         Ureg *nureg;
379         ulong oureg, sp;
380         
381         qlock(&up->debug);
382         if(arg0 != NRSTR && !up->notified){
383                 qunlock(&up->debug);
384                 pprint("call to noted() when not notified\n");
385                 pexit("Suicide", 0);
386         }
387         up->notified = 0;
388         
389         nureg = up->ureg;
390         up->fpstate &= ~FPillegal;
391         
392         oureg = (ulong) nureg;
393         if(!okaddr(oureg - BY2WD, BY2WD + sizeof(Ureg), 0) || (oureg & 3) != 0){
394                 qunlock(&up->debug);
395                 pprint("bad ureg in noted or call to noted when not notified\n");
396                 pexit("Suicide", 0);
397         }
398         
399         nureg->psr = nureg->psr & 0xf80f0000 | ureg->psr & 0x07f0ffff;
400         
401         memmove(ureg, nureg, sizeof(Ureg));
402         
403         switch(arg0){
404         case NCONT: case NRSTR:
405                 if(!okaddr(nureg->pc, BY2WD, 0) || !okaddr(nureg->sp, BY2WD, 0) ||
406                                 (nureg->pc & 3) != 0 || (nureg->sp & 3) != 0){
407                         qunlock(&up->debug);
408                         pprint("suicide: trap in noted\n");
409                         pexit("Suicide", 0);
410                 }
411                 up->ureg = (Ureg *) (*(ulong *) (oureg - BY2WD));
412                 qunlock(&up->debug);
413                 break;
414         
415         case NSAVE:
416                 if(!okaddr(nureg->pc, BY2WD, 0) || !okaddr(nureg->sp, BY2WD, 0) ||
417                                 (nureg->pc & 3) != 0 || (nureg->sp & 3) != 0){
418                         qunlock(&up->debug);
419                         pprint("suicide: trap in noted\n");
420                         pexit("Suicide", 0);
421                 }
422                 qunlock(&up->debug);
423                 sp = oureg - 4 * BY2WD - ERRMAX;
424                 splhi();
425                 ureg->sp = sp;
426                 ureg->r0 = (uintptr) oureg;
427                 ((ulong *) sp)[1] = oureg;
428                 ((ulong *) sp)[0] = 0;
429                 break;
430         
431         default:
432                 up->lastnote.flag = NDebug;
433         
434         case NDFLT:
435                 qunlock(&up->debug);
436                 if(up->lastnote.flag == NDebug)
437                         pprint("suicide: %s\n", up->lastnote.msg);
438                 pexit(up->lastnote.msg, up->lastnote.flag != NDebug);
439         }
440 }
441
442
443 void
444 dumpstack(void)
445 {
446         callwithureg(_dumpstack);
447 }
448
449 void
450 dumpregs(Ureg *ureg)
451 {
452         iprint("trap: %lux psr %8.8lux type %2.2lux pc %8.8lux link %8.8lux\n",
453                 ureg->type, ureg->psr, ureg->type, ureg->pc, ureg->link);
454         iprint("R14 %8.8lux R13 %8.8lux R12 %8.8lux R11 %8.8lux R10 %8.8lux\n",
455                 ureg->r14, ureg->r13, ureg->r12, ureg->r11, ureg->r10);
456         iprint("R9  %8.8lux R8  %8.8lux R7  %8.8lux R6  %8.8lux R5  %8.8lux\n",
457                 ureg->r9, ureg->r8, ureg->r7, ureg->r6, ureg->r5);
458         iprint("R4  %8.8lux R3  %8.8lux R2  %8.8lux R1  %8.8lux R0  %8.8lux\n",
459                 ureg->r4, ureg->r3, ureg->r2, ureg->r1, ureg->r0);
460         iprint("pc %#lux link %#lux\n", ureg->pc, ureg->link);
461 }
462
463 void
464 setkernur(Ureg *ureg, Proc *p)
465 {
466         ureg->pc = p->sched.pc;
467         ureg->sp = p->sched.sp + 4;
468         ureg->r14 = (uintptr) sched;
469 }
470
471 void
472 setregisters(Ureg* ureg, char* pureg, char* uva, int n)
473 {
474         ulong v;
475
476         v = ureg->psr;
477         memmove(pureg, uva, n);
478         ureg->psr = ureg->psr & 0xf80f0000 | v & 0x07f0ffff;
479 }
480
481 void
482 callwithureg(void (*f) (Ureg *))
483 {
484         Ureg u;
485         
486         u.pc = getcallerpc(&f);
487         u.sp = (uintptr) &f - 4;
488         f(&u);
489 }
490
491 uintptr
492 userpc(void)
493 {
494         Ureg *ur;
495         
496         ur = up->dbgreg;
497         return ur->pc;
498 }
499
500 uintptr
501 dbgpc(Proc *)
502 {
503         Ureg *ur;
504         
505         ur = up->dbgreg;
506         if(ur == nil)
507                 return 0;
508         return ur->pc;
509 }
510
511 void
512 procsave(Proc *p)
513 {
514         uvlong t;
515
516         if(p->fpstate == FPactive){
517                 if(p->state == Moribund)
518                         fpclear();
519                 else
520                         fpsave(p->fpsave);
521                 p->fpstate = FPinactive;
522         }
523         cycles(&t);
524         p->kentry -= t;
525         p->pcycles += t;
526
527         l1switch(&m->l1, 0);
528 }
529
530 void
531 procrestore(Proc *p)
532 {
533         uvlong t;
534
535         if(p->kp)
536                 return;
537
538         cycles(&t);
539         p->kentry += t;
540         p->pcycles -= t;
541 }
542
543 static void
544 linkproc(void)
545 {
546         spllo();
547         up->kpfun(up->kparg);
548         pexit("kproc dying", 0);
549 }
550
551 void
552 kprocchild(Proc* p, void (*func)(void*), void* arg)
553 {
554         p->sched.pc = (uintptr) linkproc;
555         p->sched.sp = (uintptr) p->kstack + KSTACK;
556
557         p->kpfun = func;
558         p->kparg = arg;
559 }
560
561 void
562 forkchild(Proc *p, Ureg *ureg)
563 {
564         Ureg *cureg;
565
566         p->sched.pc = (uintptr) forkret;
567         p->sched.sp = (uintptr) p->kstack + KSTACK - sizeof(Ureg);
568
569         cureg = (Ureg*) p->sched.sp;
570         memmove(cureg, ureg, sizeof(Ureg));
571         cureg->r0 = 0;
572 }
573
574 uintptr
575 execregs(uintptr entry, ulong ssize, ulong nargs)
576 {
577         ulong *sp;
578         Ureg *ureg;
579
580         sp = (ulong*)(USTKTOP - ssize);
581         *--sp = nargs;
582
583         ureg = up->dbgreg;
584         ureg->sp = (uintptr) sp;
585         ureg->pc = entry;
586         ureg->r14 = 0;
587         return USTKTOP-sizeof(Tos);
588 }