1 /* $NetBSD: trap.c,v 1.66 2001/06/28 21:54:23 ragge 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 case T_ACCFLT|T_USER: 198 if (frame->code < 0) { /* Check for kernel space */ 199 sig = SIGSEGV; 200 break; 201 } 202 case T_ACCFLT: 203 #ifdef TRAPDEBUG 204 if(faultdebug)printf("trap accflt type %lx, code %lx, pc %lx, psl %lx\n", 205 frame->trap, frame->code, frame->pc, frame->psl); 206 #endif 207 #ifdef DIAGNOSTIC 208 if (p == 0) 209 panic("trap: access fault: addr %lx code %lx", 210 frame->pc, frame->code); 211 if (frame->psl & PSL_IS) 212 panic("trap: pflt on IS"); 213 #endif 214 215 /* 216 * Page tables are allocated in pmap_enter(). We get 217 * info from below if it is a page table fault, but 218 * UVM may want to map in pages without faults, so 219 * because we must check for PTE pages anyway we don't 220 * bother doing it here. 221 */ 222 addr = trunc_page(frame->code); 223 if ((umode == 0) && (frame->code < 0)) 224 map = kernel_map; 225 else 226 map = &p->p_vmspace->vm_map; 227 228 if (frame->trap & T_WRITE) 229 ftype = VM_PROT_WRITE|VM_PROT_READ; 230 else 231 ftype = VM_PROT_READ; 232 233 if (umode) 234 KERNEL_PROC_LOCK(p); 235 else 236 KERNEL_LOCK(LK_CANRECURSE|LK_EXCLUSIVE); 237 rv = uvm_fault(map, addr, 0, ftype); 238 if (rv != 0) { 239 if (umode == 0) { 240 KERNEL_UNLOCK(); 241 FAULTCHK; 242 panic("Segv in kernel mode: pc %x addr %x", 243 (u_int)frame->pc, (u_int)frame->code); 244 } 245 if (rv == ENOMEM) { 246 printf("UVM: pid %d (%s), uid %d killed: " 247 "out of swap\n", 248 p->p_pid, p->p_comm, 249 p->p_cred && p->p_ucred ? 250 p->p_ucred->cr_uid : -1); 251 sig = SIGKILL; 252 } else { 253 sig = SIGSEGV; 254 } 255 } else 256 trapsig = 0; 257 if (umode) 258 KERNEL_PROC_UNLOCK(p); 259 else 260 KERNEL_UNLOCK(); 261 break; 262 263 case T_PTELEN: 264 if (p && p->p_addr) 265 FAULTCHK; 266 panic("ptelen fault in system space: addr %lx pc %lx", 267 frame->code, frame->pc); 268 269 case T_PTELEN|T_USER: /* Page table length exceeded */ 270 sig = SIGSEGV; 271 break; 272 273 case T_BPTFLT|T_USER: 274 case T_TRCTRAP|T_USER: 275 sig = SIGTRAP; 276 frame->psl &= ~PSL_T; 277 break; 278 279 case T_PRIVINFLT|T_USER: 280 case T_RESADFLT|T_USER: 281 case T_RESOPFLT|T_USER: 282 sig = SIGILL; 283 break; 284 285 case T_XFCFLT|T_USER: 286 sig = SIGEMT; 287 break; 288 289 case T_ARITHFLT|T_USER: 290 sig = SIGFPE; 291 break; 292 293 case T_ASTFLT|T_USER: 294 mtpr(AST_NO,PR_ASTLVL); 295 trapsig = 0; 296 break; 297 298 #ifdef DDB 299 case T_BPTFLT: /* Kernel breakpoint */ 300 case T_KDBTRAP: 301 case T_KDBTRAP|T_USER: 302 case T_TRCTRAP: 303 kdb_trap(frame); 304 return; 305 #endif 306 } 307 if (trapsig) { 308 if (sig == SIGSEGV || sig == SIGILL) 309 printf("pid %d (%s): sig %d: type %lx, code %lx, pc %lx, psl %lx\n", 310 p->p_pid, p->p_comm, sig, frame->trap, 311 frame->code, frame->pc, frame->psl); 312 KERNEL_PROC_LOCK(p); 313 trapsignal(p, sig, frame->code); 314 KERNEL_PROC_UNLOCK(p); 315 } 316 317 if (umode == 0) 318 return; 319 320 userret(p, frame, oticks); 321 } 322 323 void 324 setregs(struct proc *p, struct exec_package *pack, u_long stack) 325 { 326 struct trapframe *exptr; 327 328 exptr = p->p_addr->u_pcb.framep; 329 exptr->pc = pack->ep_entry + 2; 330 exptr->sp = stack; 331 exptr->r6 = stack; /* for ELF */ 332 exptr->r7 = 0; /* for ELF */ 333 exptr->r8 = 0; /* for ELF */ 334 exptr->r9 = (u_long) PS_STRINGS; /* for ELF */ 335 } 336 337 void 338 syscall(struct trapframe *frame) 339 { 340 const struct sysent *callp; 341 u_quad_t oticks; 342 int nsys; 343 int err, rval[2], args[8]; 344 struct trapframe *exptr; 345 struct proc *p = curproc; 346 347 348 #ifdef TRAPDEBUG 349 if(startsysc)printf("trap syscall %s pc %lx, psl %lx, sp %lx, pid %d, frame %p\n", 350 syscallnames[frame->code], frame->pc, frame->psl,frame->sp, 351 curproc->p_pid,frame); 352 #endif 353 uvmexp.syscalls++; 354 355 exptr = p->p_addr->u_pcb.framep = frame; 356 callp = p->p_emul->e_sysent; 357 nsys = p->p_emul->e_nsysent; 358 oticks = p->p_sticks; 359 360 if (frame->code == SYS___syscall) { 361 int g = *(int *)(frame->ap); 362 363 frame->code = *(int *)(frame->ap + 4); 364 frame->ap += 8; 365 *(int *)(frame->ap) = g - 2; 366 } 367 368 if ((unsigned long) frame->code >= nsys) 369 callp += p->p_emul->e_nosys; 370 else 371 callp += frame->code; 372 373 rval[0] = 0; 374 rval[1] = frame->r1; 375 KERNEL_PROC_LOCK(p); 376 if (callp->sy_narg) { 377 err = copyin((char*)frame->ap + 4, args, callp->sy_argsize); 378 if (err) { 379 #ifdef KTRACE 380 if (KTRPOINT(p, KTR_SYSCALL)) 381 ktrsyscall(p, frame->code, 382 callp->sy_argsize, args); 383 #endif 384 goto bad; 385 } 386 } 387 #ifdef KTRACE 388 if (KTRPOINT(p, KTR_SYSCALL)) 389 ktrsyscall(p, frame->code, callp->sy_argsize, args); 390 #endif 391 err = (*callp->sy_call)(curproc, args, rval); 392 KERNEL_PROC_UNLOCK(p); 393 exptr = curproc->p_addr->u_pcb.framep; 394 395 #ifdef TRAPDEBUG 396 if(startsysc) 397 printf("retur %s pc %lx, psl %lx, sp %lx, pid %d, err %d r0 %d, r1 %d, frame %p\n", 398 syscallnames[exptr->code], exptr->pc, exptr->psl,exptr->sp, 399 p->p_pid,err,rval[0],rval[1],exptr); /* } */ 400 #endif 401 402 bad: 403 switch (err) { 404 case 0: 405 exptr->r1 = rval[1]; 406 exptr->r0 = rval[0]; 407 exptr->psl &= ~PSL_C; 408 break; 409 410 case EJUSTRETURN: 411 break; 412 413 case ERESTART: 414 exptr->pc -= (exptr->code > 63 ? 4 : 2); 415 break; 416 417 default: 418 exptr->r0 = err; 419 exptr->psl |= PSL_C; 420 break; 421 } 422 423 userret(p, frame, oticks); 424 425 #ifdef KTRACE 426 if (KTRPOINT(p, KTR_SYSRET)) { 427 KERNEL_PROC_LOCK(p); 428 ktrsysret(p, frame->code, err, rval[0]); 429 KERNEL_PROC_UNLOCK(p); 430 } 431 #endif 432 } 433 434 void 435 child_return(void *arg) 436 { 437 struct proc *p = arg; 438 439 KERNEL_PROC_UNLOCK(p); 440 userret(p, p->p_addr->u_pcb.framep, 0); 441 442 #ifdef KTRACE 443 if (KTRPOINT(p, KTR_SYSRET)) { 444 KERNEL_PROC_LOCK(p); 445 ktrsysret(p, SYS_fork, 0, 0); 446 KERNEL_PROC_UNLOCK(p); 447 } 448 #endif 449 } 450