3 #include "../port/lib.h"
9 #include "../port/error.h"
12 extern int irqhandled(Ureg*, int);
13 extern void irqinit(void);
15 void noted(Ureg*, ulong);
17 static void debugexc(Ureg*, void*);
18 static void debugbpt(Ureg*, void*);
19 static void fault386(Ureg*, void*);
20 static void doublefault(Ureg*, void*);
21 static void unexpected(Ureg*, void*);
22 static void _dumpstack(Ureg*);
25 * Minimal trap setup. Just enough so that we can panic
26 * on traps (bugs) during kernel initialization.
27 * Called very early - malloc is not yet available.
37 idt = (Segdesc*)IDTADDR;
38 vaddr = (ulong)vectortable;
39 for(v = 0; v < 256; v++){
40 d1 = (vaddr & 0xFFFF0000)|SEGP;
54 idt[v].d0 = (vaddr & 0xFFFF)|(KESEL<<16);
58 ptr[0] = sizeof(Segdesc)*256-1;
59 ptr[1] = IDTADDR & 0xFFFF;
60 ptr[2] = IDTADDR >> 16;
73 * Syscall() is called directly without going through trap().
75 trapenable(VectorDE, debugexc, 0, "debugexc");
76 trapenable(VectorBPT, debugbpt, 0, "debugpt");
77 trapenable(VectorPF, fault386, 0, "fault386");
78 trapenable(Vector2F, doublefault, 0, "doublefault");
79 trapenable(Vector15, unexpected, 0, "unexpected");
82 static char* excname[32] = {
85 "nonmaskable interrupt",
90 "coprocessor not available",
92 "coprocessor segment overrun",
94 "segment not present",
96 "general protection violation",
122 if(vno < nelem(excname)){
124 sprint(buf, "sys: trap: %s", excname[vno]);
125 postnote(up, 1, buf, NDebug);
132 * All traps come here. It is slower to have all traps call trap()
133 * rather than directly vectoring the handler. However, this avoids a
134 * lot of code duplication and possible bugs. The only exception is
136 * Trap is called with interrupts disabled via interrupt-gates.
145 if(!irqhandled(ureg, vno) && (!user || !usertrap(vno))){
150 extern void _forkretpopgs(void);
151 extern void _forkretpopfs(void);
152 extern void _forkretpopes(void);
153 extern void _forkretpopds(void);
154 extern void _forkretiret(void);
155 extern void _rdmsrinst(void);
156 extern void _wrmsrinst(void);
157 extern void _peekinst(void);
159 extern void load_fs(ulong);
160 extern void load_gs(ulong);
165 sp = (ulong*)&ureg->sp; /* kernel stack */
166 pc = (void*)ureg->pc;
168 if(pc == _forkretpopgs || pc == _forkretpopfs ||
169 pc == _forkretpopes || pc == _forkretpopds){
170 if(vno == VectorGPF || vno == VectorSNP){
174 } else if(pc == _forkretiret){
175 if(vno == VectorGPF || vno == VectorSNP){
176 sp[1] = UESEL; /* CS */
177 sp[4] = UDSEL; /* SS */
180 } else if(pc == _rdmsrinst || pc == _wrmsrinst){
181 if(vno == VectorGPF){
186 } else if(pc == _peekinst){
187 if(vno == VectorGPF){
193 /* early fault before trapinit() */
200 ureg->sp = (ulong)&ureg->sp;
203 if(vno < nelem(excname))
204 panic("%s", excname[vno]);
205 panic("unknown trap/intr: %d", vno);
210 if(up->procctl || up->nnote)
220 dumpregs2(Ureg* ureg)
223 iprint("cpu%d: registers for %s %lud\n",
224 m->machno, up->text, up->pid);
226 iprint("cpu%d: registers for kernel\n", m->machno);
227 iprint("FLAGS=%luX TRAP=%luX ECODE=%luX PC=%luX",
228 ureg->flags, ureg->trap, ureg->ecode, ureg->pc);
230 iprint(" SS=%4.4luX USP=%luX\n", ureg->ss & 0xFFFF, ureg->usp);
232 iprint(" SP=%luX\n", (ulong)&ureg->sp);
233 iprint(" AX %8.8luX BX %8.8luX CX %8.8luX DX %8.8luX\n",
234 ureg->ax, ureg->bx, ureg->cx, ureg->dx);
235 iprint(" SI %8.8luX DI %8.8luX BP %8.8luX\n",
236 ureg->si, ureg->di, ureg->bp);
237 iprint(" CS %4.4luX DS %4.4luX ES %4.4luX FS %4.4luX GS %4.4luX\n",
238 ureg->cs & 0xFFFF, ureg->ds & 0xFFFF, ureg->es & 0xFFFF,
239 ureg->fs & 0xFFFF, ureg->gs & 0xFFFF);
248 * Processor control registers.
249 * If machine check exception, time stamp counter, page size extensions
250 * or enhanced virtual 8086 mode extensions are supported, there is a
251 * CR4. If there is a CR4 and machine check extensions, read the machine
252 * check address and machine check type registers if RDMSR supported.
254 iprint(" CR0 %8.8lux CR2 %8.8lux CR3 %8.8lux",
255 getcr0(), getcr2(), getcr3());
256 if(m->cpuiddx & (Mce|Tsc|Pse|Vmex)){
257 iprint(" CR4 %8.8lux\n", getcr4());
261 iprint("\n ur %#p up %#p\n", ureg, up);
266 * Fill in enough of Ureg to get a stack trace, and call a function.
267 * Used by debugging interface rdb.
270 callwithureg(void (*fn)(Ureg*))
273 ureg.pc = getcallerpc(&fn);
274 ureg.sp = (ulong)&fn;
279 _dumpstack(Ureg *ureg)
281 uintptr l, v, i, estack;
286 if((s = getconf("*nodumpstack")) != nil && strcmp(s, "0") != 0){
287 iprint("dumpstack disabled\n");
290 iprint("dumpstack\n");
293 x += iprint("ktrace /kernel/path %.8lux %.8lux <<EOF\n", ureg->pc, ureg->sp);
296 && (uintptr)&l >= (uintptr)up->kstack
297 && (uintptr)&l <= (uintptr)up->kstack+KSTACK)
298 estack = (uintptr)up->kstack+KSTACK;
299 else if((uintptr)&l >= (uintptr)m->stack
300 && (uintptr)&l <= (uintptr)m+MACHSIZE)
301 estack = (uintptr)m+MACHSIZE;
304 x += iprint("estackx %p\n", estack);
306 for(l = (uintptr)&l; l < estack; l += sizeof(uintptr)){
308 if((KTZERO < v && v < (uintptr)&etext) || estack-l < 32){
310 * Could Pick off general CALL (((uchar*)v)[-5] == 0xE8)
311 * and CALL indirect through AX
312 * (((uchar*)v)[-2] == 0xFF && ((uchar*)v)[-2] == 0xD0),
313 * but this is too clever and misses faulting address.
315 x += iprint("%.8p=%.8p ", l, v);
327 if(ureg->trap != VectorNMI)
331 for(l = (uintptr)&l; l < estack; l += sizeof(uintptr)){
332 iprint("%.8p ", *(uintptr*)l);
345 callwithureg(_dumpstack);
349 debugexc(Ureg *ureg, void *)
358 panic("kernel debug exception dr6=%#.8ux", dr6);
362 else if(!canqlock(&up->debug))
365 m = (m >> 4 | m >> 3) & 8 | (m >> 3 | m >> 2) & 4 | (m >> 2 | m >> 1) & 2 | (m >> 1 | m) & 1;
368 sprint(buf, "sys: debug exception dr6=%#.8ux", dr6);
369 postnote(up, 0, buf, NDebug);
372 e = buf + sizeof(buf);
373 p = seprint(p, e, "sys: watchpoint ");
374 for(i = 0; i < 4; i++)
376 p = seprint(p, e, "%d%s", i, (m >> i + 1 != 0) ? "," : "");
377 postnote(up, 0, buf, NDebug);
383 debugbpt(Ureg* ureg, void*)
389 /* restore pc to instruction that caused the trap */
391 sprint(buf, "sys: breakpoint");
392 postnote(up, 1, buf, NDebug);
396 doublefault(Ureg*, void*)
398 panic("double fault");
402 unexpected(Ureg* ureg, void*)
404 print("unexpected trap %lud; ignoring\n", ureg->trap);
407 extern void checkpages(void);
408 extern void checkfault(ulong, ulong);
410 fault386(Ureg* ureg, void*)
413 int read, user, n, insyscall;
417 read = !(ureg->ecode & 2);
419 user = userureg(ureg);
424 extern void _peekinst(void);
425 if((void(*)(void))ureg->pc == _peekinst){
431 panic("kernel fault: bad address pc=0x%.8lux addr=0x%.8lux", ureg->pc, addr);
433 panic("kernel fault: no user process pc=0x%.8lux addr=0x%.8lux", ureg->pc, addr);
436 panic("user fault: up=0 pc=0x%.8lux addr=0x%.8lux", ureg->pc, addr);
438 insyscall = up->insyscall;
440 n = fault(addr, ureg->pc, read);
444 panic("fault: 0x%lux", addr);
447 checkfault(addr, ureg->pc);
448 sprint(buf, "sys: trap: fault %s addr=0x%lux",
449 read ? "read" : "write", addr);
450 postnote(up, 1, buf, NDebug);
452 up->insyscall = insyscall;
458 #include "../port/systab.h"
461 * Syscall is called directly from assembler without going through trap().
471 vlong startns, stopns;
474 panic("syscall: cs 0x%4.4luX", ureg->cs);
482 up->scallnr = scallnr;
489 if(sp<(USTKTOP-BY2PG) || sp>(USTKTOP-sizeof(Sargs)-BY2WD))
490 validaddr(sp, sizeof(Sargs)+BY2WD, 0);
492 up->s = *((Sargs*)(sp+BY2WD));
494 if(up->procctl == Proc_tracesyscall){
495 syscallfmt(scallnr, ureg->pc, (va_list)up->s.args);
497 up->procctl = Proc_stopme;
500 startns = todget(nil);
503 if(scallnr >= nsyscall || systab[scallnr] == 0){
504 pprint("bad sys call number %lud pc %lux\n",
506 postnote(up, 1, "sys: bad sys call", NDebug);
509 up->psstate = sysctab[scallnr];
510 ret = systab[scallnr]((va_list)up->s.args);
513 /* failure: save the error buffer for errstr */
515 up->syserrstr = up->errstr;
517 if(0 && up->pid == 1)
518 print("syscall %lud error %s\n", scallnr, up->syserrstr);
521 print("bad errstack [%lud]: %d extra\n", scallnr, up->nerrlab);
522 for(i = 0; i < NERR; i++)
523 print("sp=%lux pc=%lux\n",
524 up->errlab[i].sp, up->errlab[i].pc);
525 panic("error stack");
529 * Put return value in frame. On the x86 the syscall is
530 * just another trap and the return value from syscall is
531 * ignored. On other machines the return value is put into
532 * the results register by caller of syscall.
536 if(up->procctl == Proc_tracesyscall){
537 stopns = todget(nil);
538 sysretfmt(scallnr, (va_list)up->s.args, ret, startns, stopns);
540 up->procctl = Proc_stopme;
549 noted(ureg, *((ulong*)up->s.args));
551 if(scallnr!=RFORK && (up->procctl || up->nnote)){
555 /* if we delayed sched because we held a lock, sched now */
562 * Call user, if necessary, with note.
563 * Pass user the Ureg struct and the note on his stack.
577 if(up->fpstate == FPactive){
579 up->fpstate = FPinactive;
581 up->fpstate |= FPillegal;
587 if(strncmp(n->msg, "sys:", 4) == 0){
589 if(l > ERRMAX-15) /* " pc=0x12345678\0" */
591 sprint(n->msg+l, " pc=0x%.8lux", ureg->pc);
594 if(n->flag!=NUser && (up->notified || up->notify==0)){
596 if(n->flag == NDebug)
597 pprint("suicide: %s\n", n->msg);
598 pexit(n->msg, n->flag!=NDebug);
609 pexit(n->msg, n->flag!=NDebug);
612 sp -= 256; /* debugging: preserve context causing problem */
614 if(0) print("%s %lud: notify %.8lux %.8lux %.8lux %s\n",
615 up->text, up->pid, ureg->pc, ureg->usp, sp, n->msg);
617 if(!okaddr((uintptr)up->notify, 1, 0)
618 || !okaddr(sp-ERRMAX-4*BY2WD, sizeof(Ureg)+ERRMAX+4*BY2WD, 1)){
620 pprint("suicide: bad address in notify\n");
624 memmove((Ureg*)sp, ureg, sizeof(Ureg));
625 *(Ureg**)(sp-BY2WD) = up->ureg; /* word under Ureg is old up->ureg */
626 up->ureg = (void*)sp;
628 memmove((char*)sp, up->note[0].msg, ERRMAX);
630 *(ulong*)(sp+2*BY2WD) = sp+3*BY2WD; /* arg 2 is string */
631 *(ulong*)(sp+1*BY2WD) = (ulong)up->ureg; /* arg 1 is ureg* */
632 *(ulong*)(sp+0*BY2WD) = 0; /* arg 0 is pc */
634 ureg->pc = (ulong)up->notify;
636 ureg->ss = ureg->ds = ureg->es = UDSEL;
639 memmove(&up->lastnote, &up->note[0], sizeof(Note));
640 memmove(&up->note[0], &up->note[1], up->nnote*sizeof(Note));
648 * Return user to state before notify()
651 noted(Ureg* ureg, ulong arg0)
657 if(arg0!=NRSTR && !up->notified) {
659 pprint("call to noted() when not notified\n");
664 nureg = up->ureg; /* pointer to user returned Ureg struct */
666 up->fpstate &= ~FPillegal;
669 oureg = (ulong)nureg;
670 if(!okaddr(oureg-BY2WD, BY2WD+sizeof(Ureg), 0)){
672 pprint("bad ureg in noted or call to noted when not notified\n");
676 /* don't let user change system flags */
677 nureg->flags = (ureg->flags & ~0xCD5) | (nureg->flags & 0xCD5);
681 memmove(ureg, nureg, sizeof(Ureg));
686 if(0) print("%s %lud: noted %.8lux %.8lux\n",
687 up->text, up->pid, nureg->pc, nureg->usp);
688 if(!okaddr(nureg->pc, 1, 0) || !okaddr(nureg->usp, BY2WD, 0)){
690 pprint("suicide: trap in noted\n");
693 up->ureg = (Ureg*)(*(ulong*)(oureg-BY2WD));
698 if(!okaddr(nureg->pc, BY2WD, 0)
699 || !okaddr(nureg->usp, BY2WD, 0)){
701 pprint("suicide: trap in noted\n");
705 sp = oureg-4*BY2WD-ERRMAX;
708 ((ulong*)sp)[1] = oureg; /* arg 1 0(FP) is ureg* */
709 ((ulong*)sp)[0] = 0; /* arg 0 is pc */
713 up->lastnote.flag = NDebug;
718 if(up->lastnote.flag == NDebug)
719 pprint("suicide: %s\n", up->lastnote.msg);
720 pexit(up->lastnote.msg, up->lastnote.flag!=NDebug);
725 execregs(uintptr entry, ulong ssize, ulong nargs)
730 sp = (ulong*)(USTKTOP - ssize);
734 ureg->usp = (ulong)sp;
737 ureg->ss = ureg->ds = ureg->es = UDSEL;
738 ureg->fs = ureg->gs = NULLSEL;
739 return USTKTOP-sizeof(Tos); /* address of kernel/user shared data */
743 * return the userpc the last exception happened at
750 ureg = (Ureg*)up->dbgreg;
754 /* This routine must save the values of registers the user is not permitted
755 * to write from devproc and then restore the saved values before returning.
758 setregisters(Ureg* ureg, char* pureg, char* uva, int n)
763 memmove(pureg, uva, n);
764 ureg->flags = (ureg->flags & 0xCD5) | (flags & ~0xCD5);
770 kprocchild(Proc *p, void (*entry)(void))
773 * gotolabel() needs a word on the stack in
774 * which to place the return PC used to jump
777 p->sched.pc = (ulong)entry;
778 p->sched.sp = (ulong)p->kstack+KSTACK-BY2WD;
782 forkchild(Proc *p, Ureg *ureg)
787 * Add 2*BY2WD to the stack to account for
789 * - trap's argument (ur)
791 p->sched.sp = (ulong)p->kstack+KSTACK-(sizeof(Ureg)+2*BY2WD);
792 p->sched.pc = (ulong)forkret;
794 cureg = (Ureg*)(p->sched.sp+2*BY2WD);
795 memmove(cureg, ureg, sizeof(Ureg));
796 /* return value of syscall in child */
800 /* Give enough context in the ureg to produce a kernel stack for
804 setkernur(Ureg* ureg, Proc* p)
806 ureg->pc = p->sched.pc;
807 ureg->sp = p->sched.sp+4;