2 #include "../port/lib.h"
6 #include "../port/error.h"
7 #include "../port/systab.h"
13 /* SPSR bits user can modify */
14 #define USPSRMASK (0xFULL<<28)
17 setupvector(u32int *v, void (*t)(void), void (*f)(void))
21 for(i = 0; i < 0x80/4; i++){
22 v[i] = ((u32int*)t)[i];
23 if(v[i] == 0x14000000){
24 v[i] |= ((u32int*)f - &v[i]) & 0x3ffffff;
28 panic("bug in vector code");
34 extern void vsys(void);
35 extern void vtrap(void);
36 extern void virq(void);
37 extern void vfiq(void);
38 extern void vserr(void);
40 extern void vsys0(void);
41 extern void vtrap0(void);
42 extern void vtrap1(void);
48 /* disable everything */
51 v = mallocalign(0x80*4*4, 1<<11, 0, 0);
53 panic("no memory for vector table");
55 setupvector(&v[0x000/4], vtrap, vtrap0);
56 setupvector(&v[0x080/4], virq, vtrap0);
57 setupvector(&v[0x100/4], vfiq, vtrap0);
58 setupvector(&v[0x180/4], vserr, vtrap0);
60 setupvector(&v[0x200/4], vtrap, vtrap1);
61 setupvector(&v[0x280/4], virq, vtrap1);
62 setupvector(&v[0x300/4], vfiq, vtrap1);
63 setupvector(&v[0x380/4], vserr, vtrap1);
65 setupvector(&v[0x400/4], vsys, vsys0);
66 setupvector(&v[0x480/4], virq, vtrap0);
67 setupvector(&v[0x500/4], vfiq, vtrap0);
68 setupvector(&v[0x580/4], vserr, vtrap0);
70 setupvector(&v[0x600/4], vtrap, vtrap0);
71 setupvector(&v[0x680/4], virq, vtrap0);
72 setupvector(&v[0x700/4], vfiq, vtrap0);
73 setupvector(&v[0x780/4], vserr, vtrap0);
75 cacheduwbse(v, 0x80*4*4);
77 cacheiinvse(v, 0x80*4*4);
78 syswr(VBAR_EL1, (uintptr)v);
79 splx(0x3<<6); // unmask serr and debug
90 tos = (Tos*)(USTKTOP-sizeof(Tos));
91 tos->kcycles += t - up->kentry;
92 tos->pcycles = t + up->pcycles;
96 static char *traps[64] = {
97 [0x00] "sys: trap: unknown",
98 [0x01] "sys: trap: WFI or WFE instruction execution",
99 [0x0E] "sys: trap: illegal execution state",
100 [0x18] "sys: trap: illegal MSR/MRS access",
101 [0x22] "sys: trap: misaligned pc",
102 [0x26] "sys: trap: stack pointer misaligned",
103 [0x30] "sys: trap: breakpoint",
104 [0x32] "sys: trap: software step",
105 [0x34] "sys: trap: watchpoint",
106 [0x3C] "sys: trap: BRK instruction",
114 intr = ureg->type >> 32;
122 up->kentry = cycles();
124 type = (u32int)ureg->type >> 26;
126 case 0x20: // instruction abort from lower level
127 case 0x21: // instruction abort from same level
128 case 0x24: // data abort from lower level
129 case 0x25: // data abort from same level
132 case 0x07: // SIMD/FP
133 case 0x2C: // FPU exception (A64 only)
136 case 0x00: // unknown
138 if(irq(ureg) && up != nil && up->delaysched)
143 case 0x2F: // SError interrupt
145 panic("SError interrupt");
149 case 0x01: // WFI or WFE instruction execution
150 case 0x03: // MCR or MRC access to CP15 (A32 only)
151 case 0x04: // MCRR or MRC access to CP15 (A32 only)
152 case 0x05: // MCR or MRC access to CP14 (A32 only)
153 case 0x06: // LDC or STD access to CP14 (A32 only)
154 case 0x08: // MCR or MRC to CP10 (A32 only)
155 case 0x0C: // MRC access to CP14 (A32 only)
156 case 0x0E: // Illegal Execution State
157 case 0x11: // SVC instruction execution (A32 only)
158 case 0x12: // HVC instruction execution (A32 only)
159 case 0x13: // SMC instruction execution (A32 only)
160 case 0x15: // SVC instruction execution (A64 only)
161 case 0x16: // HVC instruction execution (A64 only)
162 case 0x17: // SMC instruction execution (A64 only)
163 case 0x18: // MSR/MRS (A64)
164 case 0x22: // misaligned pc
165 case 0x26: // stack pointer misaligned
166 case 0x28: // FPU exception (A32 only)
167 case 0x30: // breakpoint from lower level
168 case 0x31: // breakpoint from same level
169 case 0x32: // software step from lower level
170 case 0x33: // software step from same level
171 case 0x34: // watchpoint execution from lower level
172 case 0x35: // watchpoint exception from same level
173 case 0x38: // breapoint (A32 only)
174 case 0x3A: // vector catch exception (A32 only)
175 case 0x3C: // BRK instruction (A64 only)
179 panic("unhandled trap");
181 if(traps[type] == nil) type = 0; // unknown
182 postnote(up, 1, traps[type], NDebug);
187 if(up->procctl || up->nnote)
196 vlong startns, stopns;
202 up->kentry = cycles();
210 up->scallnr = scallnr = ureg->r0;
218 if(sp < USTKTOP - BY2PG || sp > USTKTOP - sizeof(Sargs) - BY2WD){
219 validaddr(sp, sizeof(Sargs)+BY2WD, 0);
222 up->s = *((Sargs*) (sp + BY2WD));
224 if(up->procctl == Proc_tracesyscall){
225 syscallfmt(scallnr, ureg->pc, (va_list) up->s.args);
227 up->procctl = Proc_stopme;
230 startns = todget(nil);
233 if(scallnr >= nsyscall || systab[scallnr] == nil){
234 pprint("bad sys call number %lud pc %#p", scallnr, ureg->pc);
235 postnote(up, 1, "sys: bad sys call", NDebug);
238 up->psstate = sysctab[scallnr];
239 ret = systab[scallnr]((va_list)up->s.args);
243 up->syserrstr = up->errstr;
247 print("bad errstack [%lud]: %d extra\n", scallnr, up->nerrlab);
248 for(i = 0; i < NERR; i++)
249 print("sp=%#p pc=%#p\n", up->errlab[i].sp, up->errlab[i].pc);
250 panic("error stack");
253 if(up->procctl == Proc_tracesyscall){
254 stopns = todget(nil);
255 sysretfmt(scallnr, (va_list) up->s.args, ret, startns, stopns);
257 up->procctl = Proc_stopme;
264 if(scallnr == NOTED){
265 noted(ureg, *((ulong*) up->s.args));
267 * normally, syscall() returns to forkret()
268 * not restoring general registers when going
269 * to userspace. to completely restore the
270 * interrupted context, we have to return thru
271 * noteret(). we override return pc to jump to
272 * to it when returning form syscall()
277 if(scallnr != RFORK && (up->procctl || up->nnote)){
297 if(up->fpstate == FPactive){
299 up->fpstate = FPinactive;
301 up->fpstate |= FPillegal;
307 if(strncmp(n->msg, "sys:", 4) == 0){
309 if(l > ERRMAX-23) /* " pc=0x0123456789abcdef\0" */
311 sprint(n->msg+l, " pc=%#p", ureg->pc);
314 if(n->flag!=NUser && (up->notified || up->notify==0)){
316 if(n->flag == NDebug)
317 pprint("suicide: %s\n", n->msg);
318 pexit(n->msg, n->flag!=NDebug);
329 pexit(n->msg, n->flag!=NDebug);
332 sp -= 256; /* debugging: preserve context causing problem */
336 if(!okaddr((uintptr)up->notify, 1, 0)
337 || !okaddr(sp-ERRMAX-4*BY2WD, sizeof(Ureg)+ERRMAX+4*BY2WD, 1)
338 || ((uintptr) up->notify & 3) != 0
341 pprint("suicide: bad address in notify: handler=%#p sp=%#p\n",
346 memmove((Ureg*)sp, ureg, sizeof(Ureg));
347 *(Ureg**)(sp-BY2WD) = up->ureg; /* word under Ureg is old up->ureg */
348 up->ureg = (void*)sp;
350 memmove((char*)sp, up->note[0].msg, ERRMAX);
352 *(uintptr*)(sp+2*BY2WD) = sp+3*BY2WD;
353 *(uintptr*)(sp+1*BY2WD) = (uintptr)up->ureg;
354 ureg->r0 = (uintptr) up->ureg;
356 ureg->pc = (uintptr) up->notify;
360 memmove(&up->lastnote, &up->note[0], sizeof(Note));
361 memmove(&up->note[0], &up->note[1], up->nnote*sizeof(Note));
369 noted(Ureg *ureg, ulong arg0)
375 if(arg0 != NRSTR && !up->notified){
377 pprint("call to noted() when not notified\n");
383 up->fpstate &= ~FPillegal;
385 oureg = (uintptr) nureg;
386 if(!okaddr(oureg - BY2WD, BY2WD + sizeof(Ureg), 0) || (oureg & 7) != 0){
388 pprint("bad ureg in noted or call to noted when not notified\n");
392 nureg->psr = (nureg->psr & USPSRMASK) | (ureg->psr & ~USPSRMASK);
393 memmove(ureg, nureg, sizeof(Ureg));
396 case NCONT: case NRSTR:
397 if(!okaddr(nureg->pc, BY2WD, 0) || !okaddr(nureg->sp, BY2WD, 0) ||
398 (nureg->pc & 3) != 0 || (nureg->sp & 7) != 0){
400 pprint("suicide: trap in noted\n");
403 up->ureg = (Ureg *) (*(uintptr*) (oureg - BY2WD));
408 if(!okaddr(nureg->pc, BY2WD, 0) || !okaddr(nureg->sp, BY2WD, 0) ||
409 (nureg->pc & 3) != 0 || (nureg->sp & 7) != 0){
411 pprint("suicide: trap in noted\n");
415 sp = oureg - 4 * BY2WD - ERRMAX;
418 ureg->r0 = (uintptr) oureg;
419 ((uintptr *) sp)[1] = oureg;
420 ((uintptr *) sp)[0] = 0;
424 up->lastnote.flag = NDebug;
428 if(up->lastnote.flag == NDebug)
429 pprint("suicide: %s\n", up->lastnote.msg);
430 pexit(up->lastnote.msg, up->lastnote.flag != NDebug);
435 faultarm64(Ureg *ureg)
437 extern void checkpages(void);
442 insyscall = up->insyscall;
445 if(!userureg(ureg) && waserror()){
446 if(up->nerrlab == 0){
447 pprint("suicide: sys: %s\n", up->errstr);
448 pexit(up->errstr, 1);
450 up->insyscall = insyscall;
455 read = (ureg->type & (1<<6)) == 0;
457 switch((u32int)ureg->type & 0x3F){
458 case 4: case 5: case 6: case 7: // Tanslation fault.
459 case 8: case 9: case 10: case 11: // Access flag fault.
460 case 12: case 13: case 14: case 15: // Permission fault.
461 case 48: // tlb conflict fault.
462 if(fault(addr, read) == 0)
466 case 0: case 1: case 2: case 3: // Address size fault.
467 case 16: // synchronous external abort.
468 case 24: // synchronous parity error on a memory access.
469 case 20: case 21: case 22: case 23: // synchronous external abort on a table walk.
470 case 28: case 29: case 30: case 31: // synchronous parity error on table walk.
471 case 33: // alignment fault.
472 case 52: // implementation defined, lockdown abort.
473 case 53: // implementation defined, unsuppoted exclusive.
474 case 61: // first level domain fault
475 case 62: // second level domain fault
479 panic("fault: %s addr=%#p", read ? "read" : "write", addr);
482 sprint(buf, "sys: trap: fault %s addr=%#p", read ? "read" : "write", addr);
483 postnote(up, 1, buf, NDebug);
489 up->insyscall = insyscall;
495 return (ureg->psr & 15) == 0;
501 Ureg *ur = up->dbgreg;
508 Ureg *ur = up->dbgreg;
520 switch(up->fpstate & ~FPillegal){
523 up->fpstate = FPinactive;
525 memmove(p->fpsave, up->fpsave, sizeof(FPsave));
526 p->fpstate = FPinactive;
530 p->tpidr = up->tpidr;
532 p->kentry = up->kentry;
533 p->pcycles = -p->kentry;
543 syswr(TPIDR_EL0, p->tpidr);
545 p->kentry = cycles();
546 p->pcycles = -p->kentry;
554 if(p->fpstate == FPactive){
555 if(p->state == Moribund)
559 p->fpstate = FPinactive;
563 p->tpidr = sysrd(TPIDR_EL0);
565 putasid(p); // release asid
580 syswr(TPIDR_EL0, p->tpidr);
591 up->kpfun(up->kparg);
592 pexit("kproc dying", 0);
596 kprocchild(Proc* p, void (*func)(void*), void* arg)
598 p->sched.pc = (uintptr) linkproc;
599 p->sched.sp = (uintptr) p->kstack + KSTACK - 16;
600 *(void**)p->sched.sp = kprocchild; /* fake */
607 forkchild(Proc *p, Ureg *ureg)
611 p->sched.pc = (uintptr) forkret;
612 p->sched.sp = (uintptr) p->kstack + KSTACK - TRAPFRAMESIZE;
614 cureg = (Ureg*) (p->sched.sp + 16);
615 memmove(cureg, ureg, sizeof(Ureg));
623 execregs(uintptr entry, ulong ssize, ulong nargs)
628 sp = (uintptr*)(USTKTOP - ssize);
632 ureg->sp = (uintptr)sp;
635 return USTKTOP-sizeof(Tos);
639 evenaddr(uintptr addr)
642 postnote(up, 1, "sys: odd address", NDebug);
648 callwithureg(void (*f) (Ureg *))
652 u.pc = getcallerpc(&f);
658 setkernur(Ureg *ureg, Proc *p)
660 ureg->pc = p->sched.pc;
661 ureg->sp = p->sched.sp;
662 ureg->link = (uintptr)sched;
666 setupwatchpts(Proc*, Watchpt*, int)
671 setregisters(Ureg* ureg, char* pureg, char* uva, int n)
676 memmove(pureg, uva, n);
677 ureg->psr = (ureg->psr & USPSRMASK) | (v & ~USPSRMASK);
681 dumpstackwithureg(Ureg *ureg)
683 uintptr v, estack, sp;
687 if((s = getconf("*nodumpstack")) != nil && strcmp(s, "0") != 0){
688 iprint("dumpstack disabled\n");
691 iprint("ktrace /kernel/path %#p %#p %#p # pc, sp, link\n",
692 ureg->pc, ureg->sp, ureg->link);
696 if(sp < KZERO || (sp & 7) != 0)
699 estack = (uintptr)m+MACHSIZE;
700 if(up != nil && sp <= (uintptr)up->kstack+KSTACK)
701 estack = (uintptr)up->kstack+KSTACK;
705 iprint("&up->kstack %#p sp %#p\n", up->kstack, sp);
707 iprint("&m %#p sp %#p\n", m, sp);
712 for(; sp < estack; sp += sizeof(uintptr)){
714 if(KTZERO < v && v < (uintptr)etext && (v & 3) == 0){
715 iprint("%#8.8lux=%#8.8lux ", (ulong)sp, (ulong)v);
730 callwithureg(dumpstackwithureg);
741 iprint("cpu%d: dumpregs ureg %#p process %lud: %s\n", m->machno, ureg,
744 iprint("cpu%d: dumpregs ureg %#p\n", m->machno, ureg);
746 for(i = 0; i < 30; i += 3)
747 iprint("R%d %.16llux R%d %.16llux R%d %.16llux\n", i, r[i], i+1, r[i+1], i+2, r[i+2]);
748 iprint("PC %#p SP %#p LR %#p PSR %llux TYPE %llux\n",
749 ureg->pc, ureg->sp, ureg->link,
750 ureg->psr, ureg->type);