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*38406Smckusick * @(#)trap.c 7.4 (Berkeley) 07/04/89 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 */ 5030176Ssam "Kernel debugger trap", /* 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) 5925678Ssam unsigned type, code; 6024012Ssam { 6125678Ssam int r0, r1; /* must reserve space */ 6224012Ssam register int *locr0 = ((int *)&psl)-PS; 6324012Ssam register int i; 6424012Ssam register struct proc *p; 6524012Ssam struct timeval syst; 6624012Ssam 6725678Ssam #ifdef lint 6825678Ssam r0 = 0; r0 = r0; r1 = 0; r1 = r1; 6925678Ssam #endif 7024012Ssam syst = u.u_ru.ru_stime; 7124012Ssam if (USERMODE(locr0[PS])) { 7224012Ssam type |= USER; 7324012Ssam u.u_ar0 = locr0; 7424012Ssam } 7524012Ssam switch (type) { 7624012Ssam 7725678Ssam default: 7834402Skarels #ifdef KADB 7930176Ssam if (kdb_trap(&psl)) 8030176Ssam return; 8130176Ssam #endif 8225678Ssam printf("trap type %d, code = %x, pc = %x\n", type, code, pc); 8325678Ssam type &= ~USER; 8425678Ssam if (type < TRAP_TYPES && trap_type[type]) 8525678Ssam panic(trap_type[type]); 8625678Ssam else 8725678Ssam panic("trap"); 8825678Ssam /*NOTREACHED*/ 8924012Ssam 9025678Ssam case T_PROTFLT + USER: /* protection fault */ 9124012Ssam i = SIGBUS; 9224012Ssam break; 9324012Ssam 9424012Ssam case T_PRIVINFLT + USER: /* privileged instruction fault */ 9525678Ssam case T_RESADFLT + USER: /* reserved addressing fault */ 9625678Ssam case T_RESOPFLT + USER: /* resereved operand fault */ 9725678Ssam case T_ALIGNFLT + USER: /* unaligned data fault */ 9824012Ssam u.u_code = type &~ USER; 9924012Ssam i = SIGILL; 10024012Ssam break; 10124012Ssam 10225678Ssam case T_ASTFLT + USER: /* Allow process switch */ 10324012Ssam case T_ASTFLT: 10424012Ssam astoff(); 10524012Ssam if ((u.u_procp->p_flag & SOWEUPC) && u.u_prof.pr_scale) { 10624012Ssam addupc(pc, &u.u_prof, 1); 10724012Ssam u.u_procp->p_flag &= ~SOWEUPC; 10824012Ssam } 10924012Ssam goto out; 11024012Ssam 11124012Ssam case T_ARITHTRAP + USER: 11224012Ssam u.u_code = code; 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 14525746Ssam /* 14625746Ssam * For T_KSPNOTVAL and T_BUSERR, can not allow spl to 14725746Ssam * drop to 0 as clock could go off and we would end up 14825746Ssam * doing an rei to the interrupt stack at ipl 0 (a 14925746Ssam * reserved operand fault). Instead, we allow psignal 15025746Ssam * to post an ast, then return to user mode where we 15125746Ssam * will reenter the kernel on the kernel's stack and 15225746Ssam * can then service the signal. 15325746Ssam */ 15424012Ssam case T_KSPNOTVAL: 15525746Ssam if (noproc) 15625746Ssam panic("ksp not valid"); 15725746Ssam /* fall thru... */ 15824012Ssam case T_KSPNOTVAL + USER: 15925772Ssam printf("pid %d: ksp not valid\n", u.u_procp->p_pid); 16025746Ssam /* must insure valid kernel stack pointer? */ 16125746Ssam psignal(u.u_procp, SIGKILL); 16225746Ssam return; 16324012Ssam 16425678Ssam case T_BUSERR + USER: 16525678Ssam u.u_code = code; 16625746Ssam psignal(u.u_procp, SIGBUS); 16725746Ssam return; 16824012Ssam } 16924012Ssam psignal(u.u_procp, i); 17024012Ssam out: 17124012Ssam p = u.u_procp; 17224012Ssam if (p->p_cursig || ISSIG(p)) 17324012Ssam psig(); 17424012Ssam p->p_pri = p->p_usrpri; 17524012Ssam if (runrun) { 17624012Ssam /* 17724012Ssam * Since we are u.u_procp, clock will normally just change 17824012Ssam * our priority without moving us from one queue to another 17924012Ssam * (since the running process is not on a queue.) 18024012Ssam * If that happened after we setrq ourselves but before we 18124012Ssam * swtch()'ed, we might not be on the queue indicated by 18224012Ssam * our priority. 18324012Ssam */ 18429561Ssam (void) splclock(); 18524012Ssam setrq(p); 18624012Ssam u.u_ru.ru_nivcsw++; 18724012Ssam swtch(); 18824012Ssam } 18924012Ssam if (u.u_prof.pr_scale) { 19024012Ssam int ticks; 19124012Ssam struct timeval *tv = &u.u_ru.ru_stime; 19224012Ssam 19324012Ssam ticks = ((tv->tv_sec - syst.tv_sec) * 1000 + 19424012Ssam (tv->tv_usec - syst.tv_usec) / 1000) / (tick / 1000); 19524012Ssam if (ticks) 19624012Ssam addupc(locr0[PC], &u.u_prof, ticks); 19724012Ssam } 19824012Ssam curpri = p->p_pri; 19924012Ssam } 20024012Ssam 20124012Ssam #ifdef SYSCALLTRACE 20225678Ssam int syscalltrace = 0; 20324012Ssam #endif 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; 21924012Ssam int opc; 22024012Ssam 22125678Ssam #ifdef lint 22225678Ssam r0 = 0; r0 = r0; r1 = 0; r1 = r1; 22325678Ssam #endif 22424012Ssam syst = u.u_ru.ru_stime; 22524012Ssam if (!USERMODE(locr0[PS])) 22624012Ssam panic("syscall"); 22724012Ssam u.u_ar0 = locr0; 22824012Ssam params = (caddr_t)locr0[FP] + NBPW; 22924012Ssam u.u_error = 0; 23025678Ssam /* BEGIN GROT */ 23125678Ssam /* 23225678Ssam * Try to reconstruct pc, assuming code 23325678Ssam * is an immediate constant 23425678Ssam */ 23524012Ssam opc = pc - 2; /* short literal */ 23624012Ssam if (code > 0x3f) { 23725678Ssam opc--; /* byte immediate */ 23824012Ssam if (code > 0x7f) { 23925678Ssam opc--; /* word immediate */ 24024012Ssam if (code > 0x7fff) 24124012Ssam opc -= 2; /* long immediate */ 24224012Ssam } 24324012Ssam } 24425678Ssam /* END GROT */ 24524012Ssam callp = (code >= nsysent) ? &sysent[63] : &sysent[code]; 24624012Ssam if (callp == sysent) { 24724012Ssam i = fuword(params); 24824012Ssam params += NBPW; 24925678Ssam callp = (code >= nsysent) ? &sysent[63] : &sysent[code]; 25024012Ssam } 25125678Ssam if ((i = callp->sy_narg * sizeof (int)) && 25225678Ssam (u.u_error = copyin(params, (caddr_t)u.u_arg, (u_int)i)) != 0) { 25325678Ssam locr0[R0] = u.u_error; 25425678Ssam locr0[PS] |= PSL_C; /* carry bit */ 25525678Ssam goto done; 25624012Ssam } 25724012Ssam u.u_r.r_val1 = 0; 25825678Ssam u.u_r.r_val2 = locr0[R1]; 25924012Ssam if (setjmp(&u.u_qsave)) { 26025678Ssam if (u.u_error == 0 && u.u_eosys != RESTARTSYS) 26124012Ssam u.u_error = EINTR; 26224012Ssam } else { 26325678Ssam u.u_eosys = NORMALRETURN; 26438404Smarc #ifdef KTRACE 26538404Smarc if (KTRPOINT(p, KTR_SYSCALL)) 26638404Smarc ktrsyscall(p->p_tracep, code, callp->sy_narg); 26724012Ssam #endif 268*38406Smckusick (*callp->sy_call)(&u); 26924012Ssam } 27025678Ssam if (u.u_eosys == NORMALRETURN) { 27125678Ssam if (u.u_error) { 27225678Ssam locr0[R0] = u.u_error; 27325678Ssam locr0[PS] |= PSL_C; /* carry bit */ 27425678Ssam } else { 27525678Ssam locr0[PS] &= ~PSL_C; /* clear carry bit */ 27625678Ssam locr0[R0] = u.u_r.r_val1; 27725678Ssam locr0[R1] = u.u_r.r_val2; 27825678Ssam } 27925678Ssam } else if (u.u_eosys == RESTARTSYS) 28024012Ssam pc = opc; 28125678Ssam /* else if (u.u_eosys == JUSTRETURN) */ 28225678Ssam /* nothing to do */ 28338404Smarc #ifdef KTRACE 28438404Smarc if (KTRPOINT(p, KTR_SYSRET)) 28538404Smarc ktrsysret(p->p_tracep, code); 28638404Smarc #endif 28724012Ssam done: 28824012Ssam p = u.u_procp; 28924012Ssam if (p->p_cursig || ISSIG(p)) 29024012Ssam psig(); 29124012Ssam p->p_pri = p->p_usrpri; 29224012Ssam if (runrun) { 29324012Ssam /* 29424012Ssam * Since we are u.u_procp, clock will normally just change 29524012Ssam * our priority without moving us from one queue to another 29624012Ssam * (since the running process is not on a queue.) 29724012Ssam * If that happened after we setrq ourselves but before we 29824012Ssam * swtch()'ed, we might not be on the queue indicated by 29924012Ssam * our priority. 30024012Ssam */ 30129561Ssam (void) splclock(); 30224012Ssam setrq(p); 30324012Ssam u.u_ru.ru_nivcsw++; 30424012Ssam swtch(); 30524012Ssam } 30624012Ssam if (u.u_prof.pr_scale) { 30724012Ssam int ticks; 30824012Ssam struct timeval *tv = &u.u_ru.ru_stime; 30924012Ssam 31024012Ssam ticks = ((tv->tv_sec - syst.tv_sec) * 1000 + 31124012Ssam (tv->tv_usec - syst.tv_usec) / 1000) / (tick / 1000); 31224012Ssam if (ticks) 31324012Ssam addupc(locr0[PC], &u.u_prof, ticks); 31424012Ssam } 31524012Ssam curpri = p->p_pri; 31624012Ssam } 31724012Ssam 31824012Ssam /* 31924012Ssam * nonexistent system call-- signal process (may want to handle it) 32024012Ssam * flag error if process won't see signal immediately 32124012Ssam * Q: should we do that all the time ?? 32224012Ssam */ 32324012Ssam nosys() 32424012Ssam { 32525678Ssam 32624012Ssam if (u.u_signal[SIGSYS] == SIG_IGN || u.u_signal[SIGSYS] == SIG_HOLD) 32724012Ssam u.u_error = EINVAL; 32824012Ssam psignal(u.u_procp, SIGSYS); 32924012Ssam } 33024012Ssam 33125678Ssam #ifdef notdef 33224012Ssam /* 33324012Ssam * Ignored system call 33424012Ssam */ 33524012Ssam nullsys() 33624012Ssam { 33724012Ssam 33824012Ssam } 33925678Ssam #endif 340