134408Skarels /* 234408Skarels * Copyright (c) 1988 Regents of the University of California. 334408Skarels * All rights reserved. The Berkeley software License Agreement 434408Skarels * specifies the terms and conditions for redistribution. 534408Skarels * 6*44019Skarels * @(#)trap.c 7.10 (Berkeley) 06/25/90 734408Skarels */ 824012Ssam 925678Ssam #include "param.h" 1025678Ssam #include "systm.h" 1125678Ssam #include "user.h" 1225678Ssam #include "proc.h" 1325678Ssam #include "seg.h" 1425678Ssam #include "acct.h" 1525678Ssam #include "kernel.h" 1634408Skarels 1734408Skarels #include "psl.h" 1834408Skarels #include "reg.h" 1934408Skarels #include "pte.h" 2034408Skarels #include "mtpr.h" 2138404Smarc #ifdef KTRACE 2238404Smarc #include "ktrace.h" 2324012Ssam #endif 2424012Ssam 2525678Ssam #include "../tahoe/trap.h" 2625678Ssam 2724012Ssam #define USER 040 /* user-mode flag added to type */ 2824012Ssam 2925678Ssam struct sysent sysent[]; 3025678Ssam int nsysent; 3124012Ssam 3225678Ssam char *trap_type[] = { 3325678Ssam "Reserved addressing mode", /* T_RESADFLT */ 3425678Ssam "Privileged instruction", /* T_PRIVINFLT */ 3525678Ssam "Reserved operand", /* T_RESOPFLT */ 3625678Ssam "Breakpoint", /* T_BPTFLT */ 3725678Ssam 0, 3825678Ssam "Kernel call", /* T_SYSCALL */ 3925678Ssam "Arithmetic trap", /* T_ARITHTRAP */ 4025678Ssam "System forced exception", /* T_ASTFLT */ 4125678Ssam "Segmentation fault", /* T_SEGFLT */ 4225678Ssam "Protection fault", /* T_PROTFLT */ 4325678Ssam "Trace trap", /* T_TRCTRAP */ 4425678Ssam 0, 4525678Ssam "Page fault", /* T_PAGEFLT */ 4625678Ssam "Page table fault", /* T_TABLEFLT */ 4725678Ssam "Alignment fault", /* T_ALIGNFLT */ 4825678Ssam "Kernel stack not valid", /* T_KSPNOTVAL */ 4925678Ssam "Bus error", /* T_BUSERR */ 5038935Skarels "Kernel debugger request", /* T_KDBTRAP */ 5125678Ssam }; 5230176Ssam int TRAP_TYPES = sizeof (trap_type) / sizeof (trap_type[0]); 5325678Ssam 5424012Ssam /* 5524012Ssam * Called from the trap handler when a processor trap occurs. 5624012Ssam */ 5725678Ssam /*ARGSUSED*/ 5824012Ssam trap(sp, type, hfs, accmst, acclst, dbl, code, pc, psl) 5938935Skarels unsigned type, code; /* kdb assumes these are *not* registers */ 6024012Ssam { 6125678Ssam int r0, r1; /* must reserve space */ 6224012Ssam register int *locr0 = ((int *)&psl)-PS; 6324012Ssam register int i; 6438935Skarels unsigned ucode = code; 6524012Ssam register struct proc *p; 6624012Ssam struct timeval syst; 6724012Ssam 6825678Ssam #ifdef lint 6925678Ssam r0 = 0; r0 = r0; r1 = 0; r1 = r1; 7025678Ssam #endif 7124012Ssam syst = u.u_ru.ru_stime; 7224012Ssam if (USERMODE(locr0[PS])) { 7324012Ssam type |= USER; 7424012Ssam u.u_ar0 = locr0; 7524012Ssam } 7624012Ssam switch (type) { 7724012Ssam 7825678Ssam default: 7934402Skarels #ifdef KADB 8030176Ssam if (kdb_trap(&psl)) 8130176Ssam return; 8230176Ssam #endif 8325678Ssam printf("trap type %d, code = %x, pc = %x\n", type, code, pc); 8425678Ssam type &= ~USER; 8525678Ssam if (type < TRAP_TYPES && trap_type[type]) 8625678Ssam panic(trap_type[type]); 8725678Ssam else 8825678Ssam panic("trap"); 8925678Ssam /*NOTREACHED*/ 9024012Ssam 9125678Ssam case T_PROTFLT + USER: /* protection fault */ 9224012Ssam i = SIGBUS; 9324012Ssam break; 9424012Ssam 9524012Ssam case T_PRIVINFLT + USER: /* privileged instruction fault */ 9625678Ssam case T_RESADFLT + USER: /* reserved addressing fault */ 9725678Ssam case T_RESOPFLT + USER: /* resereved operand fault */ 9825678Ssam case T_ALIGNFLT + USER: /* unaligned data fault */ 9938935Skarels ucode = type &~ USER; 10024012Ssam i = SIGILL; 10124012Ssam break; 10224012Ssam 10325678Ssam case T_ASTFLT + USER: /* Allow process switch */ 10424012Ssam case T_ASTFLT: 10524012Ssam astoff(); 10624012Ssam if ((u.u_procp->p_flag & SOWEUPC) && u.u_prof.pr_scale) { 10724012Ssam addupc(pc, &u.u_prof, 1); 10824012Ssam u.u_procp->p_flag &= ~SOWEUPC; 10924012Ssam } 11024012Ssam goto out; 11124012Ssam 11224012Ssam case T_ARITHTRAP + USER: 11324012Ssam i = SIGFPE; 11424012Ssam break; 11524012Ssam 11624012Ssam /* 11724012Ssam * If the user SP is above the stack segment, 11824012Ssam * grow the stack automatically. 11924012Ssam */ 12024012Ssam case T_SEGFLT + USER: 12124012Ssam if (grow((unsigned)locr0[SP]) || grow(code)) 12224012Ssam goto out; 12324012Ssam i = SIGSEGV; 12424012Ssam break; 12524012Ssam 12625678Ssam case T_TABLEFLT: /* allow page table faults in kernel */ 12725678Ssam case T_TABLEFLT + USER: /* page table fault */ 12824012Ssam panic("ptable fault"); 12924012Ssam 13025678Ssam case T_PAGEFLT: /* allow page faults in kernel mode */ 13125678Ssam case T_PAGEFLT + USER: /* page fault */ 13225678Ssam pagein(code, 0); 13324012Ssam if (type == T_PAGEFLT) 13424012Ssam return; 13524012Ssam goto out; 13624012Ssam 13725678Ssam case T_BPTFLT + USER: /* bpt instruction fault */ 13825678Ssam case T_TRCTRAP + USER: /* trace trap */ 13924012Ssam locr0[PS] &= ~PSL_T; 14024012Ssam i = SIGTRAP; 14124012Ssam break; 14225678Ssam 14338935Skarels #ifdef notdef 14438935Skarels /* THIS CODE IS BOGUS- delete? (KSP not valid is unrecoverable) 14538935Skarels And what does KSPNOTVAL in user-mode mean? */ 14625746Ssam /* 14725746Ssam * For T_KSPNOTVAL and T_BUSERR, can not allow spl to 14825746Ssam * drop to 0 as clock could go off and we would end up 14925746Ssam * doing an rei to the interrupt stack at ipl 0 (a 15025746Ssam * reserved operand fault). Instead, we allow psignal 15125746Ssam * to post an ast, then return to user mode where we 15225746Ssam * will reenter the kernel on the kernel's stack and 15325746Ssam * can then service the signal. 15425746Ssam */ 15524012Ssam case T_KSPNOTVAL: 15625746Ssam if (noproc) 15725746Ssam panic("ksp not valid"); 15825746Ssam /* fall thru... */ 15924012Ssam case T_KSPNOTVAL + USER: 16025772Ssam printf("pid %d: ksp not valid\n", u.u_procp->p_pid); 16138935Skarels panic("ksp not valid - 2"); 16225746Ssam /* must insure valid kernel stack pointer? */ 16325746Ssam psignal(u.u_procp, SIGKILL); 16425746Ssam return; 16538935Skarels #endif 16624012Ssam 16725678Ssam case T_BUSERR + USER: 16838935Skarels i = SIGBUS; 16938935Skarels break; 17024012Ssam } 17138935Skarels trapsignal(i, ucode); 17224012Ssam out: 17324012Ssam p = u.u_procp; 17440716Skarels if (i = CURSIG(p)) 17540716Skarels psig(i); 17624012Ssam p->p_pri = p->p_usrpri; 17724012Ssam if (runrun) { 17824012Ssam /* 17924012Ssam * Since we are u.u_procp, clock will normally just change 18024012Ssam * our priority without moving us from one queue to another 18124012Ssam * (since the running process is not on a queue.) 18224012Ssam * If that happened after we setrq ourselves but before we 18324012Ssam * swtch()'ed, we might not be on the queue indicated by 18424012Ssam * our priority. 18524012Ssam */ 18629561Ssam (void) splclock(); 18724012Ssam setrq(p); 18824012Ssam u.u_ru.ru_nivcsw++; 18924012Ssam swtch(); 19040716Skarels if (i = CURSIG(p)) 19140716Skarels psig(i); 19224012Ssam } 19324012Ssam if (u.u_prof.pr_scale) { 19424012Ssam int ticks; 19524012Ssam struct timeval *tv = &u.u_ru.ru_stime; 19624012Ssam 19724012Ssam ticks = ((tv->tv_sec - syst.tv_sec) * 1000 + 19824012Ssam (tv->tv_usec - syst.tv_usec) / 1000) / (tick / 1000); 19924012Ssam if (ticks) 20024012Ssam addupc(locr0[PC], &u.u_prof, ticks); 20124012Ssam } 20224012Ssam curpri = p->p_pri; 20324012Ssam } 20424012Ssam 20524012Ssam /* 20625678Ssam * Called from locore when a system call occurs 20724012Ssam */ 20825678Ssam /*ARGSUSED*/ 20924012Ssam syscall(sp, type, hfs, accmst, acclst, dbl, code, pc, psl) 21025678Ssam unsigned code; 21124012Ssam { 21225678Ssam int r0, r1; /* must reserve space */ 21324012Ssam register int *locr0 = ((int *)&psl)-PS; 21425678Ssam register caddr_t params; 21525678Ssam register int i; 21624012Ssam register struct sysent *callp; 21738404Smarc register struct proc *p = u.u_procp; 21825678Ssam struct timeval syst; 21940716Skarels int error, opc; 220*44019Skarels struct args { 221*44019Skarels int i[8]; 222*44019Skarels } args; 223*44019Skarels int rval[2]; 22424012Ssam 22525678Ssam #ifdef lint 22625678Ssam r0 = 0; r0 = r0; r1 = 0; r1 = r1; 22725678Ssam #endif 22824012Ssam syst = u.u_ru.ru_stime; 22924012Ssam if (!USERMODE(locr0[PS])) 23024012Ssam panic("syscall"); 23124012Ssam u.u_ar0 = locr0; 23224012Ssam params = (caddr_t)locr0[FP] + NBPW; 23325678Ssam /* BEGIN GROT */ 23425678Ssam /* 23525678Ssam * Try to reconstruct pc, assuming code 23625678Ssam * is an immediate constant 23725678Ssam */ 23824012Ssam opc = pc - 2; /* short literal */ 23924012Ssam if (code > 0x3f) { 24025678Ssam opc--; /* byte immediate */ 24124012Ssam if (code > 0x7f) { 24225678Ssam opc--; /* word immediate */ 24324012Ssam if (code > 0x7fff) 24424012Ssam opc -= 2; /* long immediate */ 24524012Ssam } 24624012Ssam } 24725678Ssam /* END GROT */ 24843643Skarels if (code == 0) { /* indir */ 24943643Skarels code = fuword(params); 25024012Ssam params += NBPW; 25124012Ssam } 25243643Skarels if (code >= nsysent) 25343643Skarels callp = &sysent[0]; /* indir (illegal) */ 25443643Skarels else 25543643Skarels callp = &sysent[code]; 25625678Ssam if ((i = callp->sy_narg * sizeof (int)) && 257*44019Skarels (error = copyin(params, (caddr_t)&args, (u_int)i)) != 0) { 25840716Skarels locr0[R0] = error; 25925678Ssam locr0[PS] |= PSL_C; /* carry bit */ 26040669Smarc #ifdef KTRACE 26140669Smarc if (KTRPOINT(p, KTR_SYSCALL)) 262*44019Skarels ktrsyscall(p->p_tracep, code, callp->sy_narg, args.i); 26340669Smarc #endif 26425678Ssam goto done; 26524012Ssam } 26640669Smarc #ifdef KTRACE 26740669Smarc if (KTRPOINT(p, KTR_SYSCALL)) 268*44019Skarels ktrsyscall(p->p_tracep, code, callp->sy_narg, args.i); 26940669Smarc #endif 27043643Skarels rval[0] = 0; 27143643Skarels rval[1] = locr0[R1]; 272*44019Skarels error = (*callp->sy_call)(u.u_procp, &args, rval); 27340716Skarels if (error == ERESTART) 27440716Skarels pc = opc; 27540716Skarels else if (error != EJUSTRETURN) { 27640716Skarels if (error) { 27740716Skarels locr0[R0] = error; 27825678Ssam locr0[PS] |= PSL_C; /* carry bit */ 27925678Ssam } else { 28025678Ssam locr0[PS] &= ~PSL_C; /* clear carry bit */ 28143643Skarels locr0[R0] = rval[0]; 28243643Skarels locr0[R1] = rval[1]; 28325678Ssam } 28440716Skarels } 28540716Skarels /* else if (error == EJUSTRETURN) */ 28625678Ssam /* nothing to do */ 28724012Ssam done: 28840669Smarc /* 28940669Smarc * Reinitialize proc pointer `p' as it may be different 29040669Smarc * if this is a child returning from fork syscall. 29140669Smarc */ 29224012Ssam p = u.u_procp; 29340716Skarels if (i = CURSIG(p)) 29440716Skarels psig(i); 29524012Ssam p->p_pri = p->p_usrpri; 29624012Ssam if (runrun) { 29724012Ssam /* 29824012Ssam * Since we are u.u_procp, clock will normally just change 29924012Ssam * our priority without moving us from one queue to another 30024012Ssam * (since the running process is not on a queue.) 30124012Ssam * If that happened after we setrq ourselves but before we 30224012Ssam * swtch()'ed, we might not be on the queue indicated by 30324012Ssam * our priority. 30424012Ssam */ 30529561Ssam (void) splclock(); 30624012Ssam setrq(p); 30724012Ssam u.u_ru.ru_nivcsw++; 30824012Ssam swtch(); 30940716Skarels if (i = CURSIG(p)) 31040716Skarels psig(i); 31124012Ssam } 31224012Ssam if (u.u_prof.pr_scale) { 31324012Ssam int ticks; 31424012Ssam struct timeval *tv = &u.u_ru.ru_stime; 31524012Ssam 31624012Ssam ticks = ((tv->tv_sec - syst.tv_sec) * 1000 + 31724012Ssam (tv->tv_usec - syst.tv_usec) / 1000) / (tick / 1000); 31824012Ssam if (ticks) 31924012Ssam addupc(locr0[PC], &u.u_prof, ticks); 32024012Ssam } 32124012Ssam curpri = p->p_pri; 32240669Smarc #ifdef KTRACE 32340669Smarc if (KTRPOINT(p, KTR_SYSRET)) 32443643Skarels ktrsysret(p->p_tracep, code, error, rval[0]); 32540669Smarc #endif 32624012Ssam } 327