]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/zynq/trap.c
kernel: reduce Page structure size by changing Page.cachectl[]
[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, 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                 ((ulong *) sp)[1] = oureg;
427                 ((ulong *) sp)[0] = 0;
428                 break;
429         
430         default:
431                 up->lastnote.flag = NDebug;
432         
433         case NDFLT:
434                 qunlock(&up->debug);
435                 if(up->lastnote.flag == NDebug)
436                         pprint("suicide: %s\n", up->lastnote.msg);
437                 pexit(up->lastnote.msg, up->lastnote.flag != NDebug);
438         }
439 }
440
441
442 void
443 dumpstack(void)
444 {
445         callwithureg(_dumpstack);
446 }
447
448 void
449 dumpregs(Ureg *ureg)
450 {
451         iprint("trap: %lux psr %8.8lux type %2.2lux pc %8.8lux link %8.8lux\n",
452                 ureg->type, ureg->psr, ureg->type, ureg->pc, ureg->link);
453         iprint("R14 %8.8lux R13 %8.8lux R12 %8.8lux R11 %8.8lux R10 %8.8lux\n",
454                 ureg->r14, ureg->r13, ureg->r12, ureg->r11, ureg->r10);
455         iprint("R9  %8.8lux R8  %8.8lux R7  %8.8lux R6  %8.8lux R5  %8.8lux\n",
456                 ureg->r9, ureg->r8, ureg->r7, ureg->r6, ureg->r5);
457         iprint("R4  %8.8lux R3  %8.8lux R2  %8.8lux R1  %8.8lux R0  %8.8lux\n",
458                 ureg->r4, ureg->r3, ureg->r2, ureg->r1, ureg->r0);
459         iprint("pc %#lux link %#lux\n", ureg->pc, ureg->link);
460 }
461
462 void
463 setkernur(Ureg *ureg, Proc *p)
464 {
465         ureg->pc = p->sched.pc;
466         ureg->sp = p->sched.sp + 4;
467         ureg->r14 = (uintptr) sched;
468 }
469
470 void
471 setregisters(Ureg* ureg, char* pureg, char* uva, int n)
472 {
473         ulong v;
474
475         v = ureg->psr;
476         memmove(pureg, uva, n);
477         ureg->psr = ureg->psr & 0xf80f0000 | v & 0x07f0ffff;
478 }
479
480 void
481 callwithureg(void (*f) (Ureg *))
482 {
483         Ureg u;
484         
485         u.pc = getcallerpc(&f);
486         u.sp = (uintptr) &f - 4;
487         f(&u);
488 }
489
490 uintptr
491 userpc(void)
492 {
493         Ureg *ur;
494         
495         ur = up->dbgreg;
496         return ur->pc;
497 }
498
499 uintptr
500 dbgpc(Proc *)
501 {
502         Ureg *ur;
503         
504         ur = up->dbgreg;
505         if(ur == nil)
506                 return 0;
507         return ur->pc;
508 }
509
510 void
511 procsave(Proc *p)
512 {
513         uvlong t;
514
515         if(p->fpstate == FPactive){
516                 if(p->state == Moribund)
517                         fpclear();
518                 else
519                         fpsave(&p->fpsave);
520                 p->fpstate = FPinactive;
521         }
522         cycles(&t);
523         p->kentry -= t;
524         p->pcycles += t;
525
526         l1switch(&m->l1, 0);
527 }
528
529 void
530 procrestore(Proc *p)
531 {
532         uvlong t;
533
534         if(p->kp)
535                 return;
536
537         cycles(&t);
538         p->kentry += t;
539         p->pcycles -= t;
540 }
541
542 static void
543 linkproc(void)
544 {
545         spllo();
546         up->kpfun(up->kparg);
547         pexit("kproc dying", 0);
548 }
549
550 void
551 kprocchild(Proc* p, void (*func)(void*), void* arg)
552 {
553         p->sched.pc = (uintptr) linkproc;
554         p->sched.sp = (uintptr) p->kstack + KSTACK;
555
556         p->kpfun = func;
557         p->kparg = arg;
558 }
559
560 void
561 forkchild(Proc *p, Ureg *ureg)
562 {
563         Ureg *cureg;
564
565         p->sched.pc = (uintptr) forkret;
566         p->sched.sp = (uintptr) p->kstack + KSTACK - sizeof(Ureg);
567
568         cureg = (Ureg*) p->sched.sp;
569         memmove(cureg, ureg, sizeof(Ureg));
570         cureg->r0 = 0;
571
572         p->psstate = 0;
573         p->insyscall = 0;
574 }
575
576 uintptr
577 execregs(uintptr entry, ulong ssize, ulong nargs)
578 {
579         ulong *sp;
580         Ureg *ureg;
581
582         sp = (ulong*)(USTKTOP - ssize);
583         *--sp = nargs;
584
585         ureg = up->dbgreg;
586         ureg->sp = (uintptr) sp;
587         ureg->pc = entry;
588         ureg->r14 = 0;
589         return USTKTOP-sizeof(Tos);
590 }