1 /*- 2 * Copyright (c) 1990 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * the University of Utah, and William Jolitz. 7 * 8 * %sccs.include.386.c% 9 * 10 * @(#)trap.c 5.5 (Berkeley) 11/25/90 11 */ 12 13 /* 14 * Copyright (c) 1989, 1990 William F. Jolitz 15 */ 16 17 /* 18 * 386 Trap and System call handleing 19 */ 20 21 #include "../i386/psl.h" 22 #include "../i386/reg.h" 23 #include "../i386/pte.h" 24 #include "../i386/segments.h" 25 #include "../i386/frame.h" 26 27 #include "param.h" 28 #include "systm.h" 29 #include "dir.h" 30 #include "user.h" 31 #include "proc.h" 32 #include "seg.h" 33 #include "acct.h" 34 #include "kernel.h" 35 #include "vm.h" 36 #include "cmap.h" 37 38 #include "../i386/trap.h" 39 40 #define USER 0x100 /* user-mode flag added to type */ 41 42 struct sysent sysent[]; 43 int nsysent; 44 /* 45 * Called from the trap handler when a processor trap occurs. 46 */ 47 unsigned *rcr2(), Sysbase; 48 extern short cpl; 49 /*ARGSUSED*/ 50 trap(frame) 51 struct trapframe frame; 52 #define type frame.tf_trapno 53 #define code frame.tf_err 54 #define pc frame.tf_eip 55 { 56 register int *locr0 = ((int *)&frame); 57 register int i; 58 register struct proc *p; 59 struct timeval syst; 60 extern int nofault; 61 62 63 locr0[tEFLAGS] &= ~PSL_NT; /* clear nested trap XXX */ 64 if(nofault && frame.tf_trapno != 0xc) { 65 locr0[tEIP] = nofault; return; 66 } 67 68 syst = u.u_ru.ru_stime; 69 if (ISPL(locr0[tCS]) == SEL_UPL) { 70 type |= USER; 71 u.u_ar0 = locr0; 72 } 73 switch (type) { 74 75 default: 76 bit_sucker: 77 #ifdef KDB 78 if (kdb_trap(&psl)) 79 return; 80 #endif 81 printf("trap type %d code %x pc %x cs %x eflags %x\n", 82 type, code, pc, frame.tf_cs, frame.tf_eflags); 83 type &= ~USER; 84 panic("trap"); 85 /*NOTREACHED*/ 86 87 case T_SEGNPFLT + USER: 88 case T_PROTFLT + USER: /* protection fault */ 89 u.u_code = code + BUS_SEGM_FAULT ; 90 i = SIGBUS; 91 break; 92 93 case T_PRIVINFLT + USER: /* privileged instruction fault */ 94 case T_RESADFLT + USER: /* reserved addressing fault */ 95 case T_RESOPFLT + USER: /* reserved operand fault */ 96 case T_FPOPFLT + USER: /* coprocessor operand fault */ 97 u.u_code = type &~ USER; 98 i = SIGILL; 99 break; 100 101 case T_ASTFLT + USER: /* Allow process switch */ 102 case T_ASTFLT: 103 astoff(); 104 if ((u.u_procp->p_flag & SOWEUPC) && u.u_prof.pr_scale) { 105 addupc(pc, &u.u_prof, 1); 106 u.u_procp->p_flag &= ~SOWEUPC; 107 } 108 goto out; 109 110 case T_DNA + USER: 111 u.u_code = FPE_FPU_NP_TRAP; 112 i = SIGFPE; 113 break; 114 115 case T_BOUND + USER: 116 u.u_code = FPE_SUBRNG_TRAP; 117 i = SIGFPE; 118 break; 119 120 case T_OFLOW + USER: 121 u.u_code = FPE_INTOVF_TRAP; 122 i = SIGFPE; 123 break; 124 125 case T_DIVIDE + USER: 126 u.u_code = FPE_INTDIV_TRAP; 127 i = SIGFPE; 128 break; 129 130 case T_ARITHTRAP + USER: 131 u.u_code = code; 132 i = SIGFPE; 133 break; 134 #ifdef notdef 135 /* 136 * If the user SP is above the stack segment, 137 * grow the stack automatically. 138 */ 139 case T_STKFLT + USER: 140 case T_SEGFLT + USER: 141 if (grow((unsigned)locr0[tESP])) 142 goto out; 143 u.u_code = code; 144 i = SIGSEGV; 145 break; 146 147 case T_TABLEFLT: /* allow page table faults in kernel */ 148 case T_TABLEFLT + USER: /* page table fault */ 149 panic("ptable fault"); 150 #endif 151 152 case T_PAGEFLT: /* allow page faults in kernel mode */ 153 if (code & PGEX_P) goto bit_sucker; 154 /* fall into */ 155 case T_PAGEFLT + USER: /* page fault */ 156 { register u_int vp; 157 u_int ea; 158 159 ea = (u_int)rcr2(); 160 161 /* out of bounds reference */ 162 if (ea >= &Sysbase || code & PGEX_P) { 163 u.u_code = code + BUS_PAGE_FAULT; 164 i = SIGBUS; 165 break; 166 } 167 168 /* stack reference to the running process? */ 169 vp = btop(ea); 170 if (vp >= dptov(u.u_procp, u.u_procp->p_dsize) 171 && vp < sptov(u.u_procp, u.u_procp->p_ssize-1)){ 172 /* attempt to grow stack */ 173 if (grow((unsigned)locr0[tESP]) || grow(ea)) { 174 if (type == T_PAGEFLT) return; 175 goto out; 176 } else if (nofault) { 177 locr0[tEIP] = nofault; 178 return; 179 } 180 i = SIGSEGV; 181 break; 182 } 183 184 i = u.u_error; 185 pagein(ea, 0); 186 u.u_error = i; 187 if (type == T_PAGEFLT) return; 188 goto out; 189 } 190 191 case T_TRCTRAP: /* trace trap -- someone single stepping lcall's */ 192 locr0[tEFLAGS] &= ~PSL_T; 193 /* Q: how do we turn it on again? */ 194 return; 195 196 case T_BPTFLT + USER: /* bpt instruction fault */ 197 case T_TRCTRAP + USER: /* trace trap */ 198 locr0[tEFLAGS] &= ~PSL_T; 199 i = SIGTRAP; 200 break; 201 202 #ifdef notdef 203 /* 204 * For T_KSPNOTVAL and T_BUSERR, can not allow spl to 205 * drop to 0 as clock could go off and we would end up 206 * doing an rei to the interrupt stack at ipl 0 (a 207 * reserved operand fault). Instead, we allow psignal 208 * to post an ast, then return to user mode where we 209 * will reenter the kernel on the kernel's stack and 210 * can then service the signal. 211 */ 212 case T_KSPNOTVAL: 213 if (noproc) 214 panic("ksp not valid"); 215 /* fall thru... */ 216 case T_KSPNOTVAL + USER: 217 printf("pid %d: ksp not valid\n", u.u_procp->p_pid); 218 /* must insure valid kernel stack pointer? */ 219 psignal(u.u_procp, SIGKILL); 220 return; 221 222 case T_BUSERR + USER: 223 u.u_code = code; 224 psignal(u.u_procp, SIGBUS); 225 return; 226 #endif 227 228 #include "isa.h" 229 #if NISA > 0 230 case T_NMI: 231 case T_NMI + USER: 232 if(isa_nmi(code) == 0) return; 233 else goto bit_sucker; 234 #endif 235 } 236 psignal(u.u_procp, i); 237 out: 238 p = u.u_procp; 239 240 if (p->p_cursig || ISSIG(p)) 241 psig(1); 242 p->p_pri = p->p_usrpri; 243 if (runrun) { 244 /* 245 * Since we are u.u_procp, clock will normally just change 246 * our priority without moving us from one queue to another 247 * (since the running process is not on a queue.) 248 * If that happened after we setrq ourselves but before we 249 * swtch()'ed, we might not be on the queue indicated by 250 * our priority. 251 */ 252 (void) splclock(); 253 setrq(p); 254 u.u_ru.ru_nivcsw++; 255 swtch(); 256 (void)spl0(); 257 } 258 if (u.u_prof.pr_scale) { 259 int ticks; 260 struct timeval *tv = &u.u_ru.ru_stime; 261 262 ticks = ((tv->tv_sec - syst.tv_sec) * 1000 + 263 (tv->tv_usec - syst.tv_usec) / 1000) / (tick / 1000); 264 if (ticks) 265 addupc(pc, &u.u_prof, ticks); 266 } 267 curpri = p->p_pri; 268 #undef type 269 #undef code 270 #undef pc 271 } 272 273 /* 274 * Called from locore when a system call occurs 275 */ 276 /*ARGSUSED*/ 277 syscall(frame) 278 struct syscframe frame; 279 #define code frame.sf_eax /* note: written over! */ 280 #define pc frame.sf_eip 281 { 282 register int *locr0 = ((int *)&frame); 283 register caddr_t params; 284 register int i; 285 register struct sysent *callp; 286 register struct proc *p; 287 struct timeval syst; 288 int opc; 289 290 #ifdef lint 291 r0 = 0; r0 = r0; r1 = 0; r1 = r1; 292 #endif 293 syst = u.u_ru.ru_stime; 294 if (ISPL(locr0[sCS]) != SEL_UPL) 295 panic("syscall"); 296 u.u_ar0 = locr0; 297 params = (caddr_t)locr0[sESP] + NBPW ; 298 u.u_error = 0; 299 /* 300 * Reconstruct pc, assuming lcall $X,y is 7 bytes, as it is always. 301 */ 302 opc = pc - 7; 303 callp = (code >= nsysent) ? &sysent[63] : &sysent[code]; 304 if (callp == sysent) { 305 i = fuword(params); 306 params += NBPW; 307 callp = (code >= nsysent) ? &sysent[63] : &sysent[code]; 308 } 309 if ((i = callp->sy_narg * sizeof (int)) && 310 (u.u_error = copyin(params, (caddr_t)u.u_arg, (u_int)i)) != 0) { 311 locr0[sEAX] = u.u_error; 312 locr0[sEFLAGS] |= PSL_C; /* carry bit */ 313 goto done; 314 } 315 u.u_r.r_val1 = 0; 316 u.u_r.r_val2 = locr0[sEDX]; 317 if (setjmp(&u.u_qsave)) { 318 if (u.u_error == 0 && u.u_eosys != RESTARTSYS) 319 u.u_error = EINTR; 320 } else { 321 u.u_eosys = NORMALRETURN; 322 (*callp->sy_call)(); 323 } 324 if (u.u_eosys == NORMALRETURN) { 325 if (u.u_error) { 326 locr0[sEAX] = u.u_error; 327 locr0[sEFLAGS] |= PSL_C; /* carry bit */ 328 } else { 329 locr0[sEFLAGS] &= ~PSL_C; /* clear carry bit */ 330 locr0[sEAX] = u.u_r.r_val1; 331 locr0[sEDX] = u.u_r.r_val2; 332 } 333 } else if (u.u_eosys == RESTARTSYS) 334 pc = opc; 335 /* else if (u.u_eosys == JUSTRETURN) */ 336 /* nothing to do */ 337 done: 338 p = u.u_procp; 339 if (p->p_cursig || ISSIG(p)) 340 psig(0); 341 p->p_pri = p->p_usrpri; 342 if (runrun) { 343 /* 344 * Since we are u.u_procp, clock will normally just change 345 * our priority without moving us from one queue to another 346 * (since the running process is not on a queue.) 347 * If that happened after we setrq ourselves but before we 348 * swtch()'ed, we might not be on the queue indicated by 349 * our priority. 350 */ 351 (void) splclock(); 352 setrq(p); 353 u.u_ru.ru_nivcsw++; 354 swtch(); 355 (void)spl0(); 356 } 357 if (u.u_prof.pr_scale) { 358 int ticks; 359 struct timeval *tv = &u.u_ru.ru_stime; 360 361 ticks = ((tv->tv_sec - syst.tv_sec) * 1000 + 362 (tv->tv_usec - syst.tv_usec) / 1000) / (tick / 1000); 363 if (ticks) 364 addupc(opc, &u.u_prof, ticks); 365 } 366 curpri = p->p_pri; 367 } 368 369 /* 370 * nonexistent system call-- signal process (may want to handle it) 371 * flag error if process won't see signal immediately 372 * Q: should we do that all the time ?? 373 */ 374 nosys() 375 { 376 377 if (u.u_signal[SIGSYS] == SIG_IGN || u.u_signal[SIGSYS] == SIG_HOLD) 378 u.u_error = EINVAL; 379 psignal(u.u_procp, SIGSYS); 380 } 381 382 /* 383 * Ignored system call 384 */ 385 nullsys() 386 { 387 } 388