1 /* $NetBSD: trap.c,v 1.95 2004/09/02 02:18:38 tacha 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.95 2004/09/02 02:18:38 tacha 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 179 if ((l = curlwp) != NULL) 180 p = l->l_proc; 181 uvmexp.traps++; 182 if ((umode = USERMODE(frame))) { 183 type |= T_USER; 184 oticks = p->p_sticks; 185 l->l_addr->u_pcb.framep = frame; 186 } 187 188 type&=~(T_WRITE|T_PTEFETCH); 189 190 191 #ifdef TRAPDEBUG 192 if(frame->trap==7) goto fram; 193 if(faultdebug)printf("Trap: type %lx, code %lx, pc %lx, psl %lx\n", 194 frame->trap, frame->code, frame->pc, frame->psl); 195 fram: 196 #endif 197 switch(type){ 198 199 default: 200 #ifdef DDB 201 kdb_trap(frame); 202 #endif 203 printf("Trap: type %x, code %x, pc %x, psl %x\n", 204 (u_int)frame->trap, (u_int)frame->code, 205 (u_int)frame->pc, (u_int)frame->psl); 206 panic("trap"); 207 208 case T_KSPNOTVAL: 209 panic("kernel stack invalid"); 210 211 case T_TRANSFLT|T_USER: 212 case T_TRANSFLT: 213 /* 214 * BUG! BUG! BUG! BUG! BUG! 215 * Due to a hardware bug (at in least KA65x CPUs) a double 216 * page table fetch trap will cause a translation fault 217 * even if access in the SPT PTE entry specifies 'no access'. 218 * In for example section 6.4.2 in VAX Architecture 219 * Reference Manual it states that if a page both are invalid 220 * and have no access set, a 'access violation fault' occurs. 221 * Therefore, we must fall through here... 222 */ 223 #ifdef nohwbug 224 panic("translation fault"); 225 #endif 226 227 case T_PTELEN|T_USER: /* Page table length exceeded */ 228 case T_ACCFLT|T_USER: 229 if (frame->code < 0) { /* Check for kernel space */ 230 sig = SIGSEGV; 231 code = SEGV_ACCERR; 232 break; 233 } 234 235 case T_PTELEN: 236 case T_ACCFLT: 237 #ifdef TRAPDEBUG 238 if(faultdebug)printf("trap accflt type %lx, code %lx, pc %lx, psl %lx\n", 239 frame->trap, frame->code, frame->pc, frame->psl); 240 #endif 241 #ifdef DIAGNOSTIC 242 if (p == 0) 243 panic("trap: access fault: addr %lx code %lx", 244 frame->pc, frame->code); 245 if (frame->psl & PSL_IS) 246 panic("trap: pflt on IS"); 247 #endif 248 249 /* 250 * Page tables are allocated in pmap_enter(). We get 251 * info from below if it is a page table fault, but 252 * UVM may want to map in pages without faults, so 253 * because we must check for PTE pages anyway we don't 254 * bother doing it here. 255 */ 256 addr = trunc_page(frame->code); 257 if ((umode == 0) && (frame->code < 0)) { 258 vm = NULL; 259 map = kernel_map; 260 } else { 261 vm = p->p_vmspace; 262 map = &vm->vm_map; 263 } 264 265 if (frame->trap & T_WRITE) 266 ftype = VM_PROT_WRITE; 267 else 268 ftype = VM_PROT_READ; 269 270 if (umode) { 271 KERNEL_PROC_LOCK(l); 272 if (l->l_flag & L_SA) { 273 l->l_savp->savp_faultaddr = (vaddr_t)frame->code; 274 l->l_flag |= L_SA_PAGEFAULT; 275 } 276 } else 277 KERNEL_LOCK(LK_CANRECURSE|LK_EXCLUSIVE); 278 279 rv = uvm_fault(map, addr, 0, ftype); 280 if (rv != 0) { 281 if (umode == 0) { 282 KERNEL_UNLOCK(); 283 FAULTCHK; 284 panic("Segv in kernel mode: pc %x addr %x", 285 (u_int)frame->pc, (u_int)frame->code); 286 } 287 code = SEGV_ACCERR; 288 if (rv == ENOMEM) { 289 printf("UVM: pid %d (%s), uid %d killed: " 290 "out of swap\n", 291 p->p_pid, p->p_comm, 292 p->p_cred && p->p_ucred ? 293 p->p_ucred->cr_uid : -1); 294 sig = SIGKILL; 295 } else { 296 sig = SIGSEGV; 297 if (rv != EACCES) 298 code = SEGV_MAPERR; 299 } 300 } else { 301 trapsig = 0; 302 if (map != kernel_map && (caddr_t)addr >= vm->vm_maxsaddr) 303 uvm_grow(p, addr); 304 } 305 if (umode) { 306 l->l_flag &= ~L_SA_PAGEFAULT; 307 KERNEL_PROC_UNLOCK(l); 308 } else 309 KERNEL_UNLOCK(); 310 break; 311 312 case T_BPTFLT|T_USER: 313 sig = SIGTRAP; 314 code = TRAP_BRKPT; 315 break; 316 case T_TRCTRAP|T_USER: 317 sig = SIGTRAP; 318 code = TRAP_TRACE; 319 frame->psl &= ~PSL_T; 320 break; 321 322 case T_PRIVINFLT|T_USER: 323 sig = SIGILL; 324 code = ILL_PRVOPC; 325 break; 326 case T_RESADFLT|T_USER: 327 sig = SIGILL; 328 code = ILL_ILLADR; 329 break; 330 case T_RESOPFLT|T_USER: 331 sig = SIGILL; 332 code = ILL_ILLOPC; 333 break; 334 335 case T_XFCFLT|T_USER: 336 sig = SIGEMT; 337 break; 338 339 case T_ARITHFLT|T_USER: 340 sig = SIGFPE; 341 break; 342 343 case T_ASTFLT|T_USER: 344 mtpr(AST_NO,PR_ASTLVL); 345 trapsig = 0; 346 break; 347 348 #ifdef DDB 349 case T_BPTFLT: /* Kernel breakpoint */ 350 case T_KDBTRAP: 351 case T_KDBTRAP|T_USER: 352 case T_TRCTRAP: 353 kdb_trap(frame); 354 return; 355 #endif 356 } 357 if (trapsig) { 358 ksiginfo_t ksi; 359 if ((sig == SIGSEGV || sig == SIGILL) && cpu_printfataltraps) 360 printf("pid %d.%d (%s): sig %d: type %lx, code %lx, pc %lx, psl %lx\n", 361 p->p_pid, l->l_lid, p->p_comm, sig, frame->trap, 362 frame->code, frame->pc, frame->psl); 363 KERNEL_PROC_LOCK(l); 364 KSI_INIT_TRAP(&ksi); 365 ksi.ksi_signo = sig; 366 ksi.ksi_trap = frame->trap; 367 ksi.ksi_addr = (void *)frame->code; 368 ksi.ksi_code = code; 369 trapsignal(l, &ksi); 370 KERNEL_PROC_UNLOCK(l); 371 } 372 373 if (umode == 0) 374 return; 375 376 userret(l, frame, oticks); 377 } 378 379 void 380 setregs(struct lwp *l, struct exec_package *pack, u_long stack) 381 { 382 struct trapframe *exptr; 383 384 exptr = l->l_addr->u_pcb.framep; 385 exptr->pc = pack->ep_entry + 2; 386 exptr->sp = stack; 387 exptr->r6 = stack; /* for ELF */ 388 exptr->r7 = 0; /* for ELF */ 389 exptr->r8 = 0; /* for ELF */ 390 exptr->r9 = (u_long) l->l_proc->p_psstr; /* for ELF */ 391 } 392 393 void 394 syscall(struct trapframe *frame) 395 { 396 const struct sysent *callp; 397 u_quad_t oticks; 398 int nsys; 399 int err, rval[2], args[8]; 400 struct trapframe *exptr; 401 struct lwp *l = curlwp; 402 struct proc *p = l->l_proc; 403 404 #ifdef TRAPDEBUG 405 if(startsysc)printf("trap syscall %s pc %lx, psl %lx, sp %lx, pid %d, frame %p\n", 406 syscallnames[frame->code], frame->pc, frame->psl,frame->sp, 407 p->p_pid,frame); 408 #endif 409 uvmexp.syscalls++; 410 411 exptr = l->l_addr->u_pcb.framep = frame; 412 callp = p->p_emul->e_sysent; 413 nsys = p->p_emul->e_nsysent; 414 oticks = p->p_sticks; 415 416 if (frame->code == SYS___syscall) { 417 int g = *(int *)(frame->ap); 418 419 frame->code = *(int *)(frame->ap + 4); 420 frame->ap += 8; 421 *(int *)(frame->ap) = g - 2; 422 } 423 424 if ((unsigned long) frame->code >= nsys) 425 callp += p->p_emul->e_nosys; 426 else 427 callp += frame->code; 428 429 rval[0] = 0; 430 rval[1] = frame->r1; 431 KERNEL_PROC_LOCK(l); 432 if (callp->sy_narg) { 433 err = copyin((char*)frame->ap + 4, args, callp->sy_argsize); 434 if (err) { 435 KERNEL_PROC_UNLOCK(l); 436 goto bad; 437 } 438 } 439 440 if ((err = trace_enter(l, frame->code, frame->code, NULL, args)) != 0) { 441 KERNEL_PROC_UNLOCK(l); 442 goto bad; 443 } 444 445 err = (*callp->sy_call)(curlwp, args, rval); 446 KERNEL_PROC_UNLOCK(l); 447 exptr = l->l_addr->u_pcb.framep; 448 449 #ifdef TRAPDEBUG 450 if(startsysc) 451 printf("retur %s pc %lx, psl %lx, sp %lx, pid %d, err %d r0 %d, r1 %d, frame %p\n", 452 syscallnames[exptr->code], exptr->pc, exptr->psl,exptr->sp, 453 p->p_pid,err,rval[0],rval[1],exptr); /* } */ 454 #endif 455 456 bad: 457 switch (err) { 458 case 0: 459 exptr->r1 = rval[1]; 460 exptr->r0 = rval[0]; 461 exptr->psl &= ~PSL_C; 462 break; 463 464 case EJUSTRETURN: 465 break; 466 467 case ERESTART: 468 exptr->pc -= (exptr->code > 63 ? 4 : 2); 469 break; 470 471 default: 472 exptr->r0 = err; 473 exptr->psl |= PSL_C; 474 break; 475 } 476 477 trace_exit(l, frame->code, args, rval, err); 478 479 userret(l, frame, oticks); 480 } 481 482 void 483 child_return(void *arg) 484 { 485 struct lwp *l = arg; 486 487 KERNEL_PROC_UNLOCK(l); 488 userret(l, l->l_addr->u_pcb.framep, 0); 489 490 #ifdef KTRACE 491 if (KTRPOINT(l->l_proc, KTR_SYSRET)) { 492 KERNEL_PROC_LOCK(l); 493 ktrsysret(l->l_proc, SYS_fork, 0, 0); 494 KERNEL_PROC_UNLOCK(l); 495 } 496 #endif 497 } 498 499 /* 500 * Start a new LWP 501 */ 502 void 503 startlwp(arg) 504 void *arg; 505 { 506 int err; 507 ucontext_t *uc = arg; 508 struct lwp *l = curlwp; 509 510 err = cpu_setmcontext(l, &uc->uc_mcontext, uc->uc_flags); 511 #if DIAGNOSTIC 512 if (err) { 513 printf("Error %d from cpu_setmcontext.", err); 514 } 515 #endif 516 pool_put(&lwp_uc_pool, uc); 517 518 /* XXX - profiling spoiled here */ 519 userret(l, l->l_addr->u_pcb.framep, l->l_proc->p_sticks); 520 } 521 522 void 523 upcallret(struct lwp *l) 524 { 525 526 /* XXX - profiling */ 527 userret(l, l->l_addr->u_pcb.framep, l->l_proc->p_sticks); 528 } 529 530