1 /* $NetBSD: trap.c,v 1.33 1998/01/03 00:35:28 thorpej 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 35 36 #include <sys/types.h> 37 #include <sys/param.h> 38 #include <sys/proc.h> 39 #include <sys/user.h> 40 #include <sys/syscall.h> 41 #include <sys/systm.h> 42 #include <sys/signalvar.h> 43 #include <sys/exec.h> 44 45 #include <vm/vm.h> 46 #include <vm/vm_kern.h> 47 #include <vm/vm_page.h> 48 49 #include <machine/mtpr.h> 50 #include <machine/pte.h> 51 #include <machine/pcb.h> 52 #include <machine/trap.h> 53 #include <machine/pmap.h> 54 #include <machine/cpu.h> 55 56 #ifdef DDB 57 #include <machine/db_machdep.h> 58 #endif 59 #include <kern/syscalls.c> 60 #ifdef KTRACE 61 #include <sys/ktrace.h> 62 #endif 63 64 #ifdef TRAPDEBUG 65 volatile int startsysc = 0, faultdebug = 0; 66 #endif 67 68 void arithflt __P((struct trapframe *)); 69 void syscall __P((struct trapframe *)); 70 void stray __P((int, int)); 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, type = frame->trap, trapsig = 1; 109 u_int rv, addr, umode; 110 struct proc *p = curproc; 111 struct pmap *pm; 112 u_quad_t oticks = 0; 113 vm_map_t map; 114 vm_prot_t ftype; 115 extern vm_map_t pte_map; 116 117 if ((umode = USERMODE(frame))) { 118 type |= T_USER; 119 oticks = p->p_sticks; 120 p->p_addr->u_pcb.framep = frame; 121 } 122 123 type&=~(T_WRITE|T_PTEFETCH); 124 125 126 #ifdef TRAPDEBUG 127 if(frame->trap==7) goto fram; 128 if(faultdebug)printf("Trap: type %x, code %x, pc %x, psl %x\n", 129 frame->trap, frame->code, frame->pc, frame->psl); 130 fram: 131 #endif 132 switch(type){ 133 134 default: 135 #ifdef DDB 136 kdb_trap(frame); 137 #endif 138 printf("Trap: type %x, code %x, pc %x, psl %x\n", 139 (u_int)frame->trap, (u_int)frame->code, 140 (u_int)frame->pc, (u_int)frame->psl); 141 panic("trap"); 142 143 case T_KSPNOTVAL: 144 panic("kernel stack invalid"); 145 146 case T_TRANSFLT|T_USER: 147 case T_TRANSFLT: 148 /* 149 * BUG! BUG! BUG! BUG! BUG! 150 * Due to a hardware bug (at in least KA65x CPUs) a double 151 * page table fetch trap will cause a translation fault 152 * even if access in the SPT PTE entry specifies 'no access'. 153 * In for example section 6.4.2 in VAX Architecture 154 * Reference Manual it states that if a page both are invalid 155 * and have no access set, a 'access violation fault' occurs. 156 * Therefore, we must fall through here... 157 */ 158 #ifdef nohwbug 159 panic("translation fault"); 160 #endif 161 case T_ACCFLT|T_USER: 162 if (frame->code < 0) { /* Check for kernel space */ 163 sig = SIGSEGV; 164 break; 165 } 166 case T_ACCFLT: 167 #ifdef TRAPDEBUG 168 if(faultdebug)printf("trap accflt type %x, code %x, pc %x, psl %x\n", 169 frame->trap, frame->code, frame->pc, frame->psl); 170 #endif 171 #ifdef DIAGNOSTIC 172 if (p == 0) 173 panic("trap: access fault without process"); 174 #endif 175 /* 176 * First check for ptefetch. Can only happen to pages 177 * in user space. 178 */ 179 if (frame->trap & T_PTEFETCH) { 180 pm = p->p_vmspace->vm_map.pmap; 181 if (frame->code < 0x40000000) { 182 addr = trunc_page((unsigned)&pm->pm_p0br[ 183 frame->code >> PGSHIFT]); 184 #ifdef DEBUG 185 } else if (frame->code < 0) { 186 panic("ptefetch in kernel"); 187 #endif 188 } else { 189 addr = trunc_page((unsigned)&pm->pm_p1br[ 190 (frame->code & 0x3fffffff) >> PGSHIFT]); 191 } 192 rv = vm_fault(pte_map, addr, 193 VM_PROT_WRITE|VM_PROT_READ, FALSE); 194 if (rv != KERN_SUCCESS) { 195 sig = SIGSEGV; 196 break; 197 } else 198 trapsig = 0; 199 } 200 addr = trunc_page(frame->code); 201 if ((umode == 0) && (frame->code < 0)) 202 map = kernel_map; 203 else 204 map = &p->p_vmspace->vm_map; 205 206 if (frame->trap & T_WRITE) 207 ftype = VM_PROT_WRITE|VM_PROT_READ; 208 else 209 ftype = VM_PROT_READ; 210 211 rv = vm_fault(map, addr, ftype, FALSE); 212 if (rv != KERN_SUCCESS) { 213 if (umode == 0) { 214 FAULTCHK; 215 panic("Segv in kernel mode: pc %x addr %x", 216 (u_int)frame->pc, (u_int)frame->code); 217 } 218 sig = SIGSEGV; 219 } else 220 trapsig = 0; 221 break; 222 223 case T_PTELEN: 224 FAULTCHK; 225 panic("ptelen fault in system space"); 226 227 case T_PTELEN|T_USER: /* Page table length exceeded */ 228 sig = SIGSEGV; 229 break; 230 231 case T_BPTFLT|T_USER: 232 case T_TRCTRAP|T_USER: 233 sig = SIGTRAP; 234 frame->psl &= ~PSL_T; 235 break; 236 237 case T_PRIVINFLT|T_USER: 238 case T_RESADFLT|T_USER: 239 case T_RESOPFLT|T_USER: 240 sig = SIGILL; 241 break; 242 243 case T_XFCFLT|T_USER: 244 sig = SIGEMT; 245 break; 246 247 case T_ARITHFLT|T_USER: 248 sig = SIGFPE; 249 break; 250 251 case T_ASTFLT|T_USER: 252 mtpr(AST_NO,PR_ASTLVL); 253 trapsig = 0; 254 break; 255 256 #ifdef DDB 257 case T_KDBTRAP: 258 kdb_trap(frame); 259 return; 260 #endif 261 } 262 263 if (trapsig) 264 trapsignal(p, sig, frame->code); 265 266 if (umode == 0) 267 return; 268 269 while ((sig = CURSIG(p)) !=0) 270 postsig(sig); 271 p->p_priority = p->p_usrpri; 272 if (want_resched) { 273 /* 274 * Since we are curproc, clock will normally just change 275 * our priority without moving us from one queue to another 276 * (since the running process is not on a queue.) 277 * If that happened after we setrunqueue ourselves but before 278 * we swtch()'ed, we might not be on the queue indicated by 279 * our priority. 280 */ 281 splstatclock(); 282 setrunqueue(p); 283 mi_switch(); 284 while ((sig = CURSIG(p)) != 0) 285 postsig(sig); 286 } 287 if (p->p_flag & P_PROFIL) { 288 extern int psratio; 289 addupc_task(p, frame->pc, (int)(p->p_sticks-oticks) * psratio); 290 } 291 curpriority = p->p_priority; 292 } 293 294 void 295 setregs(p, pack, stack) 296 struct proc *p; 297 struct exec_package *pack; 298 u_long stack; 299 { 300 struct trapframe *exptr; 301 302 exptr = p->p_addr->u_pcb.framep; 303 exptr->pc = pack->ep_entry + 2; 304 exptr->sp = stack; 305 } 306 307 void 308 syscall(frame) 309 struct trapframe *frame; 310 { 311 struct sysent *callp; 312 u_quad_t oticks; 313 int nsys, sig; 314 int err, rval[2], args[8]; 315 struct trapframe *exptr; 316 struct proc *p = curproc; 317 318 #ifdef TRAPDEBUG 319 if(startsysc)printf("trap syscall %s pc %x, psl %x, sp %x, pid %d, frame %x\n", 320 syscallnames[frame->code], frame->pc, frame->psl,frame->sp, 321 curproc->p_pid,frame); 322 #endif 323 324 exptr = p->p_addr->u_pcb.framep = frame; 325 callp = p->p_emul->e_sysent; 326 nsys = p->p_emul->e_nsysent; 327 oticks = p->p_sticks; 328 329 if(frame->code == SYS___syscall){ 330 int g = *(int *)(frame->ap); 331 332 frame->code = *(int *)(frame->ap + 4); 333 frame->ap += 8; 334 *(int *)(frame->ap) = g - 2; 335 } 336 337 if(frame->code < 0 || frame->code >= nsys) 338 callp += p->p_emul->e_nosys; 339 else 340 callp += frame->code; 341 342 rval[0] = 0; 343 rval[1] = frame->r1; 344 if(callp->sy_narg) { 345 err = copyin((char*)frame->ap + 4, args, callp->sy_argsize); 346 if (err) { 347 #ifdef KTRACE 348 if (KTRPOINT(p, KTR_SYSCALL)) 349 ktrsyscall(p->p_tracep, frame->code, 350 callp->sy_argsize, args); 351 #endif 352 goto bad; 353 } 354 } 355 #ifdef KTRACE 356 if (KTRPOINT(p, KTR_SYSCALL)) 357 ktrsyscall(p->p_tracep, frame->code, callp->sy_argsize, args); 358 #endif 359 err = (*callp->sy_call)(curproc, args, rval); 360 exptr = curproc->p_addr->u_pcb.framep; 361 362 #ifdef TRAPDEBUG 363 if(startsysc) 364 printf("retur %s pc %x, psl %x, sp %x, pid %d, v{rde %d r0 %d, r1 %d, frame %x\n", 365 syscallnames[exptr->code], exptr->pc, exptr->psl,exptr->sp, 366 curproc->p_pid,err,rval[0],rval[1],exptr); 367 #endif 368 369 bad: 370 switch (err) { 371 case 0: 372 exptr->r1 = rval[1]; 373 exptr->r0 = rval[0]; 374 exptr->psl &= ~PSL_C; 375 break; 376 377 case EJUSTRETURN: 378 return; 379 380 case ERESTART: 381 exptr->pc -= (exptr->code > 63 ? 4 : 2); 382 break; 383 384 default: 385 exptr->r0 = err; 386 exptr->psl |= PSL_C; 387 break; 388 } 389 p = curproc; 390 while ((sig = CURSIG(p)) !=0) 391 postsig(sig); 392 p->p_priority = p->p_usrpri; 393 if (want_resched) { 394 /* 395 * Since we are curproc, clock will normally just change 396 * our priority without moving us from one queue to another 397 * (since the running process is not on a queue.) 398 * If that happened after we setrunqueue ourselves but before 399 * we swtch()'ed, we might not be on the queue indicated by 400 * our priority. 401 */ 402 splstatclock(); 403 setrunqueue(p); 404 mi_switch(); 405 while ((sig = CURSIG(p)) != 0) 406 postsig(sig); 407 } 408 if (p->p_flag & P_PROFIL) { 409 extern int psratio; 410 addupc_task(p, frame->pc, (int)(p->p_sticks-oticks) * psratio); 411 } 412 #ifdef KTRACE 413 if (KTRPOINT(p, KTR_SYSRET)) 414 ktrsysret(p->p_tracep, frame->code, err, rval[0]); 415 #endif 416 } 417 418 void 419 stray(scb, vec) 420 int scb, vec; 421 { 422 printf("stray interrupt scb %d, vec 0x%x\n", scb, vec); 423 } 424