1 /* $NetBSD: trap.c,v 1.47 1999/08/21 19:26:20 matt Exp $ */ 2 /* 3 * Copyright (c) 1994 Ludd, University of Lule}, Sweden. 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. All advertising materials mentioning features or use of this software 15 * must display the following acknowledgement: 16 * This product includes software developed at Ludd, University of Lule}. 17 * 4. The name of the author may not be used to endorse or promote products 18 * derived from this software without specific prior written permission 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* All bugs are subject to removal without further notice */ 33 34 #include "opt_ddb.h" 35 #include "opt_ktrace.h" 36 37 #include <sys/types.h> 38 #include <sys/param.h> 39 #include <sys/proc.h> 40 #include <sys/user.h> 41 #include <sys/syscall.h> 42 #include <sys/systm.h> 43 #include <sys/signalvar.h> 44 #include <sys/exec.h> 45 46 #include <vm/vm.h> 47 #include <vm/vm_kern.h> 48 #include <vm/vm_page.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 void arithflt __P((struct trapframe *)); 70 void syscall __P((struct trapframe *)); 71 72 char *traptypes[]={ 73 "reserved addressing", 74 "privileged instruction", 75 "reserved operand", 76 "breakpoint instruction", 77 "XFC instruction", 78 "system call ", 79 "arithmetic trap", 80 "asynchronous system trap", 81 "page table length fault", 82 "translation violation fault", 83 "trace trap", 84 "compatibility mode fault", 85 "access violation fault", 86 "", 87 "", 88 "KSP invalid", 89 "", 90 "kernel debugger trap" 91 }; 92 int no_traps = 18; 93 94 #define USERMODE(framep) ((((framep)->psl) & (PSL_U)) == PSL_U) 95 #define FAULTCHK \ 96 if (p->p_addr->u_pcb.iftrap) { \ 97 frame->pc = (unsigned)p->p_addr->u_pcb.iftrap; \ 98 frame->psl &= ~PSL_FPD; \ 99 frame->r0 = EFAULT;/* for copyin/out */ \ 100 frame->r1 = -1; /* for fetch/store */ \ 101 return; \ 102 } 103 104 void 105 arithflt(frame) 106 struct trapframe *frame; 107 { 108 u_int sig = 0, type = frame->trap, trapsig = 1; 109 u_int rv, addr, umode; 110 struct proc *p = curproc; 111 u_quad_t oticks = 0; 112 vm_map_t map; 113 vm_prot_t ftype; 114 115 uvmexp.traps++; 116 if ((umode = USERMODE(frame))) { 117 type |= T_USER; 118 oticks = p->p_sticks; 119 p->p_addr->u_pcb.framep = frame; 120 } 121 122 type&=~(T_WRITE|T_PTEFETCH); 123 124 125 #ifdef TRAPDEBUG 126 if(frame->trap==7) goto fram; 127 if(faultdebug)printf("Trap: type %lx, code %lx, pc %lx, psl %lx\n", 128 frame->trap, frame->code, frame->pc, frame->psl); 129 fram: 130 #endif 131 switch(type){ 132 133 default: 134 #ifdef DDB 135 kdb_trap(frame); 136 #endif 137 printf("Trap: type %x, code %x, pc %x, psl %x\n", 138 (u_int)frame->trap, (u_int)frame->code, 139 (u_int)frame->pc, (u_int)frame->psl); 140 panic("trap"); 141 142 case T_KSPNOTVAL: 143 panic("kernel stack invalid"); 144 145 case T_TRANSFLT|T_USER: 146 case T_TRANSFLT: 147 /* 148 * BUG! BUG! BUG! BUG! BUG! 149 * Due to a hardware bug (at in least KA65x CPUs) a double 150 * page table fetch trap will cause a translation fault 151 * even if access in the SPT PTE entry specifies 'no access'. 152 * In for example section 6.4.2 in VAX Architecture 153 * Reference Manual it states that if a page both are invalid 154 * and have no access set, a 'access violation fault' occurs. 155 * Therefore, we must fall through here... 156 */ 157 #ifdef nohwbug 158 panic("translation fault"); 159 #endif 160 case T_ACCFLT|T_USER: 161 if (frame->code < 0) { /* Check for kernel space */ 162 sig = SIGSEGV; 163 break; 164 } 165 case T_ACCFLT: 166 #ifdef TRAPDEBUG 167 if(faultdebug)printf("trap accflt type %lx, code %lx, pc %lx, psl %lx\n", 168 frame->trap, frame->code, frame->pc, frame->psl); 169 #endif 170 #ifdef DIAGNOSTIC 171 if (p == 0) 172 panic("trap: access fault: addr %lx code %lx", 173 frame->pc, frame->code); 174 #endif 175 176 /* 177 * Page tables are allocated in pmap_enter(). We get 178 * info from below if it is a page table fault, but 179 * UVM may want to map in pages without faults, so 180 * because we must check for PTE pages anyway we don't 181 * bother doing it here. 182 */ 183 addr = trunc_page(frame->code); 184 if ((umode == 0) && (frame->code < 0)) 185 map = kernel_map; 186 else 187 map = &p->p_vmspace->vm_map; 188 189 if (frame->trap & T_WRITE) 190 ftype = VM_PROT_WRITE|VM_PROT_READ; 191 else 192 ftype = VM_PROT_READ; 193 194 rv = uvm_fault(map, addr, 0, ftype); 195 if (rv != KERN_SUCCESS) { 196 if (umode == 0) { 197 FAULTCHK; 198 panic("Segv in kernel mode: pc %x addr %x", 199 (u_int)frame->pc, (u_int)frame->code); 200 } 201 if (rv == KERN_RESOURCE_SHORTAGE) { 202 printf("UVM: pid %d (%s), uid %d killed: " 203 "out of swap\n", 204 p->p_pid, p->p_comm, 205 p->p_cred && p->p_ucred ? 206 p->p_ucred->cr_uid : -1); 207 sig = SIGKILL; 208 } else { 209 sig = SIGSEGV; 210 } 211 } else 212 trapsig = 0; 213 break; 214 215 case T_PTELEN: 216 if (p && p->p_addr) 217 FAULTCHK; 218 panic("ptelen fault in system space: addr %lx pc %lx", 219 frame->code, frame->pc); 220 221 case T_PTELEN|T_USER: /* Page table length exceeded */ 222 sig = SIGSEGV; 223 break; 224 225 case T_BPTFLT|T_USER: 226 case T_TRCTRAP|T_USER: 227 sig = SIGTRAP; 228 frame->psl &= ~PSL_T; 229 break; 230 231 case T_PRIVINFLT|T_USER: 232 case T_RESADFLT|T_USER: 233 case T_RESOPFLT|T_USER: 234 sig = SIGILL; 235 break; 236 237 case T_XFCFLT|T_USER: 238 sig = SIGEMT; 239 break; 240 241 case T_ARITHFLT|T_USER: 242 sig = SIGFPE; 243 break; 244 245 case T_ASTFLT|T_USER: 246 mtpr(AST_NO,PR_ASTLVL); 247 trapsig = 0; 248 break; 249 250 #ifdef DDB 251 case T_BPTFLT: /* Kernel breakpoint */ 252 case T_KDBTRAP: 253 case T_KDBTRAP|T_USER: 254 case T_TRCTRAP: 255 kdb_trap(frame); 256 return; 257 #endif 258 } 259 260 if (trapsig) 261 trapsignal(p, sig, frame->code); 262 263 if (umode == 0) 264 return; 265 266 while ((sig = CURSIG(p)) !=0) 267 postsig(sig); 268 p->p_priority = p->p_usrpri; 269 if (want_resched) { 270 /* 271 * Since we are curproc, clock will normally just change 272 * our priority without moving us from one queue to another 273 * (since the running process is not on a queue.) 274 * If that happened after we setrunqueue ourselves but before 275 * we swtch()'ed, we might not be on the queue indicated by 276 * our priority. 277 */ 278 splstatclock(); 279 setrunqueue(p); 280 mi_switch(); 281 while ((sig = CURSIG(p)) != 0) 282 postsig(sig); 283 } 284 if (p->p_flag & P_PROFIL) { 285 extern int psratio; 286 addupc_task(p, frame->pc, (int)(p->p_sticks-oticks) * psratio); 287 } 288 curpriority = p->p_priority; 289 } 290 291 void 292 setregs(p, pack, stack) 293 struct proc *p; 294 struct exec_package *pack; 295 u_long stack; 296 { 297 struct trapframe *exptr; 298 299 exptr = p->p_addr->u_pcb.framep; 300 exptr->pc = pack->ep_entry + 2; 301 exptr->sp = stack; 302 exptr->r6 = stack; /* for ELF */ 303 exptr->r7 = 0; /* for ELF */ 304 exptr->r8 = 0; /* for ELF */ 305 exptr->r9 = (u_long) PS_STRINGS; /* for ELF */ 306 } 307 308 void 309 syscall(frame) 310 struct trapframe *frame; 311 { 312 struct sysent *callp; 313 u_quad_t oticks; 314 int nsys, sig; 315 int err, rval[2], args[8]; 316 struct trapframe *exptr; 317 struct proc *p = curproc; 318 319 #ifdef TRAPDEBUG 320 if(startsysc)printf("trap syscall %s pc %lx, psl %lx, sp %lx, pid %d, frame %p\n", 321 syscallnames[frame->code], frame->pc, frame->psl,frame->sp, 322 curproc->p_pid,frame); 323 #endif 324 uvmexp.syscalls++; 325 326 exptr = p->p_addr->u_pcb.framep = frame; 327 callp = p->p_emul->e_sysent; 328 nsys = p->p_emul->e_nsysent; 329 oticks = p->p_sticks; 330 331 if(frame->code == SYS___syscall){ 332 int g = *(int *)(frame->ap); 333 334 frame->code = *(int *)(frame->ap + 4); 335 frame->ap += 8; 336 *(int *)(frame->ap) = g - 2; 337 } 338 339 if(frame->code < 0 || frame->code >= nsys) 340 callp += p->p_emul->e_nosys; 341 else 342 callp += frame->code; 343 344 rval[0] = 0; 345 rval[1] = frame->r1; 346 if(callp->sy_narg) { 347 err = copyin((char*)frame->ap + 4, args, callp->sy_argsize); 348 if (err) { 349 #ifdef KTRACE 350 if (KTRPOINT(p, KTR_SYSCALL)) 351 ktrsyscall(p->p_tracep, frame->code, 352 callp->sy_argsize, args); 353 #endif 354 goto bad; 355 } 356 } 357 #ifdef KTRACE 358 if (KTRPOINT(p, KTR_SYSCALL)) 359 ktrsyscall(p->p_tracep, frame->code, callp->sy_argsize, args); 360 #endif 361 err = (*callp->sy_call)(curproc, args, rval); 362 exptr = curproc->p_addr->u_pcb.framep; 363 364 #ifdef TRAPDEBUG 365 if(startsysc) 366 printf("retur %s pc %lx, psl %lx, sp %lx, pid %d, v{rde %d r0 %d, r1 %d, frame %p\n", 367 syscallnames[exptr->code], exptr->pc, exptr->psl,exptr->sp, 368 curproc->p_pid,err,rval[0],rval[1],exptr); 369 #endif 370 371 bad: 372 switch (err) { 373 case 0: 374 exptr->r1 = rval[1]; 375 exptr->r0 = rval[0]; 376 exptr->psl &= ~PSL_C; 377 break; 378 379 case EJUSTRETURN: 380 return; 381 382 case ERESTART: 383 exptr->pc -= (exptr->code > 63 ? 4 : 2); 384 break; 385 386 default: 387 exptr->r0 = err; 388 exptr->psl |= PSL_C; 389 break; 390 } 391 p = curproc; 392 while ((sig = CURSIG(p)) !=0) 393 postsig(sig); 394 p->p_priority = p->p_usrpri; 395 if (want_resched) { 396 /* 397 * Since we are curproc, clock will normally just change 398 * our priority without moving us from one queue to another 399 * (since the running process is not on a queue.) 400 * If that happened after we setrunqueue ourselves but before 401 * we swtch()'ed, we might not be on the queue indicated by 402 * our priority. 403 */ 404 splstatclock(); 405 setrunqueue(p); 406 mi_switch(); 407 while ((sig = CURSIG(p)) != 0) 408 postsig(sig); 409 } 410 if (p->p_flag & P_PROFIL) { 411 extern int psratio; 412 addupc_task(p, frame->pc, (int)(p->p_sticks-oticks) * psratio); 413 } 414 #ifdef KTRACE 415 if (KTRPOINT(p, KTR_SYSRET)) 416 ktrsysret(p->p_tracep, frame->code, err, rval[0]); 417 #endif 418 } 419