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.7 (Berkeley) 01/19/91 11 */ 12 13 14 /* 15 * 386 Trap and System call handleing 16 */ 17 18 #include "machine/psl.h" 19 #include "machine/reg.h" 20 #include "machine/pte.h" 21 #include "machine/segments.h" 22 #include "machine/frame.h" 23 24 #include "param.h" 25 #include "systm.h" 26 #include "user.h" 27 #include "proc.h" 28 #include "seg.h" 29 #include "acct.h" 30 #include "kernel.h" 31 #include "vm.h" 32 #include "cmap.h" 33 #ifdef KTRACE 34 #include "ktrace.h" 35 #endif 36 37 #include "machine/trap.h" 38 39 #define USER 0x40 /* user-mode flag added to type */ 40 #define FRMTRAP 0x100 /* distinguish trap from syscall */ 41 42 struct sysent sysent[]; 43 int nsysent; 44 #include "dbg.h" 45 /* 46 * Called from the trap handler when a processor trap occurs. 47 */ 48 unsigned rcr2(), Sysbase; 49 extern short cpl; 50 /*ARGSUSED*/ 51 trap(frame) 52 struct trapframe frame; 53 #define type frame.tf_trapno 54 #define code frame.tf_err 55 #define pc frame.tf_eip 56 { 57 register int *locr0 = ((int *)&frame); 58 register int i; 59 register struct proc *p; 60 struct timeval syst; 61 extern int nofault; 62 int ucode; 63 int oar0; 64 65 #ifdef DEBUG 66 dprintf(DALLTRAPS, "\n%d. trap",u.u_procp->p_pid); 67 dprintf(DALLTRAPS, " pc:%x cs:%x ds:%x eflags:%x isp %x\n", 68 frame.tf_eip, frame.tf_cs, frame.tf_ds, frame.tf_eflags, 69 frame.tf_isp); 70 dprintf(DALLTRAPS, "edi %x esi %x ebp %x ebx %x esp %x\n", 71 frame.tf_edi, frame.tf_esi, frame.tf_ebp, 72 frame.tf_ebx, frame.tf_esp); 73 dprintf(DALLTRAPS, "edx %x ecx %x eax %x\n", 74 frame.tf_edx, frame.tf_ecx, frame.tf_eax); 75 p=u.u_procp; 76 dprintf(DALLTRAPS, "sig %x %x %x \n", 77 p->p_sigignore, p->p_sigcatch, p->p_sigmask); 78 dprintf(DALLTRAPS, " ec %x type %x cpl %x ", 79 frame.tf_err&0xffff, frame.tf_trapno, cpl); 80 #endif 81 82 locr0[tEFLAGS] &= ~PSL_NT; /* clear nested trap XXX */ 83 if(nofault && frame.tf_trapno != 0xc) 84 { locr0[tEIP] = nofault; return;} 85 86 syst = u.u_ru.ru_stime; 87 oar0= u.u_ar0; 88 if (ISPL(locr0[tCS]) == SEL_UPL) { 89 type |= USER; 90 u.u_ar0 = locr0; 91 } 92 ucode=0; 93 switch (type) { 94 95 default: 96 bit_sucker: 97 #ifdef KDB 98 if (kdb_trap(&psl)) 99 return; 100 #endif 101 102 splhigh(); 103 printf("cr2 %x cpl %x ", rcr2(), cpl); 104 printf("trap type %d, code = %x, pc = %x cs = %x, eflags = %x\n", type, code, pc, frame.tf_cs, frame.tf_eflags); 105 type &= ~USER; 106 pg("panic"); 107 panic("trap"); 108 /*NOTREACHED*/ 109 110 case T_SEGNPFLT + USER: 111 case T_PROTFLT + USER: /* protection fault */ 112 ucode = code + BUS_SEGM_FAULT ; 113 i = SIGBUS; 114 break; 115 116 case T_PRIVINFLT + USER: /* privileged instruction fault */ 117 case T_RESADFLT + USER: /* reserved addressing fault */ 118 case T_RESOPFLT + USER: /* reserved operand fault */ 119 case T_FPOPFLT + USER: /* coprocessor operand fault */ 120 ucode = type &~ USER; 121 i = SIGILL; 122 break; 123 124 case T_ASTFLT + USER: /* Allow process switch */ 125 case T_ASTFLT: 126 astoff(); 127 if ((u.u_procp->p_flag & SOWEUPC) && u.u_prof.pr_scale) { 128 addupc(pc, &u.u_prof, 1); 129 u.u_procp->p_flag &= ~SOWEUPC; 130 } 131 goto out; 132 133 case T_DNA + USER: 134 #ifdef NPX 135 if (npxdna()) return; 136 #endif 137 ucode = FPE_FPU_NP_TRAP; 138 i = SIGFPE; 139 break; 140 141 case T_BOUND + USER: 142 ucode = FPE_SUBRNG_TRAP; 143 i = SIGFPE; 144 break; 145 146 case T_OFLOW + USER: 147 ucode = FPE_INTOVF_TRAP; 148 i = SIGFPE; 149 break; 150 151 case T_DIVIDE + USER: 152 ucode = FPE_INTDIV_TRAP; 153 i = SIGFPE; 154 break; 155 156 case T_ARITHTRAP + USER: 157 ucode = code; 158 i = SIGFPE; 159 break; 160 161 #ifdef notdef 162 /* 163 * If the user SP is above the stack segment, 164 * grow the stack automatically. 165 */ 166 case T_STKFLT + USER: 167 case T_SEGFLT + USER: 168 if (grow((unsigned)locr0[tESP]) /*|| grow(code)*/) 169 goto out; 170 ucode = code; 171 i = SIGSEGV; 172 break; 173 174 case T_TABLEFLT: /* allow page table faults in kernel */ 175 case T_TABLEFLT + USER: /* page table fault */ 176 panic("ptable fault"); 177 #endif 178 179 case T_PAGEFLT: /* allow page faults in kernel mode */ 180 if (code & PGEX_P) goto bit_sucker; 181 /* fall into */ 182 case T_PAGEFLT + USER: /* page fault */ 183 { register u_int vp; 184 u_int ea; 185 186 #ifdef DEBUG 187 dprintf(DPAGIN|DALLTRAPS, "pf code %x pc %x usp %x cr2 %x |", 188 code, frame.tf_eip, frame.tf_esp, rcr2()); 189 #endif 190 ea = (u_int)rcr2(); 191 192 /* out of bounds reference */ 193 if (ea >= (u_int)&Sysbase || code & PGEX_P) { 194 ucode = code + BUS_PAGE_FAULT; 195 i = SIGBUS; 196 break; 197 } 198 199 /* stack reference to the running process? */ 200 vp = btop(ea); 201 if (vp >= dptov(u.u_procp, u.u_procp->p_dsize) 202 && vp < sptov(u.u_procp, u.u_procp->p_ssize-1)){ 203 /* attempt to grow stack */ 204 if (grow((unsigned)locr0[tESP]) || grow(ea)) { 205 if (type == T_PAGEFLT) 206 { 207 u.u_ar0 = oar0; 208 return; 209 } 210 goto out; 211 } else if (nofault) { 212 u.u_ar0 = oar0; 213 locr0[tEIP] = nofault; 214 return; 215 } 216 i = SIGSEGV; 217 ucode = code + BUS_PAGE_FAULT; 218 break; 219 } 220 221 pagein(ea, 0, code); 222 if (type == T_PAGEFLT) return; 223 goto out; 224 } 225 226 case T_TRCTRAP: /* trace trap -- someone single stepping lcall's */ 227 locr0[tEFLAGS] &= ~PSL_T; 228 /* Q: how do we turn it on again? */ 229 u.u_ar0 = oar0; 230 return; 231 232 case T_BPTFLT + USER: /* bpt instruction fault */ 233 case T_TRCTRAP + USER: /* trace trap */ 234 locr0[tEFLAGS] &= ~PSL_T; 235 i = SIGTRAP; 236 break; 237 238 #ifdef notdef 239 /* 240 * For T_KSPNOTVAL and T_BUSERR, can not allow spl to 241 * drop to 0 as clock could go off and we would end up 242 * doing an rei to the interrupt stack at ipl 0 (a 243 * reserved operand fault). Instead, we allow psignal 244 * to post an ast, then return to user mode where we 245 * will reenter the kernel on the kernel's stack and 246 * can then service the signal. 247 */ 248 case T_KSPNOTVAL: 249 if (noproc) 250 panic("ksp not valid"); 251 /* fall thru... */ 252 case T_KSPNOTVAL + USER: 253 printf("pid %d: ksp not valid\n", u.u_procp->p_pid); 254 /* must insure valid kernel stack pointer? */ 255 trapsignal(SIGKILL,0|FRMTRAP); 256 u.u_ar0 = oar0; 257 return; 258 259 case T_BUSERR + USER: 260 trapsignal(SIGBUS, code|FRMTRAP); 261 u.u_ar0 = oar0; 262 return; 263 #endif 264 265 #include "isa.h" 266 #if NISA > 0 267 case T_NMI: 268 case T_NMI + USER: 269 if(isa_nmi(code) == 0) return; 270 else goto bit_sucker; 271 #endif 272 } 273 trapsignal(i, ucode|FRMTRAP); 274 if ((type & USER) == 0) 275 { 276 u.u_ar0 = oar0; 277 return; 278 } 279 out: 280 p = u.u_procp; 281 if (i = CURSIG(p)) 282 psig(i,FRMTRAP); 283 p->p_pri = p->p_usrpri; 284 if (runrun) { 285 /* 286 * Since we are u.u_procp, clock will normally just change 287 * our priority without moving us from one queue to another 288 * (since the running process is not on a queue.) 289 * If that happened after we setrq ourselves but before we 290 * swtch()'ed, we might not be on the queue indicated by 291 * our priority. 292 */ 293 (void) splclock(); 294 setrq(p); 295 u.u_ru.ru_nivcsw++; 296 swtch(); 297 if (i = CURSIG(p)) 298 psig(i,FRMTRAP); 299 } 300 if (u.u_prof.pr_scale) { 301 int ticks; 302 struct timeval *tv = &u.u_ru.ru_stime; 303 304 ticks = ((tv->tv_sec - syst.tv_sec) * 1000 + 305 (tv->tv_usec - syst.tv_usec) / 1000) / (tick / 1000); 306 if (ticks) 307 addupc(pc, &u.u_prof, ticks); 308 } 309 curpri = p->p_pri; 310 u.u_ar0 = oar0; 311 #undef type 312 #undef code 313 #undef pc 314 } 315 316 /* 317 * Called from locore when a system call occurs 318 */ 319 /*ARGSUSED*/ 320 syscall(frame) 321 struct syscframe frame; 322 #define code frame.sf_eax /* note: written over! */ 323 #define pc frame.sf_eip 324 { 325 register int *locr0 = ((int *)&frame)/*-PS*/; 326 register caddr_t params; 327 register int i; 328 register struct sysent *callp; 329 register struct proc *p; 330 struct timeval syst; 331 int error, opc; 332 int args[8], rval[2]; 333 334 #ifdef lint 335 r0 = 0; r0 = r0; r1 = 0; r1 = r1; 336 #endif 337 syst = u.u_ru.ru_stime; 338 p = u.u_procp; 339 if (ISPL(locr0[sCS]) != SEL_UPL) 340 { 341 printf("\npc:%x cs:%x eflags:%x\n", 342 frame.sf_eip, frame.sf_cs, frame.sf_eflags); 343 printf("edi %x esi %x ebp %x ebx %x esp %x\n", 344 frame.sf_edi, frame.sf_esi, frame.sf_ebp, 345 frame.sf_ebx, frame.sf_esp); 346 printf("edx %x ecx %x eax %x\n", frame.sf_edx, frame.sf_ecx, frame.sf_eax); 347 printf("cr0 %x cr2 %x cpl %x \n", rcr0(), rcr2(), cpl); 348 panic("syscall"); 349 } 350 u.u_ar0 = locr0; 351 params = (caddr_t)locr0[sESP] + NBPW ; 352 353 /* 354 * Reconstruct pc, assuming lcall $X,y is 7 bytes, as it is always. 355 */ 356 opc = pc - 7; 357 callp = (code >= nsysent) ? &sysent[63] : &sysent[code]; 358 if (callp == sysent) { 359 i = fuword(params); 360 params += NBPW; 361 callp = (code >= nsysent) ? &sysent[63] : &sysent[code]; 362 } 363 /*dprintf(DALLSYSC,"%d. call %d ", p->p_pid, code);*/ 364 if ((i = callp->sy_narg * sizeof (int)) && 365 (error = copyin(params, (caddr_t)args, (u_int)i))) { 366 locr0[sEAX] = (u_char) error; 367 locr0[sEFLAGS] |= PSL_C; /* carry bit */ 368 #ifdef KTRACE 369 if (KTRPOINT(p, KTR_SYSCALL)) 370 ktrsyscall(p->p_tracep, code, callp->sy_narg, &args); 371 #endif 372 goto done; 373 } 374 #ifdef KTRACE 375 if (KTRPOINT(p, KTR_SYSCALL)) 376 ktrsyscall(p->p_tracep, code, callp->sy_narg, &args); 377 #endif 378 rval[0] = 0; 379 rval[1] = locr0[sEDX]; 380 error = (*callp->sy_call)(p, args, rval); 381 if (error == ERESTART) 382 pc = opc; 383 else if (error != EJUSTRETURN) { 384 if (error) { 385 locr0[sEAX] = (u_char) error; 386 locr0[sEFLAGS] |= PSL_C; /* carry bit */ 387 } else { 388 locr0[sEAX] = rval[0]; 389 locr0[sEDX] = rval[1]; 390 locr0[sEFLAGS] &= ~PSL_C; /* carry bit */ 391 } 392 } 393 /* else if (error == EJUSTRETURN) */ 394 /* nothing to do */ 395 done: 396 /* 397 * Reinitialize proc pointer `p' as it may be different 398 * if this is a child returning from fork syscall. 399 */ 400 p = u.u_procp; 401 /* 402 * XXX the check for sigreturn ensures that we don't 403 * attempt to set up a call to a signal handler (sendsig) before 404 * we have cleaned up the stack from the last call (sigreturn). 405 * Allowing this seems to lock up the machine in certain scenarios. 406 * What should really be done is to clean up the signal handling 407 * so that this is not a problem. 408 */ 409 #include "syscall.h" 410 if (code != SYS_sigreturn && (i = CURSIG(p))) 411 psig(i,0); 412 p->p_pri = p->p_usrpri; 413 if (runrun) { 414 /* 415 * Since we are u.u_procp, clock will normally just change 416 * our priority without moving us from one queue to another 417 * (since the running process is not on a queue.) 418 * If that happened after we setrq ourselves but before we 419 * swtch()'ed, we might not be on the queue indicated by 420 * our priority. 421 */ 422 (void) splclock(); 423 setrq(p); 424 u.u_ru.ru_nivcsw++; 425 swtch(); 426 if (code != SYS_sigreturn && (i = CURSIG(p))) 427 psig(i,0); 428 } 429 if (u.u_prof.pr_scale) { 430 int ticks; 431 struct timeval *tv = &u.u_ru.ru_stime; 432 433 ticks = ((tv->tv_sec - syst.tv_sec) * 1000 + 434 (tv->tv_usec - syst.tv_usec) / 1000) / (tick / 1000); 435 if (ticks) { 436 #ifdef PROFTIMER 437 extern int profscale; 438 addupc(pc, &u.u_prof, ticks * profscale); 439 #else 440 addupc(pc, &u.u_prof, ticks); 441 #endif 442 } 443 } 444 curpri = p->p_pri; 445 #ifdef KTRACE 446 if (KTRPOINT(p, KTR_SYSRET)) 447 ktrsysret(p->p_tracep, code, error, rval[0]); 448 #endif 449 } 450 451 #ifdef notdef 452 /* 453 * nonexistent system call-- signal process (may want to handle it) 454 * flag error if process won't see signal immediately 455 * Q: should we do that all the time ?? 456 */ 457 nosys() 458 { 459 460 if (u.u_signal[SIGSYS] == SIG_IGN || u.u_signal[SIGSYS] == SIG_HOLD) 461 u.u_error = EINVAL; 462 psignal(u.u_procp, SIGSYS); 463 } 464 #endif 465 466 /* 467 * Ignored system call 468 */ 469 nullsys() 470 { 471 472 } 473