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