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*38404Smarc * @(#)trap.c 7.2 (Berkeley) 07/04/89 734408Skarels */ 824012Ssam 925678Ssam #include "param.h" 1025678Ssam #include "systm.h" 1125678Ssam #include "dir.h" 1225678Ssam #include "user.h" 1325678Ssam #include "proc.h" 1425678Ssam #include "seg.h" 1525678Ssam #include "acct.h" 1625678Ssam #include "kernel.h" 1734408Skarels 1834408Skarels #include "psl.h" 1934408Skarels #include "reg.h" 2034408Skarels #include "pte.h" 2134408Skarels #include "mtpr.h" 22*38404Smarc #ifdef KTRACE 23*38404Smarc #include "ktrace.h" 2424012Ssam #endif 2524012Ssam 2625678Ssam #include "../tahoe/trap.h" 2725678Ssam 2824012Ssam #define USER 040 /* user-mode flag added to type */ 2924012Ssam 3025678Ssam struct sysent sysent[]; 3125678Ssam int nsysent; 3224012Ssam 3325678Ssam char *trap_type[] = { 3425678Ssam "Reserved addressing mode", /* T_RESADFLT */ 3525678Ssam "Privileged instruction", /* T_PRIVINFLT */ 3625678Ssam "Reserved operand", /* T_RESOPFLT */ 3725678Ssam "Breakpoint", /* T_BPTFLT */ 3825678Ssam 0, 3925678Ssam "Kernel call", /* T_SYSCALL */ 4025678Ssam "Arithmetic trap", /* T_ARITHTRAP */ 4125678Ssam "System forced exception", /* T_ASTFLT */ 4225678Ssam "Segmentation fault", /* T_SEGFLT */ 4325678Ssam "Protection fault", /* T_PROTFLT */ 4425678Ssam "Trace trap", /* T_TRCTRAP */ 4525678Ssam 0, 4625678Ssam "Page fault", /* T_PAGEFLT */ 4725678Ssam "Page table fault", /* T_TABLEFLT */ 4825678Ssam "Alignment fault", /* T_ALIGNFLT */ 4925678Ssam "Kernel stack not valid", /* T_KSPNOTVAL */ 5025678Ssam "Bus error", /* T_BUSERR */ 5130176Ssam "Kernel debugger trap", /* T_KDBTRAP */ 5225678Ssam }; 5330176Ssam int TRAP_TYPES = sizeof (trap_type) / sizeof (trap_type[0]); 5425678Ssam 5524012Ssam /* 5624012Ssam * Called from the trap handler when a processor trap occurs. 5724012Ssam */ 5825678Ssam /*ARGSUSED*/ 5924012Ssam trap(sp, type, hfs, accmst, acclst, dbl, code, pc, psl) 6025678Ssam unsigned type, code; 6124012Ssam { 6225678Ssam int r0, r1; /* must reserve space */ 6324012Ssam register int *locr0 = ((int *)&psl)-PS; 6424012Ssam register int i; 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 */ 9924012Ssam u.u_code = 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 u.u_code = code; 11424012Ssam i = SIGFPE; 11524012Ssam break; 11624012Ssam 11724012Ssam /* 11824012Ssam * If the user SP is above the stack segment, 11924012Ssam * grow the stack automatically. 12024012Ssam */ 12124012Ssam case T_SEGFLT + USER: 12224012Ssam if (grow((unsigned)locr0[SP]) || grow(code)) 12324012Ssam goto out; 12424012Ssam i = SIGSEGV; 12524012Ssam break; 12624012Ssam 12725678Ssam case T_TABLEFLT: /* allow page table faults in kernel */ 12825678Ssam case T_TABLEFLT + USER: /* page table fault */ 12924012Ssam panic("ptable fault"); 13024012Ssam 13125678Ssam case T_PAGEFLT: /* allow page faults in kernel mode */ 13225678Ssam case T_PAGEFLT + USER: /* page fault */ 13324012Ssam i = u.u_error; 13425678Ssam pagein(code, 0); 13524012Ssam u.u_error = i; 13624012Ssam if (type == T_PAGEFLT) 13724012Ssam return; 13824012Ssam goto out; 13924012Ssam 14025678Ssam case T_BPTFLT + USER: /* bpt instruction fault */ 14125678Ssam case T_TRCTRAP + USER: /* trace trap */ 14224012Ssam locr0[PS] &= ~PSL_T; 14324012Ssam i = SIGTRAP; 14424012Ssam break; 14525678Ssam 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); 16125746Ssam /* must insure valid kernel stack pointer? */ 16225746Ssam psignal(u.u_procp, SIGKILL); 16325746Ssam return; 16424012Ssam 16525678Ssam case T_BUSERR + USER: 16625678Ssam u.u_code = code; 16725746Ssam psignal(u.u_procp, SIGBUS); 16825746Ssam return; 16924012Ssam } 17024012Ssam psignal(u.u_procp, i); 17124012Ssam out: 17224012Ssam p = u.u_procp; 17324012Ssam if (p->p_cursig || ISSIG(p)) 17424012Ssam psig(); 17524012Ssam p->p_pri = p->p_usrpri; 17624012Ssam if (runrun) { 17724012Ssam /* 17824012Ssam * Since we are u.u_procp, clock will normally just change 17924012Ssam * our priority without moving us from one queue to another 18024012Ssam * (since the running process is not on a queue.) 18124012Ssam * If that happened after we setrq ourselves but before we 18224012Ssam * swtch()'ed, we might not be on the queue indicated by 18324012Ssam * our priority. 18424012Ssam */ 18529561Ssam (void) splclock(); 18624012Ssam setrq(p); 18724012Ssam u.u_ru.ru_nivcsw++; 18824012Ssam swtch(); 18924012Ssam } 19024012Ssam if (u.u_prof.pr_scale) { 19124012Ssam int ticks; 19224012Ssam struct timeval *tv = &u.u_ru.ru_stime; 19324012Ssam 19424012Ssam ticks = ((tv->tv_sec - syst.tv_sec) * 1000 + 19524012Ssam (tv->tv_usec - syst.tv_usec) / 1000) / (tick / 1000); 19624012Ssam if (ticks) 19724012Ssam addupc(locr0[PC], &u.u_prof, ticks); 19824012Ssam } 19924012Ssam curpri = p->p_pri; 20024012Ssam } 20124012Ssam 20224012Ssam #ifdef SYSCALLTRACE 20325678Ssam int syscalltrace = 0; 20424012Ssam #endif 20524012Ssam 20624012Ssam /* 20725678Ssam * Called from locore when a system call occurs 20824012Ssam */ 20925678Ssam /*ARGSUSED*/ 21024012Ssam syscall(sp, type, hfs, accmst, acclst, dbl, code, pc, psl) 21125678Ssam unsigned code; 21224012Ssam { 21325678Ssam int r0, r1; /* must reserve space */ 21424012Ssam register int *locr0 = ((int *)&psl)-PS; 21525678Ssam register caddr_t params; 21625678Ssam register int i; 21724012Ssam register struct sysent *callp; 218*38404Smarc register struct proc *p = u.u_procp; 21925678Ssam struct timeval syst; 22024012Ssam int opc; 22124012Ssam 22225678Ssam #ifdef lint 22325678Ssam r0 = 0; r0 = r0; r1 = 0; r1 = r1; 22425678Ssam #endif 22524012Ssam syst = u.u_ru.ru_stime; 22624012Ssam if (!USERMODE(locr0[PS])) 22724012Ssam panic("syscall"); 22824012Ssam u.u_ar0 = locr0; 22925678Ssam if (code == 139) { /* 4.2 COMPATIBILTY XXX */ 23025678Ssam osigcleanup(); /* 4.2 COMPATIBILTY XXX */ 23125678Ssam goto done; /* 4.2 COMPATIBILTY XXX */ 23224012Ssam } 23324012Ssam params = (caddr_t)locr0[FP] + NBPW; 23424012Ssam u.u_error = 0; 23525678Ssam /* BEGIN GROT */ 23625678Ssam /* 23725678Ssam * Try to reconstruct pc, assuming code 23825678Ssam * is an immediate constant 23925678Ssam */ 24024012Ssam opc = pc - 2; /* short literal */ 24124012Ssam if (code > 0x3f) { 24225678Ssam opc--; /* byte immediate */ 24324012Ssam if (code > 0x7f) { 24425678Ssam opc--; /* word immediate */ 24524012Ssam if (code > 0x7fff) 24624012Ssam opc -= 2; /* long immediate */ 24724012Ssam } 24824012Ssam } 24925678Ssam /* END GROT */ 25024012Ssam callp = (code >= nsysent) ? &sysent[63] : &sysent[code]; 25124012Ssam if (callp == sysent) { 25224012Ssam i = fuword(params); 25324012Ssam params += NBPW; 25425678Ssam callp = (code >= nsysent) ? &sysent[63] : &sysent[code]; 25524012Ssam } 25625678Ssam if ((i = callp->sy_narg * sizeof (int)) && 25725678Ssam (u.u_error = copyin(params, (caddr_t)u.u_arg, (u_int)i)) != 0) { 25825678Ssam locr0[R0] = u.u_error; 25925678Ssam locr0[PS] |= PSL_C; /* carry bit */ 26025678Ssam goto done; 26124012Ssam } 26224012Ssam u.u_r.r_val1 = 0; 26325678Ssam u.u_r.r_val2 = locr0[R1]; 26424012Ssam if (setjmp(&u.u_qsave)) { 26525678Ssam if (u.u_error == 0 && u.u_eosys != RESTARTSYS) 26624012Ssam u.u_error = EINTR; 26724012Ssam } else { 26825678Ssam u.u_eosys = NORMALRETURN; 269*38404Smarc #ifdef KTRACE 270*38404Smarc if (KTRPOINT(p, KTR_SYSCALL)) 271*38404Smarc ktrsyscall(p->p_tracep, code, callp->sy_narg); 27224012Ssam #endif 27325678Ssam (*callp->sy_call)(); 27424012Ssam } 27525678Ssam if (u.u_eosys == NORMALRETURN) { 27625678Ssam if (u.u_error) { 27725678Ssam locr0[R0] = u.u_error; 27825678Ssam locr0[PS] |= PSL_C; /* carry bit */ 27925678Ssam } else { 28025678Ssam locr0[PS] &= ~PSL_C; /* clear carry bit */ 28125678Ssam locr0[R0] = u.u_r.r_val1; 28225678Ssam locr0[R1] = u.u_r.r_val2; 28325678Ssam } 28425678Ssam } else if (u.u_eosys == RESTARTSYS) 28524012Ssam pc = opc; 28625678Ssam /* else if (u.u_eosys == JUSTRETURN) */ 28725678Ssam /* nothing to do */ 288*38404Smarc #ifdef KTRACE 289*38404Smarc if (KTRPOINT(p, KTR_SYSRET)) 290*38404Smarc ktrsysret(p->p_tracep, code); 291*38404Smarc #endif 29224012Ssam done: 29324012Ssam p = u.u_procp; 29424012Ssam if (p->p_cursig || ISSIG(p)) 29524012Ssam psig(); 29624012Ssam p->p_pri = p->p_usrpri; 29724012Ssam if (runrun) { 29824012Ssam /* 29924012Ssam * Since we are u.u_procp, clock will normally just change 30024012Ssam * our priority without moving us from one queue to another 30124012Ssam * (since the running process is not on a queue.) 30224012Ssam * If that happened after we setrq ourselves but before we 30324012Ssam * swtch()'ed, we might not be on the queue indicated by 30424012Ssam * our priority. 30524012Ssam */ 30629561Ssam (void) splclock(); 30724012Ssam setrq(p); 30824012Ssam u.u_ru.ru_nivcsw++; 30924012Ssam swtch(); 31024012Ssam } 31124012Ssam if (u.u_prof.pr_scale) { 31224012Ssam int ticks; 31324012Ssam struct timeval *tv = &u.u_ru.ru_stime; 31424012Ssam 31524012Ssam ticks = ((tv->tv_sec - syst.tv_sec) * 1000 + 31624012Ssam (tv->tv_usec - syst.tv_usec) / 1000) / (tick / 1000); 31724012Ssam if (ticks) 31824012Ssam addupc(locr0[PC], &u.u_prof, ticks); 31924012Ssam } 32024012Ssam curpri = p->p_pri; 32124012Ssam } 32224012Ssam 32324012Ssam /* 32424012Ssam * nonexistent system call-- signal process (may want to handle it) 32524012Ssam * flag error if process won't see signal immediately 32624012Ssam * Q: should we do that all the time ?? 32724012Ssam */ 32824012Ssam nosys() 32924012Ssam { 33025678Ssam 33124012Ssam if (u.u_signal[SIGSYS] == SIG_IGN || u.u_signal[SIGSYS] == SIG_HOLD) 33224012Ssam u.u_error = EINVAL; 33324012Ssam psignal(u.u_procp, SIGSYS); 33424012Ssam } 33524012Ssam 33625678Ssam #ifdef notdef 33724012Ssam /* 33824012Ssam * Ignored system call 33924012Ssam */ 34024012Ssam nullsys() 34124012Ssam { 34224012Ssam 34324012Ssam } 34425678Ssam #endif 345