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