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