1 /* $NetBSD: trap.c,v 1.91 2004/01/02 18:52:17 cl Exp $ */ 2 3 /* 4 * Copyright (c) 1994 Ludd, University of Lule}, Sweden. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed at Ludd, University of Lule}. 18 * 4. The name of the author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 /* All bugs are subject to removal without further notice */ 34 35 #include <sys/cdefs.h> 36 __KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.91 2004/01/02 18:52:17 cl Exp $"); 37 38 #include "opt_ddb.h" 39 #include "opt_ktrace.h" 40 #include "opt_systrace.h" 41 #include "opt_multiprocessor.h" 42 43 #include <sys/types.h> 44 #include <sys/param.h> 45 #include <sys/proc.h> 46 #include <sys/user.h> 47 #include <sys/syscall.h> 48 #include <sys/systm.h> 49 #include <sys/signalvar.h> 50 #include <sys/exec.h> 51 #include <sys/sa.h> 52 #include <sys/savar.h> 53 #include <sys/pool.h> 54 55 #include <uvm/uvm_extern.h> 56 57 #include <machine/mtpr.h> 58 #include <machine/pte.h> 59 #include <machine/pcb.h> 60 #include <machine/trap.h> 61 #include <machine/pmap.h> 62 #include <machine/cpu.h> 63 64 #ifdef DDB 65 #include <machine/db_machdep.h> 66 #endif 67 #include <kern/syscalls.c> 68 #ifdef KTRACE 69 #include <sys/ktrace.h> 70 #endif 71 #ifdef SYSTRACE 72 #include <sys/systrace.h> 73 #endif 74 75 #ifdef TRAPDEBUG 76 volatile int startsysc = 0, faultdebug = 0; 77 #endif 78 79 int cpu_printfataltraps = 0; 80 81 static __inline void userret (struct lwp *, struct trapframe *, u_quad_t); 82 83 void trap (struct trapframe *); 84 void syscall (struct trapframe *); 85 86 const char * const traptypes[]={ 87 "reserved addressing", 88 "privileged instruction", 89 "reserved operand", 90 "breakpoint instruction", 91 "XFC instruction", 92 "system call ", 93 "arithmetic trap", 94 "asynchronous system trap", 95 "page table length fault", 96 "translation violation fault", 97 "trace trap", 98 "compatibility mode fault", 99 "access violation fault", 100 "", 101 "", 102 "KSP invalid", 103 "", 104 "kernel debugger trap" 105 }; 106 int no_traps = 18; 107 108 #define USERMODE(framep) ((((framep)->psl) & (PSL_U)) == PSL_U) 109 #define FAULTCHK \ 110 if (l->l_addr->u_pcb.iftrap) { \ 111 frame->pc = (unsigned)l->l_addr->u_pcb.iftrap; \ 112 frame->psl &= ~PSL_FPD; \ 113 frame->r0 = EFAULT;/* for copyin/out */ \ 114 frame->r1 = -1; /* for fetch/store */ \ 115 return; \ 116 } 117 118 /* 119 * userret: 120 * 121 * Common code used by various execption handlers to 122 * return to usermode. 123 */ 124 static __inline void 125 userret(struct lwp *l, struct trapframe *frame, u_quad_t oticks) 126 { 127 int sig; 128 struct proc *p = l->l_proc; 129 130 /* Generate UNBLOCKED upcall. */ 131 if (l->l_flag & L_SA_BLOCKING) 132 sa_unblock_userret(l); 133 134 /* Take pending signals. */ 135 while ((sig = CURSIG(l)) != 0) 136 postsig(sig); 137 l->l_priority = l->l_usrpri; 138 if (curcpu()->ci_want_resched) { 139 /* 140 * We are being preempted. 141 */ 142 preempt(0); 143 while ((sig = CURSIG(l)) != 0) 144 postsig(sig); 145 } 146 147 /* Invoke per-process kernel-exit handling, if any */ 148 if (p->p_userret) 149 (p->p_userret)(l, p->p_userret_arg); 150 151 /* 152 * If profiling, charge system time to the trapped pc. 153 */ 154 if (p->p_flag & P_PROFIL) { 155 extern int psratio; 156 157 addupc_task(p, frame->pc, 158 (int)(p->p_sticks - oticks) * psratio); 159 } 160 /* Invoke any pending upcalls. */ 161 if (l->l_flag & L_SA_UPCALL) 162 sa_upcall_userret(l); 163 164 curcpu()->ci_schedstate.spc_curpriority = l->l_priority; 165 } 166 167 void 168 trap(struct trapframe *frame) 169 { 170 u_int sig = 0, type = frame->trap, trapsig = 1, code = 0; 171 u_int rv, addr, umode; 172 struct lwp *l; 173 struct proc *p = NULL; 174 u_quad_t oticks = 0; 175 struct vmspace *vm; 176 struct vm_map *map; 177 vm_prot_t ftype; 178 vsize_t nss; 179 180 if ((l = curlwp) != NULL) 181 p = l->l_proc; 182 uvmexp.traps++; 183 if ((umode = USERMODE(frame))) { 184 type |= T_USER; 185 oticks = p->p_sticks; 186 l->l_addr->u_pcb.framep = frame; 187 } 188 189 type&=~(T_WRITE|T_PTEFETCH); 190 191 192 #ifdef TRAPDEBUG 193 if(frame->trap==7) goto fram; 194 if(faultdebug)printf("Trap: type %lx, code %lx, pc %lx, psl %lx\n", 195 frame->trap, frame->code, frame->pc, frame->psl); 196 fram: 197 #endif 198 switch(type){ 199 200 default: 201 #ifdef DDB 202 kdb_trap(frame); 203 #endif 204 printf("Trap: type %x, code %x, pc %x, psl %x\n", 205 (u_int)frame->trap, (u_int)frame->code, 206 (u_int)frame->pc, (u_int)frame->psl); 207 panic("trap"); 208 209 case T_KSPNOTVAL: 210 panic("kernel stack invalid"); 211 212 case T_TRANSFLT|T_USER: 213 case T_TRANSFLT: 214 /* 215 * BUG! BUG! BUG! BUG! BUG! 216 * Due to a hardware bug (at in least KA65x CPUs) a double 217 * page table fetch trap will cause a translation fault 218 * even if access in the SPT PTE entry specifies 'no access'. 219 * In for example section 6.4.2 in VAX Architecture 220 * Reference Manual it states that if a page both are invalid 221 * and have no access set, a 'access violation fault' occurs. 222 * Therefore, we must fall through here... 223 */ 224 #ifdef nohwbug 225 panic("translation fault"); 226 #endif 227 228 case T_PTELEN|T_USER: /* Page table length exceeded */ 229 case T_ACCFLT|T_USER: 230 if (frame->code < 0) { /* Check for kernel space */ 231 sig = SIGSEGV; 232 code = SEGV_ACCERR; 233 break; 234 } 235 236 case T_PTELEN: 237 case T_ACCFLT: 238 #ifdef TRAPDEBUG 239 if(faultdebug)printf("trap accflt type %lx, code %lx, pc %lx, psl %lx\n", 240 frame->trap, frame->code, frame->pc, frame->psl); 241 #endif 242 #ifdef DIAGNOSTIC 243 if (p == 0) 244 panic("trap: access fault: addr %lx code %lx", 245 frame->pc, frame->code); 246 if (frame->psl & PSL_IS) 247 panic("trap: pflt on IS"); 248 #endif 249 250 /* 251 * Page tables are allocated in pmap_enter(). We get 252 * info from below if it is a page table fault, but 253 * UVM may want to map in pages without faults, so 254 * because we must check for PTE pages anyway we don't 255 * bother doing it here. 256 */ 257 addr = trunc_page(frame->code); 258 if ((umode == 0) && (frame->code < 0)) { 259 vm = NULL; 260 map = kernel_map; 261 } else { 262 vm = p->p_vmspace; 263 map = &vm->vm_map; 264 } 265 266 if (frame->trap & T_WRITE) 267 ftype = VM_PROT_WRITE; 268 else 269 ftype = VM_PROT_READ; 270 271 if (umode) { 272 KERNEL_PROC_LOCK(l); 273 if (l->l_flag & L_SA) { 274 KDASSERT(p != NULL && p->p_sa != NULL); 275 p->p_sa->sa_vp_faultaddr = (vaddr_t)frame->code; 276 l->l_flag |= L_SA_PAGEFAULT; 277 } 278 } else 279 KERNEL_LOCK(LK_CANRECURSE|LK_EXCLUSIVE); 280 281 nss = 0; 282 if (map != kernel_map && 283 (caddr_t)addr >= vm->vm_maxsaddr && 284 (caddr_t)addr < (caddr_t)USRSTACK) { 285 nss = btoc(USRSTACK - addr); 286 if (nss > btoc(p->p_rlimit[RLIMIT_STACK].rlim_cur)) { 287 /* 288 * Set nss to 0, since this case is not 289 * a "stack extension". 290 */ 291 nss = 0; 292 } 293 } 294 295 rv = uvm_fault(map, addr, 0, ftype); 296 if (rv != 0) { 297 if (umode == 0) { 298 KERNEL_UNLOCK(); 299 FAULTCHK; 300 panic("Segv in kernel mode: pc %x addr %x", 301 (u_int)frame->pc, (u_int)frame->code); 302 } 303 code = SEGV_ACCERR; 304 if (rv == ENOMEM) { 305 printf("UVM: pid %d (%s), uid %d killed: " 306 "out of swap\n", 307 p->p_pid, p->p_comm, 308 p->p_cred && p->p_ucred ? 309 p->p_ucred->cr_uid : -1); 310 sig = SIGKILL; 311 } else { 312 sig = SIGSEGV; 313 if (rv != EACCES) 314 code = SEGV_MAPERR; 315 } 316 } else { 317 trapsig = 0; 318 if (nss != 0 && nss > vm->vm_ssize) 319 vm->vm_ssize = nss; 320 } 321 if (umode) { 322 l->l_flag &= ~L_SA_PAGEFAULT; 323 KERNEL_PROC_UNLOCK(l); 324 } else 325 KERNEL_UNLOCK(); 326 break; 327 328 case T_BPTFLT|T_USER: 329 sig = SIGTRAP; 330 code = TRAP_BRKPT; 331 break; 332 case T_TRCTRAP|T_USER: 333 sig = SIGTRAP; 334 code = TRAP_TRACE; 335 frame->psl &= ~PSL_T; 336 break; 337 338 case T_PRIVINFLT|T_USER: 339 sig = SIGILL; 340 code = ILL_PRVOPC; 341 break; 342 case T_RESADFLT|T_USER: 343 sig = SIGILL; 344 code = ILL_ILLADR; 345 break; 346 case T_RESOPFLT|T_USER: 347 sig = SIGILL; 348 code = ILL_ILLOPC; 349 break; 350 351 case T_XFCFLT|T_USER: 352 sig = SIGEMT; 353 break; 354 355 case T_ARITHFLT|T_USER: 356 sig = SIGFPE; 357 break; 358 359 case T_ASTFLT|T_USER: 360 mtpr(AST_NO,PR_ASTLVL); 361 trapsig = 0; 362 break; 363 364 #ifdef DDB 365 case T_BPTFLT: /* Kernel breakpoint */ 366 case T_KDBTRAP: 367 case T_KDBTRAP|T_USER: 368 case T_TRCTRAP: 369 kdb_trap(frame); 370 return; 371 #endif 372 } 373 if (trapsig) { 374 ksiginfo_t ksi; 375 if ((sig == SIGSEGV || sig == SIGILL) && cpu_printfataltraps) 376 printf("pid %d.%d (%s): sig %d: type %lx, code %lx, pc %lx, psl %lx\n", 377 p->p_pid, l->l_lid, p->p_comm, sig, frame->trap, 378 frame->code, frame->pc, frame->psl); 379 KERNEL_PROC_LOCK(l); 380 KSI_INIT_TRAP(&ksi); 381 ksi.ksi_signo = sig; 382 ksi.ksi_trap = frame->trap; 383 ksi.ksi_addr = (void *)frame->code; 384 ksi.ksi_code = code; 385 trapsignal(l, &ksi); 386 KERNEL_PROC_UNLOCK(l); 387 } 388 389 if (umode == 0) 390 return; 391 392 userret(l, frame, oticks); 393 } 394 395 void 396 setregs(struct lwp *l, struct exec_package *pack, u_long stack) 397 { 398 struct trapframe *exptr; 399 400 exptr = l->l_addr->u_pcb.framep; 401 exptr->pc = pack->ep_entry + 2; 402 exptr->sp = stack; 403 exptr->r6 = stack; /* for ELF */ 404 exptr->r7 = 0; /* for ELF */ 405 exptr->r8 = 0; /* for ELF */ 406 exptr->r9 = (u_long) l->l_proc->p_psstr; /* for ELF */ 407 } 408 409 void 410 syscall(struct trapframe *frame) 411 { 412 const struct sysent *callp; 413 u_quad_t oticks; 414 int nsys; 415 int err, rval[2], args[8]; 416 struct trapframe *exptr; 417 struct lwp *l = curlwp; 418 struct proc *p = l->l_proc; 419 420 #ifdef TRAPDEBUG 421 if(startsysc)printf("trap syscall %s pc %lx, psl %lx, sp %lx, pid %d, frame %p\n", 422 syscallnames[frame->code], frame->pc, frame->psl,frame->sp, 423 p->p_pid,frame); 424 #endif 425 uvmexp.syscalls++; 426 427 exptr = l->l_addr->u_pcb.framep = frame; 428 callp = p->p_emul->e_sysent; 429 nsys = p->p_emul->e_nsysent; 430 oticks = p->p_sticks; 431 432 if (frame->code == SYS___syscall) { 433 int g = *(int *)(frame->ap); 434 435 frame->code = *(int *)(frame->ap + 4); 436 frame->ap += 8; 437 *(int *)(frame->ap) = g - 2; 438 } 439 440 if ((unsigned long) frame->code >= nsys) 441 callp += p->p_emul->e_nosys; 442 else 443 callp += frame->code; 444 445 rval[0] = 0; 446 rval[1] = frame->r1; 447 KERNEL_PROC_LOCK(l); 448 if (callp->sy_narg) { 449 err = copyin((char*)frame->ap + 4, args, callp->sy_argsize); 450 if (err) 451 goto bad; 452 } 453 454 if ((err = trace_enter(l, frame->code, frame->code, NULL, args)) != 0) 455 goto bad; 456 457 err = (*callp->sy_call)(curlwp, args, rval); 458 KERNEL_PROC_UNLOCK(l); 459 exptr = l->l_addr->u_pcb.framep; 460 461 #ifdef TRAPDEBUG 462 if(startsysc) 463 printf("retur %s pc %lx, psl %lx, sp %lx, pid %d, err %d r0 %d, r1 %d, frame %p\n", 464 syscallnames[exptr->code], exptr->pc, exptr->psl,exptr->sp, 465 p->p_pid,err,rval[0],rval[1],exptr); /* } */ 466 #endif 467 468 bad: 469 switch (err) { 470 case 0: 471 exptr->r1 = rval[1]; 472 exptr->r0 = rval[0]; 473 exptr->psl &= ~PSL_C; 474 break; 475 476 case EJUSTRETURN: 477 break; 478 479 case ERESTART: 480 exptr->pc -= (exptr->code > 63 ? 4 : 2); 481 break; 482 483 default: 484 exptr->r0 = err; 485 exptr->psl |= PSL_C; 486 break; 487 } 488 489 trace_exit(l, frame->code, args, rval, err); 490 491 userret(l, frame, oticks); 492 } 493 494 void 495 child_return(void *arg) 496 { 497 struct lwp *l = arg; 498 499 KERNEL_PROC_UNLOCK(l); 500 userret(l, l->l_addr->u_pcb.framep, 0); 501 502 #ifdef KTRACE 503 if (KTRPOINT(l->l_proc, KTR_SYSRET)) { 504 KERNEL_PROC_LOCK(l); 505 ktrsysret(l->l_proc, SYS_fork, 0, 0); 506 KERNEL_PROC_UNLOCK(l); 507 } 508 #endif 509 } 510 511 /* 512 * Start a new LWP 513 */ 514 void 515 startlwp(arg) 516 void *arg; 517 { 518 int err; 519 ucontext_t *uc = arg; 520 struct lwp *l = curlwp; 521 522 err = cpu_setmcontext(l, &uc->uc_mcontext, uc->uc_flags); 523 #if DIAGNOSTIC 524 if (err) { 525 printf("Error %d from cpu_setmcontext.", err); 526 } 527 #endif 528 pool_put(&lwp_uc_pool, uc); 529 530 /* XXX - profiling spoiled here */ 531 userret(l, l->l_addr->u_pcb.framep, l->l_proc->p_sticks); 532 } 533 534 void 535 upcallret(struct lwp *l) 536 { 537 538 /* XXX - profiling */ 539 userret(l, l->l_addr->u_pcb.framep, l->l_proc->p_sticks); 540 } 541 542