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*40669Smarc * @(#)trap.c 7.6 (Berkeley) 04/01/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 */ 13224012Ssam i = u.u_error; 13325678Ssam pagein(code, 0); 13424012Ssam u.u_error = i; 13524012Ssam if (type == T_PAGEFLT) 13624012Ssam return; 13724012Ssam goto out; 13824012Ssam 13925678Ssam case T_BPTFLT + USER: /* bpt instruction fault */ 14025678Ssam case T_TRCTRAP + USER: /* trace trap */ 14124012Ssam locr0[PS] &= ~PSL_T; 14224012Ssam i = SIGTRAP; 14324012Ssam break; 14425678Ssam 14538935Skarels #ifdef notdef 14638935Skarels /* THIS CODE IS BOGUS- delete? (KSP not valid is unrecoverable) 14738935Skarels And what does KSPNOTVAL in user-mode mean? */ 14825746Ssam /* 14925746Ssam * For T_KSPNOTVAL and T_BUSERR, can not allow spl to 15025746Ssam * drop to 0 as clock could go off and we would end up 15125746Ssam * doing an rei to the interrupt stack at ipl 0 (a 15225746Ssam * reserved operand fault). Instead, we allow psignal 15325746Ssam * to post an ast, then return to user mode where we 15425746Ssam * will reenter the kernel on the kernel's stack and 15525746Ssam * can then service the signal. 15625746Ssam */ 15724012Ssam case T_KSPNOTVAL: 15825746Ssam if (noproc) 15925746Ssam panic("ksp not valid"); 16025746Ssam /* fall thru... */ 16124012Ssam case T_KSPNOTVAL + USER: 16225772Ssam printf("pid %d: ksp not valid\n", u.u_procp->p_pid); 16338935Skarels panic("ksp not valid - 2"); 16425746Ssam /* must insure valid kernel stack pointer? */ 16525746Ssam psignal(u.u_procp, SIGKILL); 16625746Ssam return; 16738935Skarels #endif 16824012Ssam 16925678Ssam case T_BUSERR + USER: 17038935Skarels i = SIGBUS; 17138935Skarels break; 17224012Ssam } 17338935Skarels trapsignal(i, ucode); 17424012Ssam out: 17524012Ssam p = u.u_procp; 17638935Skarels if (ISSIG(p)) 17724012Ssam psig(); 17824012Ssam p->p_pri = p->p_usrpri; 17924012Ssam if (runrun) { 18024012Ssam /* 18124012Ssam * Since we are u.u_procp, clock will normally just change 18224012Ssam * our priority without moving us from one queue to another 18324012Ssam * (since the running process is not on a queue.) 18424012Ssam * If that happened after we setrq ourselves but before we 18524012Ssam * swtch()'ed, we might not be on the queue indicated by 18624012Ssam * our priority. 18724012Ssam */ 18829561Ssam (void) splclock(); 18924012Ssam setrq(p); 19024012Ssam u.u_ru.ru_nivcsw++; 19124012Ssam swtch(); 19238935Skarels if (ISSIG(p)) 19338935Skarels psig(); 19424012Ssam } 19524012Ssam if (u.u_prof.pr_scale) { 19624012Ssam int ticks; 19724012Ssam struct timeval *tv = &u.u_ru.ru_stime; 19824012Ssam 19924012Ssam ticks = ((tv->tv_sec - syst.tv_sec) * 1000 + 20024012Ssam (tv->tv_usec - syst.tv_usec) / 1000) / (tick / 1000); 20124012Ssam if (ticks) 20224012Ssam addupc(locr0[PC], &u.u_prof, ticks); 20324012Ssam } 20424012Ssam curpri = p->p_pri; 20524012Ssam } 20624012Ssam 20724012Ssam /* 20825678Ssam * Called from locore when a system call occurs 20924012Ssam */ 21025678Ssam /*ARGSUSED*/ 21124012Ssam syscall(sp, type, hfs, accmst, acclst, dbl, code, pc, psl) 21225678Ssam unsigned code; 21324012Ssam { 21425678Ssam int r0, r1; /* must reserve space */ 21524012Ssam register int *locr0 = ((int *)&psl)-PS; 21625678Ssam register caddr_t params; 21725678Ssam register int i; 21824012Ssam register struct sysent *callp; 21938404Smarc register struct proc *p = u.u_procp; 22025678Ssam struct timeval syst; 22124012Ssam int opc; 22224012Ssam 22325678Ssam #ifdef lint 22425678Ssam r0 = 0; r0 = r0; r1 = 0; r1 = r1; 22525678Ssam #endif 22624012Ssam syst = u.u_ru.ru_stime; 22724012Ssam if (!USERMODE(locr0[PS])) 22824012Ssam panic("syscall"); 22924012Ssam u.u_ar0 = locr0; 23024012Ssam params = (caddr_t)locr0[FP] + NBPW; 23124012Ssam u.u_error = 0; 23225678Ssam /* BEGIN GROT */ 23325678Ssam /* 23425678Ssam * Try to reconstruct pc, assuming code 23525678Ssam * is an immediate constant 23625678Ssam */ 23724012Ssam opc = pc - 2; /* short literal */ 23824012Ssam if (code > 0x3f) { 23925678Ssam opc--; /* byte immediate */ 24024012Ssam if (code > 0x7f) { 24125678Ssam opc--; /* word immediate */ 24224012Ssam if (code > 0x7fff) 24324012Ssam opc -= 2; /* long immediate */ 24424012Ssam } 24524012Ssam } 24625678Ssam /* END GROT */ 24724012Ssam callp = (code >= nsysent) ? &sysent[63] : &sysent[code]; 24824012Ssam if (callp == sysent) { 24924012Ssam i = fuword(params); 25024012Ssam params += NBPW; 25125678Ssam callp = (code >= nsysent) ? &sysent[63] : &sysent[code]; 25224012Ssam } 25325678Ssam if ((i = callp->sy_narg * sizeof (int)) && 25425678Ssam (u.u_error = copyin(params, (caddr_t)u.u_arg, (u_int)i)) != 0) { 25525678Ssam locr0[R0] = u.u_error; 25625678Ssam locr0[PS] |= PSL_C; /* carry bit */ 257*40669Smarc #ifdef KTRACE 258*40669Smarc if (KTRPOINT(p, KTR_SYSCALL)) 259*40669Smarc ktrsyscall(p->p_tracep, code, callp->sy_narg); 260*40669Smarc #endif 26125678Ssam goto done; 26224012Ssam } 263*40669Smarc #ifdef KTRACE 264*40669Smarc if (KTRPOINT(p, KTR_SYSCALL)) 265*40669Smarc ktrsyscall(p->p_tracep, code, callp->sy_narg); 266*40669Smarc #endif 26724012Ssam u.u_r.r_val1 = 0; 26825678Ssam u.u_r.r_val2 = locr0[R1]; 26924012Ssam if (setjmp(&u.u_qsave)) { 27025678Ssam if (u.u_error == 0 && u.u_eosys != RESTARTSYS) 27124012Ssam u.u_error = EINTR; 27224012Ssam } else { 27325678Ssam u.u_eosys = NORMALRETURN; 27438406Smckusick (*callp->sy_call)(&u); 27524012Ssam } 27625678Ssam if (u.u_eosys == NORMALRETURN) { 27725678Ssam if (u.u_error) { 27825678Ssam locr0[R0] = u.u_error; 27925678Ssam locr0[PS] |= PSL_C; /* carry bit */ 28025678Ssam } else { 28125678Ssam locr0[PS] &= ~PSL_C; /* clear carry bit */ 28225678Ssam locr0[R0] = u.u_r.r_val1; 28325678Ssam locr0[R1] = u.u_r.r_val2; 28425678Ssam } 28525678Ssam } else if (u.u_eosys == RESTARTSYS) 28624012Ssam pc = opc; 28725678Ssam /* else if (u.u_eosys == JUSTRETURN) */ 28825678Ssam /* nothing to do */ 28924012Ssam done: 290*40669Smarc /* 291*40669Smarc * Reinitialize proc pointer `p' as it may be different 292*40669Smarc * if this is a child returning from fork syscall. 293*40669Smarc */ 29424012Ssam p = u.u_procp; 29524012Ssam if (p->p_cursig || ISSIG(p)) 29624012Ssam psig(); 29724012Ssam p->p_pri = p->p_usrpri; 29824012Ssam if (runrun) { 29924012Ssam /* 30024012Ssam * Since we are u.u_procp, clock will normally just change 30124012Ssam * our priority without moving us from one queue to another 30224012Ssam * (since the running process is not on a queue.) 30324012Ssam * If that happened after we setrq ourselves but before we 30424012Ssam * swtch()'ed, we might not be on the queue indicated by 30524012Ssam * our priority. 30624012Ssam */ 30729561Ssam (void) splclock(); 30824012Ssam setrq(p); 30924012Ssam u.u_ru.ru_nivcsw++; 31024012Ssam swtch(); 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; 322*40669Smarc #ifdef KTRACE 323*40669Smarc if (KTRPOINT(p, KTR_SYSRET)) 324*40669Smarc ktrsysret(p->p_tracep, code); 325*40669Smarc #endif 32624012Ssam } 327