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