1 /* $NetBSD: trap.c,v 1.30 1997/10/19 12:32:52 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 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 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 extern int want_resched,whichqs; 65 #ifdef TRAPDEBUG 66 volatile int startsysc=0,faultdebug=0; 67 #endif 68 69 static void userret __P((struct proc *, u_int, u_int)); 70 void arithflt __P((struct trapframe *)); 71 void syscall __P((struct trapframe *)); 72 void showregs __P((struct trapframe *)); 73 void stray __P((int, int)); 74 75 void 76 userret(p, pc, psl) 77 struct proc *p; 78 u_int pc, psl; 79 { 80 int s,sig; 81 82 while ((sig = CURSIG(p)) !=0) 83 postsig(sig); 84 p->p_priority = p->p_usrpri; 85 if (want_resched) { 86 /* 87 * Since we are curproc, clock will normally just change 88 * our priority without moving us from one queue to another 89 * (since the running process is not on a queue.) 90 * If that happened after we setrunqueue ourselves but before 91 * we swtch()'ed, we might not be on the queue indicated by 92 * our priority. 93 */ 94 s=splstatclock(); 95 setrunqueue(curproc); 96 mi_switch(); 97 splx(s); 98 while ((sig = CURSIG(curproc)) != 0) 99 postsig(sig); 100 } 101 102 curpriority = curproc->p_priority; 103 } 104 105 char *traptypes[]={ 106 "reserved addressing", 107 "privileged instruction", 108 "reserved operand", 109 "breakpoint instruction", 110 "XFC instruction", 111 "system call ", 112 "arithmetic trap", 113 "asynchronous system trap", 114 "page table length fault", 115 "translation violation fault", 116 "trace trap", 117 "compatibility mode fault", 118 "access violation fault", 119 "", 120 "", 121 "KSP invalid", 122 "", 123 "kernel debugger trap" 124 }; 125 int no_traps = 18; 126 127 #define USERMODE(framep) ((((framep)->psl) & (PSL_U)) == PSL_U) 128 #define FAULTCHK \ 129 if (p->p_addr->u_pcb.iftrap) { \ 130 frame->pc = (unsigned)p->p_addr->u_pcb.iftrap; \ 131 return; \ 132 } 133 134 void 135 arithflt(frame) 136 struct trapframe *frame; 137 { 138 u_int sig, type=frame->trap,trapsig=1,s; 139 u_int rv, addr, umode; 140 struct proc *p=curproc; 141 struct pmap *pm; 142 vm_map_t map; 143 vm_prot_t ftype; 144 extern vm_map_t pte_map; 145 146 if ((umode = USERMODE(frame))) { 147 type |= T_USER; 148 p->p_addr->u_pcb.framep = frame; 149 } 150 151 type&=~(T_WRITE|T_PTEFETCH); 152 153 154 #ifdef TRAPDEBUG 155 if(frame->trap==7) goto fram; 156 if(faultdebug)printf("Trap: type %x, code %x, pc %x, psl %x\n", 157 frame->trap, frame->code, frame->pc, frame->psl); 158 fram: 159 #endif 160 switch(type){ 161 162 default: 163 faulter: 164 #ifdef DDB 165 kdb_trap(frame); 166 #endif 167 printf("Trap: type %x, code %x, pc %x, psl %x\n", 168 frame->trap, frame->code, frame->pc, frame->psl); 169 showregs(frame); 170 panic("trap: adr %x",frame->code); 171 case T_KSPNOTVAL: 172 goto faulter; 173 174 case T_TRANSFLT|T_USER: 175 case T_TRANSFLT: /* Translation invalid - may be simul page ref */ 176 if(frame->trap&T_PTEFETCH){ 177 u_int *ptep, *pte, *pte1; 178 179 if(frame->code<0x40000000) 180 ptep=(u_int *)p->p_addr->u_pcb.P0BR; 181 else 182 ptep=(u_int *)p->p_addr->u_pcb.P1BR; 183 pte1=(u_int *)trunc_page(&ptep[(frame->code 184 &0x3fffffff)>>PGSHIFT]); 185 pte=(u_int*)&Sysmap[((u_int)pte1&0x3fffffff)>>PGSHIFT]; 186 if(*pte&PG_SREF){ /* Yes, simulated */ 187 s=splhigh(); 188 189 *pte|=PG_REF|PG_V;*pte&=~PG_SREF;pte++; 190 *pte|=PG_REF|PG_V;*pte&=~PG_SREF; 191 mtpr(0,PR_TBIA); 192 splx(s); 193 goto uret; 194 } 195 } else { 196 u_int *ptep, *pte; 197 198 frame->code = trunc_page(frame->code); 199 if ((u_int)frame->code < (u_int)0x40000000) { 200 ptep = (u_int *)p->p_addr->u_pcb.P0BR; 201 pte = &ptep[(frame->code >> PGSHIFT)]; 202 } else if ((u_int)frame->code > (u_int)0x7fffffff) { 203 pte = (u_int *)&Sysmap[((u_int)frame->code & 204 0x3fffffff) >> PGSHIFT]; 205 } else { 206 ptep = (u_int *)p->p_addr->u_pcb.P1BR; 207 pte = &ptep[(frame->code&0x3fffffff)>>PGSHIFT]; 208 } 209 if (*pte & PG_SREF) { 210 s = splhigh(); 211 *pte|=PG_REF|PG_V;*pte&=~PG_SREF;pte++; 212 *pte|=PG_REF|PG_V;*pte&=~PG_SREF; 213 /* mtpr(frame->code,PR_TBIS); */ 214 /* mtpr(frame->code+NBPG,PR_TBIS); */ 215 mtpr(0,PR_TBIA); 216 splx(s); 217 goto uret; 218 } 219 } 220 /* Fall into... */ 221 case T_ACCFLT: 222 case T_ACCFLT|T_USER: 223 #ifdef TRAPDEBUG 224 if(faultdebug)printf("trap accflt type %x, code %x, pc %x, psl %x\n", 225 frame->trap, frame->code, frame->pc, frame->psl); 226 #endif 227 if (!p) 228 panic("trap: access fault without process"); 229 pm = p->p_vmspace->vm_map.pmap; 230 if(frame->trap&T_PTEFETCH){ 231 u_int faultaddr,testaddr=(u_int)frame->code&0x3fffffff; 232 int P0 = 0, P1 = 0, SYS = 0; 233 234 if (frame->code == testaddr) 235 P0++; 236 else if ((u_int)frame->code > (u_int)0x7fffffff) 237 SYS++; 238 else 239 P1++; 240 241 if (P0) { 242 faultaddr = (u_int)pm->pm_pcb->P0BR + 243 ((testaddr >> PGSHIFT) << 2); 244 } else if (P1) { 245 faultaddr= (u_int)pm->pm_pcb->P1BR + 246 ((testaddr >> PGSHIFT) << 2); 247 } else 248 panic("pageflt: PTE fault in SPT\n"); 249 250 faultaddr &= ~PAGE_MASK; 251 rv = vm_fault(pte_map, faultaddr, 252 VM_PROT_WRITE|VM_PROT_READ, FALSE); 253 if (rv != KERN_SUCCESS) { 254 255 sig = SIGSEGV; 256 goto bad; 257 } else 258 trapsig = 0; 259 } 260 addr=(frame->code& ~PAGE_MASK); 261 if ((umode == 0) && (frame->code < 0)) { 262 map=kernel_map; 263 } else { 264 map= &p->p_vmspace->vm_map; 265 } 266 if(frame->trap&T_WRITE) ftype=VM_PROT_WRITE|VM_PROT_READ; 267 else ftype = VM_PROT_READ; 268 269 rv = vm_fault(map, addr, ftype, FALSE); 270 if (rv != KERN_SUCCESS) { 271 if (umode == 0) { 272 FAULTCHK; 273 panic("Segv in kernel mode: rv %d\n",rv); 274 } 275 sig=SIGSEGV; 276 } else 277 trapsig=0; 278 break; 279 280 case T_PTELEN: 281 case T_PTELEN|T_USER: /* Page table length exceeded */ 282 pm = p->p_vmspace->vm_map.pmap; 283 #ifdef TRAPDEBUG 284 if(faultdebug)printf("trap ptelen type %x, code %x, pc %x, psl %x\n", 285 frame->trap, frame->code, frame->pc, frame->psl); 286 #endif 287 if ((u_int)frame->code < (u_int)0x40000000) { /* P0 */ 288 int i; 289 290 if (p->p_vmspace == 0){ 291 printf("no vmspace in fault\n"); 292 goto faulter; 293 } 294 i = p->p_vmspace->vm_tsize + p->p_vmspace->vm_dsize; 295 if (i > (frame->code >> PAGE_SHIFT)){ 296 pmap_expandp0(pm, i << 1); 297 trapsig = 0; 298 } else { 299 FAULTCHK; 300 sig = SIGSEGV; 301 } 302 } else if ((u_int)frame->code > (u_int)0x7fffffff){ /* System, segv */ 303 FAULTCHK; 304 if (umode == 0) 305 panic("ptelen"); 306 sig = SIGSEGV; 307 } else { /* P1 */ 308 int i; 309 310 i = (u_int)(p->p_vmspace->vm_maxsaddr); 311 if (frame->code < i){ 312 FAULTCHK; 313 sig = SIGSEGV; 314 } else { 315 pmap_expandp1(pm); 316 trapsig = 0; 317 } 318 } 319 break; 320 321 case T_BPTFLT|T_USER: 322 case T_TRCTRAP|T_USER: 323 sig = SIGTRAP; 324 frame->psl &= ~PSL_T; 325 break; 326 327 case T_PRIVINFLT|T_USER: 328 case T_RESADFLT|T_USER: 329 case T_RESOPFLT|T_USER: 330 sig=SIGILL; 331 break; 332 333 case T_XFCFLT|T_USER: 334 sig = SIGEMT; 335 break; 336 337 case T_ARITHFLT|T_USER: 338 sig=SIGFPE; 339 break; 340 341 case T_ASTFLT|T_USER: 342 mtpr(AST_NO,PR_ASTLVL); 343 trapsig=0; 344 break; 345 346 #ifdef DDB 347 case T_KDBTRAP: 348 kdb_trap(frame); 349 return; 350 #endif 351 } 352 bad: 353 if (trapsig) 354 trapsignal(curproc, sig, frame->code); 355 uret: 356 if (umode) 357 userret(curproc, frame->pc, frame->psl); 358 }; 359 360 void 361 setregs(p, pack, stack) 362 struct proc *p; 363 struct exec_package *pack; 364 u_long stack; 365 { 366 struct trapframe *exptr; 367 368 exptr = p->p_addr->u_pcb.framep; 369 exptr->pc = pack->ep_entry + 2; 370 exptr->sp = stack; 371 } 372 373 void 374 syscall(frame) 375 struct trapframe *frame; 376 { 377 struct sysent *callp; 378 int nsys; 379 int err, rval[2], args[8]; 380 struct trapframe *exptr; 381 struct proc *p = curproc; 382 383 #ifdef TRAPDEBUG 384 if(startsysc)printf("trap syscall %s pc %x, psl %x, sp %x, pid %d, frame %x\n", 385 syscallnames[frame->code], frame->pc, frame->psl,frame->sp, 386 curproc->p_pid,frame); 387 #endif 388 389 exptr = p->p_addr->u_pcb.framep = frame; 390 callp = p->p_emul->e_sysent; 391 nsys = p->p_emul->e_nsysent; 392 393 if(frame->code == SYS___syscall){ 394 int g = *(int *)(frame->ap); 395 396 frame->code=*(int *)(frame->ap+4); 397 frame->ap+=8; 398 *(int *)(frame->ap)=g-2; 399 } 400 401 if(frame->code<0||frame->code>=nsys) 402 callp += p->p_emul->e_nosys; 403 else 404 callp += frame->code; 405 406 rval[0]=0; 407 rval[1]=frame->r1; 408 if(callp->sy_narg) { 409 err = copyin((char*)frame->ap+4, args, callp->sy_argsize); 410 if (err) { 411 #ifdef KTRACE 412 if (KTRPOINT(p, KTR_SYSCALL)) 413 ktrsyscall(p->p_tracep, frame->code, 414 callp->sy_argsize, args); 415 #endif 416 goto bad; 417 } 418 } 419 #ifdef KTRACE 420 if (KTRPOINT(p, KTR_SYSCALL)) 421 ktrsyscall(p->p_tracep, frame->code, callp->sy_argsize, args); 422 #endif 423 err=(*callp->sy_call)(curproc,args,rval); 424 exptr = curproc->p_addr->u_pcb.framep; 425 426 #ifdef TRAPDEBUG 427 if(startsysc) 428 printf("retur %s pc %x, psl %x, sp %x, pid %d, v{rde %d r0 %d, r1 %d, frame %x\n", 429 syscallnames[exptr->code], exptr->pc, exptr->psl,exptr->sp, 430 curproc->p_pid,err,rval[0],rval[1],exptr); 431 #endif 432 433 bad: 434 switch (err) { 435 case 0: 436 exptr->r1 = rval[1]; 437 exptr->r0 = rval[0]; 438 exptr->psl &= ~PSL_C; 439 break; 440 441 case EJUSTRETURN: 442 return; 443 444 case ERESTART: 445 exptr->pc -= (exptr->code > 63 ? 4 : 2); 446 break; 447 448 default: 449 exptr->r0 = err; 450 exptr->psl |= PSL_C; 451 break; 452 } 453 userret(curproc, exptr->pc, exptr->psl); 454 #ifdef KTRACE 455 if (KTRPOINT(p, KTR_SYSRET)) 456 ktrsysret(p->p_tracep, frame->code, err, rval[0]); 457 #endif 458 } 459 460 void 461 stray(scb, vec) 462 int scb, vec; 463 { 464 printf("stray interrupt scb %d, vec 0x%x\n", scb, vec); 465 } 466 467 void 468 showregs(frame) 469 struct trapframe *frame; 470 { 471 printf("P0BR %8x P1BR %8x P0LR %8x P1LR %8x\n", 472 mfpr(PR_P0BR), mfpr(PR_P1BR), mfpr(PR_P0LR), mfpr(PR_P1LR)); 473 printf("KSP %8x ISP %8x USP %8x\n", 474 mfpr(PR_KSP), mfpr(PR_ISP), mfpr(PR_USP)); 475 printf("R0 %8x R1 %8x R2 %8x R3 %8x\n", 476 frame->r0, frame->r1, frame->r2, frame->r3); 477 printf("R4 %8x R5 %8x R6 %8x R7 %8x\n", 478 frame->r4, frame->r5, frame->r6, frame->r7); 479 printf("R8 %8x R9 %8x R10 %8x R11 %8x\n", 480 frame->r8, frame->r9, frame->r10, frame->r11); 481 printf("FP %8x AP %8x PC %8x PSL %8x\n", 482 frame->fp, frame->ap, frame->pc, frame->psl); 483 } 484