1 /* 2 * Copyright (c) 1988 University of Utah. 3 * Copyright (c) 1992 OMRON Corporation. 4 * Copyright (c) 1982, 1986, 1990 The Regents of the University of California. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * the Systems Programming Group of the University of Utah Computer 9 * Science Department. 10 * 11 * %sccs.include.redist.c% 12 * 13 * from: Utah $Hdr: trap.c 1.35 91/12/26$ 14 * from: hp300/hp300/trap.c 7.26 (Berkeley) 12/27/92 15 * 16 * @(#)trap.c 7.4 (Berkeley) 01/02/93 17 */ 18 19 #include <sys/param.h> 20 #include <sys/systm.h> 21 #include <sys/proc.h> 22 #include <sys/acct.h> 23 #include <sys/kernel.h> 24 #include <sys/signalvar.h> 25 #include <sys/resourcevar.h> 26 #include <sys/syscall.h> 27 #include <sys/syslog.h> 28 #include <sys/user.h> 29 #ifdef KTRACE 30 #include <sys/ktrace.h> 31 #endif 32 33 #include <machine/psl.h> 34 #include <machine/trap.h> 35 #include <machine/cpu.h> 36 #include <machine/reg.h> 37 #include <machine/mtpr.h> 38 39 #include <vm/vm.h> 40 #include <vm/pmap.h> 41 42 struct sysent sysent[]; 43 int nsysent; 44 45 char *trap_type[] = { 46 "Bus error", 47 "Address error", 48 "Illegal instruction", 49 "Zero divide", 50 "CHK instruction", 51 "TRAPV instruction", 52 "Privilege violation", 53 "Trace trap", 54 "MMU fault", 55 "SSIR trap", 56 "Format error", 57 "68881 exception", 58 "Coprocessor violation", 59 "Async system trap" 60 }; 61 #define TRAP_TYPES (sizeof trap_type / sizeof trap_type[0]) 62 63 /* 64 * Size of various exception stack frames (minus the standard 8 bytes) 65 */ 66 short exframesize[] = { 67 FMT0SIZE, /* type 0 - normal (68020/030/040) */ 68 FMT1SIZE, /* type 1 - throwaway (68020/030/040) */ 69 FMT2SIZE, /* type 2 - normal 6-word (68020/030/040) */ 70 FMT3SIZE, /* type 3 - FP post-instruction (68040) */ 71 -1, -1, -1, /* type 4-6 - undefined */ 72 FMT7SIZE, /* type 7 - access error (68040) */ 73 58, /* type 8 - bus fault (68010) */ 74 FMT9SIZE, /* type 9 - coprocessor mid-instruction (68020/030) */ 75 FMTASIZE, /* type A - short bus fault (68020/030) */ 76 FMTBSIZE, /* type B - long bus fault (68020/030) */ 77 -1, -1, -1, -1 /* type C-F - undefined */ 78 }; 79 80 #define KDFAULT(c) (((c) & (SSW_DF|SSW_FCMASK)) == (SSW_DF|FC_SUPERD)) 81 #define WRFAULT(c) (((c) & (SSW_DF|SSW_RW)) == SSW_DF) 82 83 #ifdef DEBUG 84 int mmudebug = 0; 85 int mmupid = -1; 86 #define MDB_FOLLOW 1 87 #define MDB_WBFOLLOW 2 88 #define MDB_WBFAILED 4 89 #define MDB_ISPID(p) (p) == mmupid 90 #endif 91 92 /* 93 * trap and syscall both need the following work done before returning 94 * to user mode. 95 */ 96 static inline void 97 userret(p, fp, oticks, faultaddr, fromtrap) 98 register struct proc *p; 99 register struct frame *fp; 100 u_quad_t oticks; 101 u_int faultaddr; 102 int fromtrap; 103 { 104 int sig, s; 105 106 /* take pending signals */ 107 while ((sig = CURSIG(p)) != 0) 108 psig(sig); 109 p->p_pri = p->p_usrpri; 110 if (want_resched) { 111 /* 112 * Since we are curproc, clock will normally just change 113 * our priority without moving us from one queue to another 114 * (since the running process is not on a queue.) 115 * If that happened after we setrq ourselves but before we 116 * swtch()'ed, we might not be on the queue indicated by 117 * our priority. 118 */ 119 s = splstatclock(); 120 setrq(p); 121 p->p_stats->p_ru.ru_nivcsw++; 122 swtch(); 123 splx(s); 124 while ((sig = CURSIG(p)) != 0) 125 psig(sig); 126 } 127 128 /* 129 * If profiling, charge system time to the trapped pc. 130 */ 131 if (p->p_flag & SPROFIL) { 132 extern int psratio; 133 134 addupc_task(p, fp->f_pc, 135 (int)(p->p_sticks - oticks) * psratio); 136 } 137 curpri = p->p_pri; 138 } 139 140 /* 141 * Trap is called from locore to handle most types of processor traps, 142 * including events such as simulated software interrupts/AST's. 143 * System calls are broken out for efficiency. 144 */ 145 /*ARGSUSED*/ 146 trap(type, code, v, frame) 147 int type; 148 unsigned code; 149 register unsigned v; 150 struct frame frame; 151 { 152 register int i; 153 unsigned ucode; 154 register struct proc *p; 155 u_quad_t sticks; 156 unsigned ncode; 157 extern char fswintr[]; 158 159 cnt.v_trap++; 160 p = curproc; 161 ucode = 0; 162 if (USERMODE(frame.f_sr)) { 163 type |= T_USER; 164 sticks = p->p_sticks; 165 p->p_md.md_regs = frame.f_regs; 166 } 167 switch (type) { 168 169 default: 170 dopanic: 171 printf("trap type %d, code = %x, v = %x\n", type, code, v); 172 regdump(&frame, 128); 173 type &= ~T_USER; 174 if ((unsigned)type < TRAP_TYPES) 175 panic(trap_type[type]); 176 panic("trap"); 177 178 case T_BUSERR: /* kernel bus error */ 179 if (!p->p_addr->u_pcb.pcb_onfault) 180 goto dopanic; 181 /* 182 * If we have arranged to catch this fault in any of the 183 * copy to/from user space routines, set PC to return to 184 * indicated location and set flag informing buserror code 185 * that it may need to clean up stack frame. 186 */ 187 copyfault: 188 frame.f_stackadj = exframesize[frame.f_format]; 189 frame.f_format = frame.f_vector = 0; 190 frame.f_pc = (int) p->p_addr->u_pcb.pcb_onfault; 191 return; 192 193 case T_BUSERR|T_USER: /* bus error */ 194 case T_ADDRERR|T_USER: /* address error */ 195 ucode = v; 196 i = SIGBUS; 197 break; 198 199 #ifdef FPCOPROC 200 case T_COPERR: /* kernel coprocessor violation */ 201 #endif 202 case T_FMTERR|T_USER: /* do all RTE errors come in as T_USER? */ 203 case T_FMTERR: /* ...just in case... */ 204 /* 205 * The user has most likely trashed the RTE or FP state info 206 * in the stack frame of a signal handler. 207 */ 208 type |= T_USER; 209 printf("pid %d: kernel %s exception\n", p->p_pid, 210 type==T_COPERR ? "coprocessor" : "format"); 211 p->p_sigacts->ps_sigact[SIGILL] = SIG_DFL; 212 i = sigmask(SIGILL); 213 p->p_sigignore &= ~i; 214 p->p_sigcatch &= ~i; 215 p->p_sigmask &= ~i; 216 i = SIGILL; 217 ucode = frame.f_format; /* XXX was ILL_RESAD_FAULT */ 218 break; 219 220 #ifdef FPCOPROC 221 case T_COPERR|T_USER: /* user coprocessor violation */ 222 /* What is a proper response here? */ 223 ucode = 0; 224 i = SIGFPE; 225 break; 226 227 case T_FPERR|T_USER: /* 68881 exceptions */ 228 /* 229 * We pass along the 68881 status register which locore stashed 230 * in code for us. Note that there is a possibility that the 231 * bit pattern of this register will conflict with one of the 232 * FPE_* codes defined in signal.h. Fortunately for us, the 233 * only such codes we use are all in the range 1-7 and the low 234 * 3 bits of the status register are defined as 0 so there is 235 * no clash. 236 */ 237 ucode = code; 238 i = SIGFPE; 239 break; 240 #endif 241 242 case T_ILLINST|T_USER: /* illegal instruction fault */ 243 case T_PRIVINST|T_USER: /* privileged instruction fault */ 244 ucode = frame.f_format; /* XXX was ILL_PRIVIN_FAULT */ 245 i = SIGILL; 246 break; 247 248 case T_ZERODIV|T_USER: /* Divide by zero */ 249 ucode = frame.f_format; /* XXX was FPE_INTDIV_TRAP */ 250 i = SIGFPE; 251 break; 252 253 case T_CHKINST|T_USER: /* CHK instruction trap */ 254 ucode = frame.f_format; /* XXX was FPE_SUBRNG_TRAP */ 255 i = SIGFPE; 256 break; 257 258 case T_TRAPVINST|T_USER: /* TRAPV instruction trap */ 259 ucode = frame.f_format; /* XXX was FPE_INTOVF_TRAP */ 260 i = SIGFPE; 261 break; 262 263 /* 264 * XXX: Trace traps are a nightmare. 265 * 266 * HP-UX uses trap #1 for breakpoints, 267 * HPBSD uses trap #2, 268 * SUN 3.x uses trap #15, 269 * KGDB uses trap #15 (for kernel breakpoints; handled elsewhere). 270 * 271 * HPBSD and HP-UX traps both get mapped by locore.s into T_TRACE. 272 * SUN 3.x traps get passed through as T_TRAP15 and are not really 273 * supported yet. 274 */ 275 case T_TRACE: /* kernel trace trap */ 276 case T_TRAP15: /* SUN trace trap */ 277 frame.f_sr &= ~PSL_T; 278 i = SIGTRAP; 279 break; 280 281 case T_TRACE|T_USER: /* user trace trap */ 282 case T_TRAP15|T_USER: /* SUN user trace trap */ 283 frame.f_sr &= ~PSL_T; 284 i = SIGTRAP; 285 break; 286 287 case T_ASTFLT: /* system async trap, cannot happen */ 288 goto dopanic; 289 290 case T_ASTFLT|T_USER: /* user async trap */ 291 astpending = 0; 292 /* 293 * We check for software interrupts first. This is because 294 * they are at a higher level than ASTs, and on a VAX would 295 * interrupt the AST. We assume that if we are processing 296 * an AST that we must be at IPL0 so we don't bother to 297 * check. Note that we ensure that we are at least at SIR 298 * IPL while processing the SIR. 299 */ 300 spl1(); 301 /* fall into... */ 302 303 case T_SSIR: /* software interrupt */ 304 case T_SSIR|T_USER: 305 if (ssir & SIR_NET) { 306 siroff(SIR_NET); 307 cnt.v_soft++; 308 netintr(); 309 } 310 if (ssir & SIR_CLOCK) { 311 siroff(SIR_CLOCK); 312 cnt.v_soft++; 313 softclock(); 314 } 315 /* 316 * If this was not an AST trap, we are all done. 317 */ 318 if (type != (T_ASTFLT|T_USER)) { 319 cnt.v_trap--; 320 return; 321 } 322 spl0(); 323 if (p->p_flag & SOWEUPC) { 324 p->p_flag &= ~SOWEUPC; 325 ADDUPROF(p); 326 } 327 goto out; 328 329 case T_MMUFLT: /* kernel mode page fault */ 330 /* 331 * If we were doing profiling ticks or other user mode 332 * stuff from interrupt code, Just Say No. 333 */ 334 if (p->p_addr->u_pcb.pcb_onfault == fswintr) 335 goto copyfault; 336 /* fall into ... */ 337 338 case T_MMUFLT|T_USER: /* page fault */ 339 { 340 register vm_offset_t va; 341 register struct vmspace *vm = p->p_vmspace; 342 register vm_map_t map; 343 int rv; 344 vm_prot_t ftype; 345 extern vm_map_t kernel_map; 346 347 #ifdef DEBUG 348 if ((mmudebug & MDB_WBFOLLOW) || MDB_ISPID(p->p_pid)) 349 printf("trap: T_MMUFLT pid=%d, code=%x, v=%x, pc=%x, sr=%x\n", 350 p->p_pid, code, v, frame.f_pc, frame.f_sr); 351 #endif 352 /* 353 * It is only a kernel address space fault iff: 354 * 1. (type & T_USER) == 0 and 355 * 2. pcb_onfault not set or 356 * 3. pcb_onfault set but supervisor space data fault 357 * The last can occur during an exec() copyin where the 358 * argument space is lazy-allocated. 359 */ 360 if (type == T_MMUFLT && 361 (!p->p_addr->u_pcb.pcb_onfault || KDFAULT(code))) 362 map = kernel_map; 363 else 364 map = &vm->vm_map; 365 if (WRFAULT(code)) 366 ftype = VM_PROT_READ | VM_PROT_WRITE; 367 else 368 ftype = VM_PROT_READ; 369 va = trunc_page((vm_offset_t)v); 370 #ifdef DEBUG 371 if (map == kernel_map && va == 0) { 372 printf("trap: bad kernel access at %x\n", v); 373 goto dopanic; 374 } 375 #endif 376 rv = vm_fault(map, va, ftype, FALSE); 377 #ifdef DEBUG 378 if (rv && MDB_ISPID(p->p_pid)) 379 printf("vm_fault(%x, %x, %x, 0) -> %x\n", 380 map, va, ftype, rv); 381 #endif 382 /* 383 * If this was a stack access we keep track of the maximum 384 * accessed stack size. Also, if vm_fault gets a protection 385 * failure it is due to accessing the stack region outside 386 * the current limit and we need to reflect that as an access 387 * error. 388 */ 389 if ((caddr_t)va >= vm->vm_maxsaddr && map != kernel_map) { 390 if (rv == KERN_SUCCESS) { 391 unsigned nss; 392 393 nss = clrnd(btoc(USRSTACK-(unsigned)va)); 394 if (nss > vm->vm_ssize) 395 vm->vm_ssize = nss; 396 } else if (rv == KERN_PROTECTION_FAILURE) 397 rv = KERN_INVALID_ADDRESS; 398 } 399 if (rv == KERN_SUCCESS) { 400 if (type == T_MMUFLT) { 401 return; 402 } 403 goto out; 404 } 405 if (type == T_MMUFLT) { 406 if (p->p_addr->u_pcb.pcb_onfault) 407 goto copyfault; 408 printf("vm_fault(%x, %x, %x, 0) -> %x\n", 409 map, va, ftype, rv); 410 printf(" type %x, code [mmu,,ssw]: %x\n", 411 type, code); 412 goto dopanic; 413 } 414 ucode = v; 415 i = (rv == KERN_PROTECTION_FAILURE) ? SIGBUS : SIGSEGV; 416 break; 417 } 418 } 419 trapsignal(p, i, ucode); 420 if ((type & T_USER) == 0) 421 return; 422 out: 423 userret(p, &frame, sticks, v, 1); 424 } 425 426 /* 427 * Proces a system call. 428 */ 429 syscall(code, frame) 430 u_int code; 431 struct frame frame; 432 { 433 register caddr_t params; 434 register struct sysent *callp; 435 register struct proc *p; 436 int error, opc, numsys, s; 437 u_int argsize; 438 struct args { 439 int i[8]; 440 } args; 441 int rval[2]; 442 u_quad_t sticks; 443 444 cnt.v_syscall++; 445 if (!USERMODE(frame.f_sr)) 446 panic("syscall"); 447 p = curproc; 448 sticks = p->p_sticks; 449 p->p_md.md_regs = frame.f_regs; 450 opc = frame.f_pc - 2; 451 callp = sysent, numsys = nsysent; 452 params = (caddr_t)frame.f_regs[SP] + sizeof(int); 453 switch (code) { 454 455 case SYS_indir: 456 /* 457 * Code is first argument, followed by actual args. 458 */ 459 code = fuword(params); 460 params += sizeof(int); 461 /* 462 * XXX sigreturn requires special stack manipulation 463 * that is only done if entered via the sigreturn 464 * trap. Cannot allow it here so make sure we fail. 465 */ 466 if (code == SYS_sigreturn) 467 code = numsys; 468 break; 469 470 case SYS___indir: 471 /* 472 * Like indir, but code is a quad, so as to maintain 473 * quad alignment for the rest of the arguments. 474 */ 475 code = fuword(params + _QUAD_LOWWORD * sizeof(int)); 476 params += sizeof(quad_t); 477 break; 478 479 default: 480 /* nothing to do by default */ 481 break; 482 } 483 if (code < numsys) 484 callp += code; 485 else 486 callp += SYS_indir; /* => nosys */ 487 argsize = callp->sy_narg * sizeof(int); 488 if (argsize && (error = copyin(params, (caddr_t)&args, argsize))) { 489 #ifdef KTRACE 490 if (KTRPOINT(p, KTR_SYSCALL)) 491 ktrsyscall(p->p_tracep, code, callp->sy_narg, args.i); 492 #endif 493 goto bad; 494 } 495 #ifdef KTRACE 496 if (KTRPOINT(p, KTR_SYSCALL)) 497 ktrsyscall(p->p_tracep, code, callp->sy_narg, args.i); 498 #endif 499 rval[0] = 0; 500 rval[1] = frame.f_regs[D1]; 501 error = (*callp->sy_call)(p, &args, rval); 502 switch (error) { 503 504 case 0: 505 /* 506 * Reinitialize proc pointer `p' as it may be different 507 * if this is a child returning from fork syscall. 508 */ 509 p = curproc; 510 frame.f_regs[D0] = rval[0]; 511 frame.f_regs[D1] = rval[1]; 512 frame.f_sr &= ~PSL_C; 513 break; 514 515 case ERESTART: 516 frame.f_pc = opc; 517 break; 518 519 case EJUSTRETURN: 520 break; /* nothing to do */ 521 522 default: 523 bad: 524 frame.f_regs[D0] = error; 525 frame.f_sr |= PSL_C; 526 break; 527 } 528 529 userret(p, &frame, sticks, (u_int)0, 0); 530 #ifdef KTRACE 531 if (KTRPOINT(p, KTR_SYSRET)) 532 ktrsysret(p->p_tracep, code, error, rval[0]); 533 #endif 534 } 535