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