trap.c revision 77957
1/* 2 * Copyright (C) 1995, 1996 Wolfgang Solfrank. 3 * Copyright (C) 1995, 1996 TooLs GmbH. 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 by TooLs GmbH. 17 * 4. The name of TooLs GmbH 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 TOOLS GMBH ``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 TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 26 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 27 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 28 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 29 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 * 31 * $NetBSD: trap.c,v 1.26 2000/05/27 00:40:40 sommerfeld Exp $ 32 */ 33 34#ifndef lint 35static const char rcsid[] = 36 "$FreeBSD: head/sys/powerpc/aim/trap.c 77957 2001-06-10 02:39:37Z benno $"; 37#endif /* not lint */ 38 39#include "opt_ddb.h" 40#include "opt_ktrace.h" 41 42#include <sys/param.h> 43#include <sys/proc.h> 44#include <sys/reboot.h> 45#include <sys/syscall.h> 46#include <sys/systm.h> 47#include <sys/uio.h> 48#include <sys/user.h> 49#include <sys/ktrace.h> 50 51#include <vm/vm.h> 52#include <vm/vm_kern.h> 53#include <vm/pmap.h> 54 55#include <machine/cpu.h> 56#include <machine/frame.h> 57#include <machine/pcb.h> 58#include <machine/psl.h> 59#include <machine/trap.h> 60 61/* These definitions should probably be somewhere else XXX */ 62#define FIRSTARG 3 /* first argument is in reg 3 */ 63#define NARGREG 8 /* 8 args are in registers */ 64#define MOREARGS(sp) ((caddr_t)((int)(sp) + 8)) /* more args go here */ 65 66volatile int astpending; 67volatile int want_resched; 68 69#if 0 /* XXX: not used yet */ 70static int fix_unaligned __P((struct proc *p, struct trapframe *frame)); 71#endif 72 73void 74trap(struct trapframe *frame) 75{ 76#if 0 /* XXX: This code hasn't been reworked yet. */ 77 struct proc *p; 78 int type; 79 u_quad_t sticks; 80 81 p = curproc; 82 type = frame->exc; 83 84 if (frame->srr1 & PSL_PR) { 85 type |= EXC_USER; 86 sticks = p->p_sticks; 87 } 88 89 switch (type) { 90 case EXC_TRC|EXC_USER: 91 frame->srr1 &= ~PSL_SE; 92 trapsignal(p, SIGTRAP, EXC_TRC); 93 break; 94 case EXC_DSI: 95 { 96 vm_map_t map; 97 vaddr_t va; 98 int ftype; 99 faultbuf *fb; 100 101 map = kernel_map; 102 va = frame->dar; 103 if ((va >> ADDR_SR_SHFT) == USER_SR) { 104 sr_t user_sr; 105 106 __asm ("mfsr %0, %1" 107 : "=r"(user_sr) : "K"(USER_SR)); 108 va &= ADDR_PIDX | ADDR_POFF; 109 va |= user_sr << ADDR_SR_SHFT; 110 map = &p->p_vmspace->vm_map; 111 } 112 if (frame->dsisr & DSISR_STORE) 113 ftype = VM_PROT_READ | VM_PROT_WRITE; 114 else 115 ftype = VM_PROT_READ; 116 if (uvm_fault(map, trunc_page(va), 0, ftype) 117 == KERN_SUCCESS) 118 return; 119 if (fb = p->p_addr->u_pcb.pcb_onfault) { 120 frame->srr0 = (*fb)[0]; 121 frame->fixreg[1] = (*fb)[1]; 122 frame->fixreg[2] = (*fb)[2]; 123 frame->cr = (*fb)[3]; 124 bcopy(&(*fb)[4], &frame->fixreg[13], 125 19 * sizeof(register_t)); 126 return; 127 } 128 map = kernel_map; 129 } 130 goto brain_damage; 131 case EXC_DSI|EXC_USER: 132 { 133 int ftype, rv; 134 135 if (frame->dsisr & DSISR_STORE) 136 ftype = VM_PROT_READ | VM_PROT_WRITE; 137 else 138 ftype = VM_PROT_READ; 139 if ((rv = uvm_fault(&p->p_vmspace->vm_map, 140 trunc_page(frame->dar), 0, ftype)) 141 == KERN_SUCCESS) 142 break; 143 if (rv == KERN_RESOURCE_SHORTAGE) { 144 printf("UVM: pid %d (%s), uid %d killed: " 145 "out of swap\n", 146 p->p_pid, p->p_comm, 147 p->p_cred && p->p_ucred ? 148 p->p_ucred->cr_uid : -1); 149 trapsignal(p, SIGKILL, EXC_DSI); 150 } else { 151 trapsignal(p, SIGSEGV, EXC_DSI); 152 } 153 } 154 break; 155 case EXC_ISI|EXC_USER: 156 { 157 int ftype; 158 159 ftype = VM_PROT_READ | VM_PROT_EXECUTE; 160 if (uvm_fault(&p->p_vmspace->vm_map, 161 trunc_page(frame->srr0), 0, ftype) 162 == KERN_SUCCESS) 163 break; 164 } 165 trapsignal(p, SIGSEGV, EXC_ISI); 166 break; 167 case EXC_SC|EXC_USER: 168 { 169 struct sysent *callp; 170 size_t argsize; 171 register_t code, error; 172 register_t *params, rval[2]; 173 int nsys, n; 174 register_t args[10]; 175 176 uvmexp.syscalls++; 177 178 nsys = p->p_emul->e_nsysent; 179 callp = p->p_emul->e_sysent; 180 181 code = frame->fixreg[0]; 182 params = frame->fixreg + FIRSTARG; 183 184 switch (code) { 185 case SYS_syscall: 186 /* 187 * code is first argument, 188 * followed by actual args. 189 */ 190 code = *params++; 191 break; 192 case SYS___syscall: 193 /* 194 * Like syscall, but code is a quad, 195 * so as to maintain quad alignment 196 * for the rest of the args. 197 */ 198 if (callp != sysent) 199 break; 200 params++; 201 code = *params++; 202 break; 203 default: 204 break; 205 } 206 if (code < 0 || code >= nsys) 207 callp += p->p_emul->e_nosys; 208 else 209 callp += code; 210 argsize = callp->sy_argsize; 211 n = NARGREG - (params - (frame->fixreg + FIRSTARG)); 212 if (argsize > n * sizeof(register_t)) { 213 bcopy(params, args, n * sizeof(register_t)); 214 if (error = copyin(MOREARGS(frame->fixreg[1]), 215 args + n, 216 argsize - n * sizeof(register_t))) { 217#ifdef KTRACE 218 /* Can't get all the arguments! */ 219 if (KTRPOINT(p, KTR_SYSCALL)) 220 ktrsyscall(p, code, argsize, 221 args); 222#endif 223 goto syscall_bad; 224 } 225 params = args; 226 } 227#ifdef KTRACE 228 if (KTRPOINT(p, KTR_SYSCALL)) 229 ktrsyscall(p, code, argsize, params); 230#endif 231 rval[0] = 0; 232 rval[1] = frame->fixreg[FIRSTARG + 1]; 233 234 switch (error = (*callp->sy_call)(p, params, rval)) { 235 case 0: 236 frame->fixreg[FIRSTARG] = rval[0]; 237 frame->fixreg[FIRSTARG + 1] = rval[1]; 238 frame->cr &= ~0x10000000; 239 break; 240 case ERESTART: 241 /* 242 * Set user's pc back to redo the system call. 243 */ 244 frame->srr0 -= 4; 245 break; 246 case EJUSTRETURN: 247 /* nothing to do */ 248 break; 249 default: 250syscall_bad: 251 if (p->p_emul->e_errno) 252 error = p->p_emul->e_errno[error]; 253 frame->fixreg[FIRSTARG] = error; 254 frame->cr |= 0x10000000; 255 break; 256 } 257#ifdef KTRACE 258 if (KTRPOINT(p, KTR_SYSRET)) 259 ktrsysret(p, code, error, rval[0]); 260#endif 261 } 262 break; 263 264 case EXC_FPU|EXC_USER: 265 if (fpuproc) 266 save_fpu(fpuproc); 267 fpuproc = p; 268 enable_fpu(p); 269 break; 270 271 case EXC_AST|EXC_USER: 272 /* This is just here that we trap */ 273 break; 274 275 case EXC_ALI|EXC_USER: 276 if (fix_unaligned(p, frame) != 0) 277 trapsignal(p, SIGBUS, EXC_ALI); 278 else 279 frame->srr0 += 4; 280 break; 281 282 case EXC_PGM|EXC_USER: 283/* XXX temporarily */ 284 if (frame->srr1 & 0x0002000) 285 trapsignal(p, SIGTRAP, EXC_PGM); 286 else 287 trapsignal(p, SIGILL, EXC_PGM); 288 break; 289 290 case EXC_MCHK: 291 { 292 faultbuf *fb; 293 294 if (fb = p->p_addr->u_pcb.pcb_onfault) { 295 frame->srr0 = (*fb)[0]; 296 frame->fixreg[1] = (*fb)[1]; 297 frame->fixreg[2] = (*fb)[2]; 298 frame->cr = (*fb)[3]; 299 bcopy(&(*fb)[4], &frame->fixreg[13], 300 19 * sizeof(register_t)); 301 return; 302 } 303 } 304 goto brain_damage; 305 306 default: 307brain_damage: 308 printf("trap type %x at %x\n", type, frame->srr0); 309#ifdef DDB 310 Debugger(); /* XXX temporarily */ 311#endif 312#ifdef TRAP_PANICWAIT 313 printf("Press a key to panic.\n"); 314 cngetc(); 315#endif 316 panic("trap"); 317 } 318 319 astpending = 0; /* we are about to do it */ 320 321 uvmexp.softs++; 322 323 if (p->p_flag & P_OWEUPC) { 324 p->p_flag &= ~P_OWEUPC; 325 ADDUPROF(p); 326 } 327 328 /* take pending signals */ 329 { 330 int sig; 331 332 while (sig = CURSIG(p)) 333 postsig(sig); 334 } 335 336 p->p_priority = p->p_usrpri; 337 if (want_resched) { 338 int sig; 339 /* 340 * We are being preempted. 341 */ 342 preempt(NULL); 343 while (sig = CURSIG(p)) 344 postsig(sig); 345 } 346 347 /* 348 * If profiling, charge recent system time to the trapped pc. 349 */ 350 if (p->p_flag & P_PROFIL) { 351 extern int psratio; 352 353 addupc_task(p, frame->srr0, 354 (int)(p->p_sticks - sticks) * psratio); 355 } 356 /* 357 * If someone stole the fpu while we were away, disable it 358 */ 359 if (p != fpuproc) 360 frame->srr1 &= ~PSL_FP; 361 curcpu()->ci_schedstate.spc_curpriority = p->p_priority; 362#endif 363} 364 365#if 0 /* XXX: child_return not used */ 366void 367child_return(void *arg) 368{ 369 struct proc *p; 370 struct trapframe *tf; 371 372 p = arg; 373 tf = trapframe(p); 374 375 tf->fixreg[FIRSTARG] = 0; 376 tf->fixreg[FIRSTARG + 1] = 1; 377 tf->cr &= ~0x10000000; 378 tf->srr1 &= ~PSL_FP; /* Disable FPU, as we can't be fpuproc */ 379#ifdef KTRACE 380 if (KTRPOINT(p, KTR_SYSRET)) 381 ktrsysret(p, SYS_fork, 0, 0); 382#endif 383 /* Profiling? XXX */ 384 curcpu()->ci_schedstate.spc_curpriority = p->p_priority; 385} 386#endif 387 388static __inline void 389setusr(int content) 390{ 391 392 __asm __volatile ("isync; mtsr %0,%1; isync" 393 :: "n"(USER_SR), "r"(content)); 394} 395 396int 397copyin(udaddr, kaddr, len) 398 const void *udaddr; 399 void *kaddr; 400 size_t len; 401{ 402 const char *up; 403 char *kp; 404 char *p; 405 size_t l; 406 faultbuf env; 407 408 up = udaddr; 409 kp = kaddr; 410 411#if 0 412 if (setfault(env)) { 413 curpcb->pcb_onfault = 0; 414 return EFAULT; 415 } 416#endif 417 while (len > 0) { 418 p = (char *)USER_ADDR + ((u_int)up & ~SEGMENT_MASK); 419 l = ((char *)USER_ADDR + SEGMENT_LENGTH) - p; 420 if (l > len) 421 l = len; 422 setusr(curpcb->pcb_pm->pm_sr[(u_int)up >> ADDR_SR_SHFT]); 423 bcopy(p, kp, l); 424 up += l; 425 kp += l; 426 len -= l; 427 } 428 curpcb->pcb_onfault = 0; 429 return 0; 430} 431 432int 433copyout(kaddr, udaddr, len) 434 const void *kaddr; 435 void *udaddr; 436 size_t len; 437{ 438 const char *kp; 439 char *up; 440 char *p; 441 size_t l; 442 faultbuf env; 443 444 kp = kaddr; 445 up = udaddr; 446 447#if 0 448 if (setfault(env)) { 449 curpcb->pcb_onfault = 0; 450 return EFAULT; 451 } 452#endif 453 while (len > 0) { 454 p = (char *)USER_ADDR + ((u_int)up & ~SEGMENT_MASK); 455 l = ((char *)USER_ADDR + SEGMENT_LENGTH) - p; 456 if (l > len) 457 l = len; 458 setusr(curpcb->pcb_pm->pm_sr[(u_int)up >> ADDR_SR_SHFT]); 459 bcopy(kp, p, l); 460 up += l; 461 kp += l; 462 len -= l; 463 } 464 curpcb->pcb_onfault = 0; 465 return 0; 466} 467 468#if 0 /* XXX: not used yet */ 469/* 470 * kcopy(const void *src, void *dst, size_t len); 471 * 472 * Copy len bytes from src to dst, aborting if we encounter a fatal 473 * page fault. 474 * 475 * kcopy() _must_ save and restore the old fault handler since it is 476 * called by uiomove(), which may be in the path of servicing a non-fatal 477 * page fault. 478 */ 479int 480kcopy(const void *src, void *dst, size_t len) 481{ 482 faultbuf env, *oldfault; 483 484 oldfault = curpcb->pcb_onfault; 485 if (setfault(env)) { 486 curpcb->pcb_onfault = oldfault; 487 return EFAULT; 488 } 489 490 bcopy(src, dst, len); 491 492 curpcb->pcb_onfault = oldfault; 493 return 0; 494} 495 496int 497badaddr(void *addr, size_t size) 498{ 499 500 return badaddr_read(addr, size, NULL); 501} 502 503int 504badaddr_read(void *addr, size_t size, int *rptr) 505{ 506 faultbuf env; 507 int x; 508 509 /* Get rid of any stale machine checks that have been waiting. */ 510 __asm __volatile ("sync; isync"); 511 512 if (setfault(env)) { 513 curpcb->pcb_onfault = 0; 514 __asm __volatile ("sync"); 515 return 1; 516 } 517 518 __asm __volatile ("sync"); 519 520 switch (size) { 521 case 1: 522 x = *(volatile int8_t *)addr; 523 break; 524 case 2: 525 x = *(volatile int16_t *)addr; 526 break; 527 case 4: 528 x = *(volatile int32_t *)addr; 529 break; 530 default: 531 panic("badaddr: invalid size (%d)", size); 532 } 533 534 /* Make sure we took the machine check, if we caused one. */ 535 __asm __volatile ("sync; isync"); 536 537 curpcb->pcb_onfault = 0; 538 __asm __volatile ("sync"); /* To be sure. */ 539 540 /* Use the value to avoid reorder. */ 541 if (rptr) 542 *rptr = x; 543 544 return 0; 545} 546#endif 547 548/* 549 * For now, this only deals with the particular unaligned access case 550 * that gcc tends to generate. Eventually it should handle all of the 551 * possibilities that can happen on a 32-bit PowerPC in big-endian mode. 552 */ 553 554#if 0 /* XXX: Not used yet */ 555static int 556fix_unaligned(p, frame) 557 struct proc *p; 558 struct trapframe *frame; 559{ 560 int indicator; 561 562 indicator = EXC_ALI_OPCODE_INDICATOR(frame->dsisr); 563 564 switch (indicator) { 565 case EXC_ALI_LFD: 566 case EXC_ALI_STFD: 567 { 568 int reg = EXC_ALI_RST(frame->dsisr); 569 double *fpr = &p->p_addr->u_pcb.pcb_fpu.fpr[reg]; 570 571 /* Juggle the FPU to ensure that we've initialized 572 * the FPRs, and that their current state is in 573 * the PCB. 574 */ 575 if (fpuproc != p) { 576 if (fpuproc) 577 save_fpu(fpuproc); 578 enable_fpu(p); 579 } 580 save_fpu(p); 581 582 if (indicator == EXC_ALI_LFD) { 583 if (copyin((void *)frame->dar, fpr, 584 sizeof(double)) != 0) 585 return -1; 586 enable_fpu(p); 587 } else { 588 if (copyout(fpr, (void *)frame->dar, 589 sizeof(double)) != 0) 590 return -1; 591 } 592 return 0; 593 } 594 break; 595 } 596 597 return -1; 598} 599#endif 600 601void 602userret(struct proc *p, struct trapframe *frame, u_quad_t oticks) 603{ 604 605 /* XXX: Coming soon */ 606 return; 607} 608