1*34408Skarels /* 2*34408Skarels * Copyright (c) 1988 Regents of the University of California. 3*34408Skarels * All rights reserved. The Berkeley software License Agreement 4*34408Skarels * specifies the terms and conditions for redistribution. 5*34408Skarels * 6*34408Skarels * @(#)trap.c 7.1 (Berkeley) 05/21/88 7*34408Skarels */ 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" 17*34408Skarels 18*34408Skarels #include "psl.h" 19*34408Skarels #include "reg.h" 20*34408Skarels #include "pte.h" 21*34408Skarels #include "mtpr.h" 22*34408Skarels 2325678Ssam #define SYSCALLTRACE 2424012Ssam #ifdef SYSCALLTRACE 2524012Ssam #include "../sys/syscalls.c" 2624012Ssam #endif 2724012Ssam 2825678Ssam #include "../tahoe/trap.h" 2925678Ssam 3024012Ssam #define USER 040 /* user-mode flag added to type */ 3124012Ssam 3225678Ssam struct sysent sysent[]; 3325678Ssam int nsysent; 3424012Ssam 3525678Ssam char *trap_type[] = { 3625678Ssam "Reserved addressing mode", /* T_RESADFLT */ 3725678Ssam "Privileged instruction", /* T_PRIVINFLT */ 3825678Ssam "Reserved operand", /* T_RESOPFLT */ 3925678Ssam "Breakpoint", /* T_BPTFLT */ 4025678Ssam 0, 4125678Ssam "Kernel call", /* T_SYSCALL */ 4225678Ssam "Arithmetic trap", /* T_ARITHTRAP */ 4325678Ssam "System forced exception", /* T_ASTFLT */ 4425678Ssam "Segmentation fault", /* T_SEGFLT */ 4525678Ssam "Protection fault", /* T_PROTFLT */ 4625678Ssam "Trace trap", /* T_TRCTRAP */ 4725678Ssam 0, 4825678Ssam "Page fault", /* T_PAGEFLT */ 4925678Ssam "Page table fault", /* T_TABLEFLT */ 5025678Ssam "Alignment fault", /* T_ALIGNFLT */ 5125678Ssam "Kernel stack not valid", /* T_KSPNOTVAL */ 5225678Ssam "Bus error", /* T_BUSERR */ 5330176Ssam "Kernel debugger trap", /* T_KDBTRAP */ 5425678Ssam }; 5530176Ssam int TRAP_TYPES = sizeof (trap_type) / sizeof (trap_type[0]); 5625678Ssam 5724012Ssam /* 5824012Ssam * Called from the trap handler when a processor trap occurs. 5924012Ssam */ 6025678Ssam /*ARGSUSED*/ 6124012Ssam trap(sp, type, hfs, accmst, acclst, dbl, code, pc, psl) 6225678Ssam unsigned type, code; 6324012Ssam { 6425678Ssam int r0, r1; /* must reserve space */ 6524012Ssam register int *locr0 = ((int *)&psl)-PS; 6624012Ssam register int i; 6724012Ssam register struct proc *p; 6824012Ssam struct timeval syst; 6924012Ssam 7025678Ssam #ifdef lint 7125678Ssam r0 = 0; r0 = r0; r1 = 0; r1 = r1; 7225678Ssam #endif 7324012Ssam syst = u.u_ru.ru_stime; 7424012Ssam if (USERMODE(locr0[PS])) { 7524012Ssam type |= USER; 7624012Ssam u.u_ar0 = locr0; 7724012Ssam } 7824012Ssam switch (type) { 7924012Ssam 8025678Ssam default: 8134402Skarels #ifdef KADB 8230176Ssam if (kdb_trap(&psl)) 8330176Ssam return; 8430176Ssam #endif 8525678Ssam printf("trap type %d, code = %x, pc = %x\n", type, code, pc); 8625678Ssam type &= ~USER; 8725678Ssam if (type < TRAP_TYPES && trap_type[type]) 8825678Ssam panic(trap_type[type]); 8925678Ssam else 9025678Ssam panic("trap"); 9125678Ssam /*NOTREACHED*/ 9224012Ssam 9325678Ssam case T_PROTFLT + USER: /* protection fault */ 9424012Ssam i = SIGBUS; 9524012Ssam break; 9624012Ssam 9724012Ssam case T_PRIVINFLT + USER: /* privileged instruction fault */ 9825678Ssam case T_RESADFLT + USER: /* reserved addressing fault */ 9925678Ssam case T_RESOPFLT + USER: /* resereved operand fault */ 10025678Ssam case T_ALIGNFLT + USER: /* unaligned data fault */ 10124012Ssam u.u_code = type &~ USER; 10224012Ssam i = SIGILL; 10324012Ssam break; 10424012Ssam 10525678Ssam case T_ASTFLT + USER: /* Allow process switch */ 10624012Ssam case T_ASTFLT: 10724012Ssam astoff(); 10824012Ssam if ((u.u_procp->p_flag & SOWEUPC) && u.u_prof.pr_scale) { 10924012Ssam addupc(pc, &u.u_prof, 1); 11024012Ssam u.u_procp->p_flag &= ~SOWEUPC; 11124012Ssam } 11224012Ssam goto out; 11324012Ssam 11424012Ssam case T_ARITHTRAP + USER: 11524012Ssam u.u_code = code; 11624012Ssam i = SIGFPE; 11724012Ssam break; 11824012Ssam 11924012Ssam /* 12024012Ssam * If the user SP is above the stack segment, 12124012Ssam * grow the stack automatically. 12224012Ssam */ 12324012Ssam case T_SEGFLT + USER: 12424012Ssam if (grow((unsigned)locr0[SP]) || grow(code)) 12524012Ssam goto out; 12624012Ssam i = SIGSEGV; 12724012Ssam break; 12824012Ssam 12925678Ssam case T_TABLEFLT: /* allow page table faults in kernel */ 13025678Ssam case T_TABLEFLT + USER: /* page table fault */ 13124012Ssam panic("ptable fault"); 13224012Ssam 13325678Ssam case T_PAGEFLT: /* allow page faults in kernel mode */ 13425678Ssam case T_PAGEFLT + USER: /* page fault */ 13524012Ssam i = u.u_error; 13625678Ssam pagein(code, 0); 13724012Ssam u.u_error = i; 13824012Ssam if (type == T_PAGEFLT) 13924012Ssam return; 14024012Ssam goto out; 14124012Ssam 14225678Ssam case T_BPTFLT + USER: /* bpt instruction fault */ 14325678Ssam case T_TRCTRAP + USER: /* trace trap */ 14424012Ssam locr0[PS] &= ~PSL_T; 14524012Ssam i = SIGTRAP; 14624012Ssam break; 14725678Ssam 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); 16325746Ssam /* must insure valid kernel stack pointer? */ 16425746Ssam psignal(u.u_procp, SIGKILL); 16525746Ssam return; 16624012Ssam 16725678Ssam case T_BUSERR + USER: 16825678Ssam u.u_code = code; 16925746Ssam psignal(u.u_procp, SIGBUS); 17025746Ssam return; 17124012Ssam } 17224012Ssam psignal(u.u_procp, i); 17324012Ssam out: 17424012Ssam p = u.u_procp; 17524012Ssam if (p->p_cursig || ISSIG(p)) 17624012Ssam psig(); 17724012Ssam p->p_pri = p->p_usrpri; 17824012Ssam if (runrun) { 17924012Ssam /* 18024012Ssam * Since we are u.u_procp, clock will normally just change 18124012Ssam * our priority without moving us from one queue to another 18224012Ssam * (since the running process is not on a queue.) 18324012Ssam * If that happened after we setrq ourselves but before we 18424012Ssam * swtch()'ed, we might not be on the queue indicated by 18524012Ssam * our priority. 18624012Ssam */ 18729561Ssam (void) splclock(); 18824012Ssam setrq(p); 18924012Ssam u.u_ru.ru_nivcsw++; 19024012Ssam swtch(); 19124012Ssam } 19224012Ssam if (u.u_prof.pr_scale) { 19324012Ssam int ticks; 19424012Ssam struct timeval *tv = &u.u_ru.ru_stime; 19524012Ssam 19624012Ssam ticks = ((tv->tv_sec - syst.tv_sec) * 1000 + 19724012Ssam (tv->tv_usec - syst.tv_usec) / 1000) / (tick / 1000); 19824012Ssam if (ticks) 19924012Ssam addupc(locr0[PC], &u.u_prof, ticks); 20024012Ssam } 20124012Ssam curpri = p->p_pri; 20224012Ssam } 20324012Ssam 20424012Ssam #ifdef SYSCALLTRACE 20525678Ssam int syscalltrace = 0; 20624012Ssam #endif 20724012Ssam 20824012Ssam /* 20925678Ssam * Called from locore when a system call occurs 21024012Ssam */ 21125678Ssam /*ARGSUSED*/ 21224012Ssam syscall(sp, type, hfs, accmst, acclst, dbl, code, pc, psl) 21325678Ssam unsigned code; 21424012Ssam { 21525678Ssam int r0, r1; /* must reserve space */ 21624012Ssam register int *locr0 = ((int *)&psl)-PS; 21725678Ssam register caddr_t params; 21825678Ssam register int i; 21924012Ssam register struct sysent *callp; 22024012Ssam register struct proc *p; 22125678Ssam struct timeval syst; 22224012Ssam int opc; 22324012Ssam 22425678Ssam #ifdef lint 22525678Ssam r0 = 0; r0 = r0; r1 = 0; r1 = r1; 22625678Ssam #endif 22724012Ssam syst = u.u_ru.ru_stime; 22824012Ssam if (!USERMODE(locr0[PS])) 22924012Ssam panic("syscall"); 23024012Ssam u.u_ar0 = locr0; 23125678Ssam if (code == 139) { /* 4.2 COMPATIBILTY XXX */ 23225678Ssam osigcleanup(); /* 4.2 COMPATIBILTY XXX */ 23325678Ssam goto done; /* 4.2 COMPATIBILTY XXX */ 23424012Ssam } 23524012Ssam params = (caddr_t)locr0[FP] + NBPW; 23624012Ssam u.u_error = 0; 23725678Ssam /* BEGIN GROT */ 23825678Ssam /* 23925678Ssam * Try to reconstruct pc, assuming code 24025678Ssam * is an immediate constant 24125678Ssam */ 24224012Ssam opc = pc - 2; /* short literal */ 24324012Ssam if (code > 0x3f) { 24425678Ssam opc--; /* byte immediate */ 24524012Ssam if (code > 0x7f) { 24625678Ssam opc--; /* word immediate */ 24724012Ssam if (code > 0x7fff) 24824012Ssam opc -= 2; /* long immediate */ 24924012Ssam } 25024012Ssam } 25125678Ssam /* END GROT */ 25224012Ssam callp = (code >= nsysent) ? &sysent[63] : &sysent[code]; 25324012Ssam if (callp == sysent) { 25424012Ssam i = fuword(params); 25524012Ssam params += NBPW; 25625678Ssam callp = (code >= nsysent) ? &sysent[63] : &sysent[code]; 25724012Ssam } 25825678Ssam if ((i = callp->sy_narg * sizeof (int)) && 25925678Ssam (u.u_error = copyin(params, (caddr_t)u.u_arg, (u_int)i)) != 0) { 26025678Ssam locr0[R0] = u.u_error; 26125678Ssam locr0[PS] |= PSL_C; /* carry bit */ 26225678Ssam goto done; 26324012Ssam } 26424012Ssam u.u_r.r_val1 = 0; 26525678Ssam u.u_r.r_val2 = locr0[R1]; 26624012Ssam if (setjmp(&u.u_qsave)) { 26725678Ssam if (u.u_error == 0 && u.u_eosys != RESTARTSYS) 26824012Ssam u.u_error = EINTR; 26924012Ssam } else { 27025678Ssam u.u_eosys = NORMALRETURN; 27124012Ssam #ifdef SYSCALLTRACE 27224012Ssam if (syscalltrace) { 27330297Ssam register int a; 27424012Ssam char *cp; 27524012Ssam 27624012Ssam if (code >= nsysent) 27724012Ssam printf("0x%x", code); 27824012Ssam else 27924012Ssam printf("%s", syscallnames[code]); 28024012Ssam cp = "("; 28130297Ssam for (a = 0; a < callp->sy_narg; a++) { 28230297Ssam printf("%s%x", cp, u.u_arg[a]); 28324012Ssam cp = ", "; 28424012Ssam } 28530297Ssam if (a) 28630297Ssam printf(")"); 28730297Ssam printf("\n"); 28824012Ssam } 28924012Ssam #endif 29025678Ssam (*callp->sy_call)(); 29124012Ssam } 29225678Ssam if (u.u_eosys == NORMALRETURN) { 29325678Ssam if (u.u_error) { 29425678Ssam locr0[R0] = u.u_error; 29525678Ssam locr0[PS] |= PSL_C; /* carry bit */ 29625678Ssam } else { 29725678Ssam locr0[PS] &= ~PSL_C; /* clear carry bit */ 29825678Ssam locr0[R0] = u.u_r.r_val1; 29925678Ssam locr0[R1] = u.u_r.r_val2; 30025678Ssam } 30125678Ssam } else if (u.u_eosys == RESTARTSYS) 30224012Ssam pc = opc; 30325678Ssam /* else if (u.u_eosys == JUSTRETURN) */ 30425678Ssam /* nothing to do */ 30524012Ssam done: 30624012Ssam p = u.u_procp; 30724012Ssam if (p->p_cursig || ISSIG(p)) 30824012Ssam psig(); 30924012Ssam p->p_pri = p->p_usrpri; 31024012Ssam if (runrun) { 31124012Ssam /* 31224012Ssam * Since we are u.u_procp, clock will normally just change 31324012Ssam * our priority without moving us from one queue to another 31424012Ssam * (since the running process is not on a queue.) 31524012Ssam * If that happened after we setrq ourselves but before we 31624012Ssam * swtch()'ed, we might not be on the queue indicated by 31724012Ssam * our priority. 31824012Ssam */ 31929561Ssam (void) splclock(); 32024012Ssam setrq(p); 32124012Ssam u.u_ru.ru_nivcsw++; 32224012Ssam swtch(); 32324012Ssam } 32424012Ssam if (u.u_prof.pr_scale) { 32524012Ssam int ticks; 32624012Ssam struct timeval *tv = &u.u_ru.ru_stime; 32724012Ssam 32824012Ssam ticks = ((tv->tv_sec - syst.tv_sec) * 1000 + 32924012Ssam (tv->tv_usec - syst.tv_usec) / 1000) / (tick / 1000); 33024012Ssam if (ticks) 33124012Ssam addupc(locr0[PC], &u.u_prof, ticks); 33224012Ssam } 33324012Ssam curpri = p->p_pri; 33424012Ssam } 33524012Ssam 33624012Ssam /* 33724012Ssam * nonexistent system call-- signal process (may want to handle it) 33824012Ssam * flag error if process won't see signal immediately 33924012Ssam * Q: should we do that all the time ?? 34024012Ssam */ 34124012Ssam nosys() 34224012Ssam { 34325678Ssam 34424012Ssam if (u.u_signal[SIGSYS] == SIG_IGN || u.u_signal[SIGSYS] == SIG_HOLD) 34524012Ssam u.u_error = EINVAL; 34624012Ssam psignal(u.u_procp, SIGSYS); 34724012Ssam } 34824012Ssam 34925678Ssam #ifdef notdef 35024012Ssam /* 35124012Ssam * Ignored system call 35224012Ssam */ 35324012Ssam nullsys() 35424012Ssam { 35524012Ssam 35624012Ssam } 35725678Ssam #endif 358