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