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