1 /* $NetBSD: trap.c,v 1.116 2008/10/15 06:51:19 wrstuden 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.116 2008/10/15 06:51:19 wrstuden Exp $"); 37 38 #include "opt_ddb.h" 39 #include "opt_multiprocessor.h" 40 41 #include <sys/types.h> 42 #include <sys/param.h> 43 #include <sys/proc.h> 44 #include <sys/user.h> 45 #include <sys/syscall.h> 46 #include <sys/systm.h> 47 #include <sys/signalvar.h> 48 #include <sys/exec.h> 49 #include <sys/sa.h> 50 #include <sys/savar.h> 51 #include <sys/pool.h> 52 #include <sys/kauth.h> 53 54 #include <uvm/uvm_extern.h> 55 56 #include <machine/mtpr.h> 57 #include <machine/pte.h> 58 #include <machine/pcb.h> 59 #include <machine/trap.h> 60 #include <machine/pmap.h> 61 #include <machine/cpu.h> 62 #include <machine/userret.h> 63 64 #ifdef DDB 65 #include <machine/db_machdep.h> 66 #endif 67 #include <kern/syscalls.c> 68 #include <sys/ktrace.h> 69 70 #ifdef TRAPDEBUG 71 volatile int faultdebug = 0; 72 #endif 73 74 int cpu_printfataltraps = 0; 75 76 void trap (struct trapframe *); 77 78 const char * const 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_P(framep) ((((framep)->psl) & (PSL_U)) == PSL_U) 101 #define FAULTCHK \ 102 if (l->l_addr->u_pcb.iftrap) { \ 103 frame->pc = (unsigned)l->l_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 void 112 trap(struct trapframe *frame) 113 { 114 u_int sig = 0, type = frame->trap, code = 0; 115 u_int rv, addr; 116 bool trapsig = true; 117 const bool usermode = USERMODE_P(frame);; 118 struct lwp *l; 119 struct proc *p; 120 u_quad_t oticks = 0; 121 struct vmspace *vm; 122 struct vm_map *map; 123 vm_prot_t ftype; 124 125 l = curlwp; 126 KASSERT(l != NULL); 127 p = l->l_proc; 128 KASSERT(p != NULL); 129 uvmexp.traps++; 130 if (usermode) { 131 type |= T_USER; 132 oticks = p->p_sticks; 133 l->l_addr->u_pcb.framep = frame; 134 LWP_CACHE_CREDS(l, p); 135 } 136 137 type &= ~(T_WRITE|T_PTEFETCH); 138 139 140 #ifdef TRAPDEBUG 141 if(frame->trap==7) goto fram; 142 if(faultdebug)printf("Trap: type %lx, code %lx, pc %lx, psl %lx\n", 143 frame->trap, frame->code, frame->pc, frame->psl); 144 fram: 145 #endif 146 switch (type) { 147 148 default: 149 #ifdef DDB 150 kdb_trap(frame); 151 #endif 152 panic("trap: type %x, code %x, pc %x, psl %x", 153 (u_int)frame->trap, (u_int)frame->code, 154 (u_int)frame->pc, (u_int)frame->psl); 155 156 case T_KSPNOTVAL: 157 panic("%d.%d (%s): KSP invalid %#x@%#x pcb %p fp %#x psl %#x)", 158 p->p_pid, l->l_lid, l->l_name ? l->l_name : "??", 159 mfpr(PR_KSP), (u_int)frame->pc, l->l_addr, 160 (u_int)frame->fp, (u_int)frame->psl); 161 162 case T_TRANSFLT|T_USER: 163 case T_TRANSFLT: 164 /* 165 * BUG! BUG! BUG! BUG! BUG! 166 * Due to a hardware bug (at in least KA65x CPUs) a double 167 * page table fetch trap will cause a translation fault 168 * even if access in the SPT PTE entry specifies 'no access'. 169 * In for example section 6.4.2 in VAX Architecture 170 * Reference Manual it states that if a page both are invalid 171 * and have no access set, a 'access violation fault' occurs. 172 * Therefore, we must fall through here... 173 */ 174 #ifdef nohwbug 175 panic("translation fault"); 176 #endif 177 178 case T_PTELEN|T_USER: /* Page table length exceeded */ 179 case T_ACCFLT|T_USER: 180 if (frame->code < 0) { /* Check for kernel space */ 181 sig = SIGSEGV; 182 code = SEGV_ACCERR; 183 break; 184 } 185 186 case T_PTELEN: 187 case T_ACCFLT: 188 #ifdef TRAPDEBUG 189 if(faultdebug)printf("trap accflt type %lx, code %lx, pc %lx, psl %lx\n", 190 frame->trap, frame->code, frame->pc, frame->psl); 191 #endif 192 #ifdef DIAGNOSTIC 193 if (p == 0) 194 panic("trap: access fault: addr %lx code %lx", 195 frame->pc, frame->code); 196 if (frame->psl & PSL_IS) 197 panic("trap: pflt on IS"); 198 #endif 199 200 /* 201 * Page tables are allocated in pmap_enter(). We get 202 * info from below if it is a page table fault, but 203 * UVM may want to map in pages without faults, so 204 * because we must check for PTE pages anyway we don't 205 * bother doing it here. 206 */ 207 addr = trunc_page(frame->code); 208 if (!usermode && (frame->code < 0)) { 209 vm = NULL; 210 map = kernel_map; 211 212 } else { 213 vm = p->p_vmspace; 214 map = &vm->vm_map; 215 } 216 217 if (frame->trap & T_WRITE) 218 ftype = VM_PROT_WRITE; 219 else 220 ftype = VM_PROT_READ; 221 222 if ((usermode) && (l->l_flag & LW_SA)) { 223 l->l_savp->savp_faultaddr = (vaddr_t)frame->code; 224 l->l_pflag |= LP_SA_PAGEFAULT; 225 } 226 227 rv = uvm_fault(map, addr, ftype); 228 if (rv != 0) { 229 if (!usermode) { 230 FAULTCHK; 231 panic("Segv in kernel mode: pc %x addr %x", 232 (u_int)frame->pc, (u_int)frame->code); 233 } 234 code = SEGV_ACCERR; 235 if (rv == ENOMEM) { 236 printf("UVM: pid %d (%s), uid %d killed: " 237 "out of swap\n", 238 p->p_pid, p->p_comm, 239 l->l_cred ? 240 kauth_cred_geteuid(l->l_cred) : -1); 241 sig = SIGKILL; 242 } else { 243 sig = SIGSEGV; 244 if (rv != EACCES) 245 code = SEGV_MAPERR; 246 } 247 } else { 248 trapsig = false; 249 if (map != kernel_map && addr > 0 250 && (void *)addr >= vm->vm_maxsaddr) 251 uvm_grow(p, addr); 252 } 253 if (usermode) { 254 l->l_pflag &= ~LP_SA_PAGEFAULT; 255 } 256 break; 257 258 case T_BPTFLT|T_USER: 259 sig = SIGTRAP; 260 code = TRAP_BRKPT; 261 break; 262 case T_TRCTRAP|T_USER: 263 sig = SIGTRAP; 264 code = TRAP_TRACE; 265 frame->psl &= ~PSL_T; 266 break; 267 268 case T_PRIVINFLT|T_USER: 269 sig = SIGILL; 270 code = ILL_PRVOPC; 271 break; 272 case T_RESADFLT|T_USER: 273 sig = SIGILL; 274 code = ILL_ILLADR; 275 break; 276 case T_RESOPFLT|T_USER: 277 sig = SIGILL; 278 code = ILL_ILLOPC; 279 break; 280 281 case T_XFCFLT|T_USER: 282 sig = SIGEMT; 283 break; 284 285 case T_ARITHFLT|T_USER: 286 sig = SIGFPE; 287 switch (frame->code) { 288 case AFLT_FLTDIV: code = FPE_FLTDIV; break; 289 case AFLT_FLTUND: code = FPE_FLTUND; break; 290 case AFLT_FLTOVF: code = FPE_FLTOVF; break; 291 } 292 break; 293 294 case T_ASTFLT|T_USER: 295 mtpr(AST_NO,PR_ASTLVL); 296 trapsig = false; 297 break; 298 299 #ifdef DDB 300 case T_BPTFLT: /* Kernel breakpoint */ 301 case T_KDBTRAP: 302 case T_KDBTRAP|T_USER: 303 case T_TRCTRAP: 304 kdb_trap(frame); 305 return; 306 #endif 307 } 308 if (trapsig) { 309 ksiginfo_t ksi; 310 if ((sig == SIGSEGV || sig == SIGILL) && cpu_printfataltraps) 311 printf("pid %d.%d (%s): sig %d: type %lx, code %lx, pc %lx, psl %lx\n", 312 p->p_pid, l->l_lid, p->p_comm, sig, frame->trap, 313 frame->code, frame->pc, frame->psl); 314 KSI_INIT_TRAP(&ksi); 315 ksi.ksi_signo = sig; 316 ksi.ksi_trap = frame->trap; 317 ksi.ksi_addr = (void *)frame->code; 318 ksi.ksi_code = code; 319 trapsignal(l, &ksi); 320 } 321 322 if (!usermode) 323 return; 324 325 userret(l, frame, oticks); 326 } 327 328 void 329 setregs(struct lwp *l, struct exec_package *pack, u_long stack) 330 { 331 struct trapframe *exptr; 332 333 exptr = l->l_addr->u_pcb.framep; 334 exptr->pc = pack->ep_entry + 2; 335 exptr->sp = stack; 336 exptr->r6 = stack; /* for ELF */ 337 exptr->r7 = 0; /* for ELF */ 338 exptr->r8 = 0; /* for ELF */ 339 exptr->r9 = (u_long) l->l_proc->p_psstr; /* for ELF */ 340 } 341 342 343 /* 344 * Start a new LWP 345 */ 346 void 347 startlwp(void *arg) 348 { 349 int err; 350 ucontext_t *uc = arg; 351 struct lwp *l = curlwp; 352 353 err = cpu_setmcontext(l, &uc->uc_mcontext, uc->uc_flags); 354 #if DIAGNOSTIC 355 if (err) { 356 printf("Error %d from cpu_setmcontext.", err); 357 } 358 #endif 359 pool_put(&lwp_uc_pool, uc); 360 361 /* XXX - profiling spoiled here */ 362 userret(l, l->l_addr->u_pcb.framep, l->l_proc->p_sticks); 363 } 364 365 void 366 upcallret(struct lwp *l) 367 { 368 369 /* XXX - profiling */ 370 userret(l, l->l_addr->u_pcb.framep, l->l_proc->p_sticks); 371 } 372 373