1 /* $NetBSD: trap.c,v 1.114 2008/05/21 14:07:29 ad 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.114 2008/05/21 14:07:29 ad 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/pool.h> 50 #include <sys/kauth.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 #include <machine/userret.h> 61 62 #ifdef DDB 63 #include <machine/db_machdep.h> 64 #endif 65 #include <kern/syscalls.c> 66 #include <sys/ktrace.h> 67 68 #ifdef TRAPDEBUG 69 volatile int faultdebug = 0; 70 #endif 71 72 int cpu_printfataltraps = 0; 73 74 void trap (struct trapframe *); 75 76 const char * const traptypes[]={ 77 "reserved addressing", 78 "privileged instruction", 79 "reserved operand", 80 "breakpoint instruction", 81 "XFC instruction", 82 "system call ", 83 "arithmetic trap", 84 "asynchronous system trap", 85 "page table length fault", 86 "translation violation fault", 87 "trace trap", 88 "compatibility mode fault", 89 "access violation fault", 90 "", 91 "", 92 "KSP invalid", 93 "", 94 "kernel debugger trap" 95 }; 96 int no_traps = 18; 97 98 #define USERMODE_P(framep) ((((framep)->psl) & (PSL_U)) == PSL_U) 99 #define FAULTCHK \ 100 if (l->l_addr->u_pcb.iftrap) { \ 101 frame->pc = (unsigned)l->l_addr->u_pcb.iftrap; \ 102 frame->psl &= ~PSL_FPD; \ 103 frame->r0 = EFAULT;/* for copyin/out */ \ 104 frame->r1 = -1; /* for fetch/store */ \ 105 return; \ 106 } 107 108 109 void 110 trap(struct trapframe *frame) 111 { 112 u_int sig = 0, type = frame->trap, code = 0; 113 u_int rv, addr; 114 bool trapsig = true; 115 const bool usermode = USERMODE_P(frame);; 116 struct lwp *l; 117 struct proc *p; 118 u_quad_t oticks = 0; 119 struct vmspace *vm; 120 struct vm_map *map; 121 vm_prot_t ftype; 122 123 l = curlwp; 124 KASSERT(l != NULL); 125 p = l->l_proc; 126 KASSERT(p != NULL); 127 uvmexp.traps++; 128 if (usermode) { 129 type |= T_USER; 130 oticks = p->p_sticks; 131 l->l_addr->u_pcb.framep = frame; 132 LWP_CACHE_CREDS(l, p); 133 } 134 135 type &= ~(T_WRITE|T_PTEFETCH); 136 137 138 #ifdef TRAPDEBUG 139 if(frame->trap==7) goto fram; 140 if(faultdebug)printf("Trap: type %lx, code %lx, pc %lx, psl %lx\n", 141 frame->trap, frame->code, frame->pc, frame->psl); 142 fram: 143 #endif 144 switch (type) { 145 146 default: 147 #ifdef DDB 148 kdb_trap(frame); 149 #endif 150 panic("trap: type %x, code %x, pc %x, psl %x", 151 (u_int)frame->trap, (u_int)frame->code, 152 (u_int)frame->pc, (u_int)frame->psl); 153 154 case T_KSPNOTVAL: 155 panic("%d.%d (%s): KSP invalid %#x@%#x pcb %p fp %#x psl %#x)", 156 p->p_pid, l->l_lid, l->l_name ? l->l_name : "??", 157 mfpr(PR_KSP), (u_int)frame->pc, l->l_addr, 158 (u_int)frame->fp, (u_int)frame->psl); 159 160 case T_TRANSFLT|T_USER: 161 case T_TRANSFLT: 162 /* 163 * BUG! BUG! BUG! BUG! BUG! 164 * Due to a hardware bug (at in least KA65x CPUs) a double 165 * page table fetch trap will cause a translation fault 166 * even if access in the SPT PTE entry specifies 'no access'. 167 * In for example section 6.4.2 in VAX Architecture 168 * Reference Manual it states that if a page both are invalid 169 * and have no access set, a 'access violation fault' occurs. 170 * Therefore, we must fall through here... 171 */ 172 #ifdef nohwbug 173 panic("translation fault"); 174 #endif 175 176 case T_PTELEN|T_USER: /* Page table length exceeded */ 177 case T_ACCFLT|T_USER: 178 if (frame->code < 0) { /* Check for kernel space */ 179 sig = SIGSEGV; 180 code = SEGV_ACCERR; 181 break; 182 } 183 184 case T_PTELEN: 185 case T_ACCFLT: 186 #ifdef TRAPDEBUG 187 if(faultdebug)printf("trap accflt type %lx, code %lx, pc %lx, psl %lx\n", 188 frame->trap, frame->code, frame->pc, frame->psl); 189 #endif 190 #ifdef DIAGNOSTIC 191 if (p == 0) 192 panic("trap: access fault: addr %lx code %lx", 193 frame->pc, frame->code); 194 if (frame->psl & PSL_IS) 195 panic("trap: pflt on IS"); 196 #endif 197 198 /* 199 * Page tables are allocated in pmap_enter(). We get 200 * info from below if it is a page table fault, but 201 * UVM may want to map in pages without faults, so 202 * because we must check for PTE pages anyway we don't 203 * bother doing it here. 204 */ 205 addr = trunc_page(frame->code); 206 if (!usermode && (frame->code < 0)) { 207 vm = NULL; 208 map = kernel_map; 209 210 } else { 211 vm = p->p_vmspace; 212 map = &vm->vm_map; 213 } 214 215 if (frame->trap & T_WRITE) 216 ftype = VM_PROT_WRITE; 217 else 218 ftype = VM_PROT_READ; 219 220 rv = uvm_fault(map, addr, ftype); 221 if (rv != 0) { 222 if (!usermode) { 223 FAULTCHK; 224 panic("Segv in kernel mode: pc %x addr %x", 225 (u_int)frame->pc, (u_int)frame->code); 226 } 227 code = SEGV_ACCERR; 228 if (rv == ENOMEM) { 229 printf("UVM: pid %d (%s), uid %d killed: " 230 "out of swap\n", 231 p->p_pid, p->p_comm, 232 l->l_cred ? 233 kauth_cred_geteuid(l->l_cred) : -1); 234 sig = SIGKILL; 235 } else { 236 sig = SIGSEGV; 237 if (rv != EACCES) 238 code = SEGV_MAPERR; 239 } 240 } else { 241 trapsig = false; 242 if (map != kernel_map && addr > 0 243 && (void *)addr >= vm->vm_maxsaddr) 244 uvm_grow(p, addr); 245 } 246 break; 247 248 case T_BPTFLT|T_USER: 249 sig = SIGTRAP; 250 code = TRAP_BRKPT; 251 break; 252 case T_TRCTRAP|T_USER: 253 sig = SIGTRAP; 254 code = TRAP_TRACE; 255 frame->psl &= ~PSL_T; 256 break; 257 258 case T_PRIVINFLT|T_USER: 259 sig = SIGILL; 260 code = ILL_PRVOPC; 261 break; 262 case T_RESADFLT|T_USER: 263 sig = SIGILL; 264 code = ILL_ILLADR; 265 break; 266 case T_RESOPFLT|T_USER: 267 sig = SIGILL; 268 code = ILL_ILLOPC; 269 break; 270 271 case T_XFCFLT|T_USER: 272 sig = SIGEMT; 273 break; 274 275 case T_ARITHFLT|T_USER: 276 sig = SIGFPE; 277 break; 278 279 case T_ASTFLT|T_USER: 280 mtpr(AST_NO,PR_ASTLVL); 281 trapsig = false; 282 break; 283 284 #ifdef DDB 285 case T_BPTFLT: /* Kernel breakpoint */ 286 case T_KDBTRAP: 287 case T_KDBTRAP|T_USER: 288 case T_TRCTRAP: 289 kdb_trap(frame); 290 return; 291 #endif 292 } 293 if (trapsig) { 294 ksiginfo_t ksi; 295 if ((sig == SIGSEGV || sig == SIGILL) && cpu_printfataltraps) 296 printf("pid %d.%d (%s): sig %d: type %lx, code %lx, pc %lx, psl %lx\n", 297 p->p_pid, l->l_lid, p->p_comm, sig, frame->trap, 298 frame->code, frame->pc, frame->psl); 299 KSI_INIT_TRAP(&ksi); 300 ksi.ksi_signo = sig; 301 ksi.ksi_trap = frame->trap; 302 ksi.ksi_addr = (void *)frame->code; 303 ksi.ksi_code = code; 304 trapsignal(l, &ksi); 305 } 306 307 if (!usermode) 308 return; 309 310 userret(l, frame, oticks); 311 } 312 313 void 314 setregs(struct lwp *l, struct exec_package *pack, u_long stack) 315 { 316 struct trapframe *exptr; 317 318 exptr = l->l_addr->u_pcb.framep; 319 exptr->pc = pack->ep_entry + 2; 320 exptr->sp = stack; 321 exptr->r6 = stack; /* for ELF */ 322 exptr->r7 = 0; /* for ELF */ 323 exptr->r8 = 0; /* for ELF */ 324 exptr->r9 = (u_long) l->l_proc->p_psstr; /* for ELF */ 325 } 326 327 328 /* 329 * Start a new LWP 330 */ 331 void 332 startlwp(void *arg) 333 { 334 int err; 335 ucontext_t *uc = arg; 336 struct lwp *l = curlwp; 337 338 err = cpu_setmcontext(l, &uc->uc_mcontext, uc->uc_flags); 339 #if DIAGNOSTIC 340 if (err) { 341 printf("Error %d from cpu_setmcontext.", err); 342 } 343 #endif 344 pool_put(&lwp_uc_pool, uc); 345 346 /* XXX - profiling spoiled here */ 347 userret(l, l->l_addr->u_pcb.framep, l->l_proc->p_sticks); 348 } 349