trap.c revision 96499
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.58 2002/03/04 04:07:35 dbj Exp $ 32 */ 33 34#ifndef lint 35static const char rcsid[] = 36 "$FreeBSD: head/sys/powerpc/aim/trap.c 96499 2002-05-13 07:44:48Z 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/lock.h> 44#include <sys/mutex.h> 45#include <sys/proc.h> 46#include <sys/reboot.h> 47#include <sys/syscall.h> 48#include <sys/systm.h> 49#include <sys/sysent.h> 50#include <sys/user.h> 51#ifdef KTRACE 52#include <sys/uio.h> 53#include <sys/ktrace.h> 54#endif 55 56#include <vm/vm.h> 57#include <vm/pmap.h> 58#include <vm/vm_extern.h> 59#include <vm/vm_param.h> 60#include <vm/vm_kern.h> 61#include <vm/vm_map.h> 62#include <vm/vm_page.h> 63 64#include <machine/cpu.h> 65#include <machine/db_machdep.h> 66#include <machine/fpu.h> 67#include <machine/frame.h> 68#include <machine/pcb.h> 69#include <machine/pmap.h> 70#include <machine/psl.h> 71#include <machine/trap.h> 72#include <machine/spr.h> 73#include <machine/sr.h> 74 75/* These definitions should probably be somewhere else XXX */ 76#define FIRSTARG 3 /* first argument is in reg 3 */ 77#define NARGREG 8 /* 8 args are in registers */ 78#define MOREARGS(sp) ((caddr_t)((int)(sp) + 8)) /* more args go here */ 79 80#ifndef MULTIPROCESSOR 81volatile int astpending; 82volatile int want_resched; 83extern int intr_depth; 84#endif 85 86void *syscall = NULL; /* XXX dummy symbol for emul_netbsd */ 87 88static int fix_unaligned(struct proc *p, struct trapframe *frame); 89static __inline void setusr(int); 90 91void trap(struct trapframe *); /* Called from locore / trap_subr */ 92int setfault(faultbuf); /* defined in locore.S */ 93/* Why are these not defined in a header? */ 94int badaddr(void *, size_t); 95int badaddr_read(void *, size_t, int *); 96 97extern char *syscallnames[]; 98 99void 100trap(frame) 101 struct trapframe *frame; 102{ 103 struct thread *td = PCPU_GET(curthread); 104 struct thread *fputhread; 105 struct proc *p = td->td_proc; 106 int type = frame->exc; 107 int ftype, rv; 108 109#if 0 110 curcpu()->ci_ev_traps.ev_count++; 111#endif 112 113 if (frame->srr1 & PSL_PR) 114 type |= EXC_USER; 115 116#ifdef DIAGNOSTIC 117 if (curpcb->pcb_pmreal != curpm) 118 panic("trap: curpm (%p) != curpcb->pcb_pmreal (%p)", 119 curpm, curpcb->pcb_pmreal); 120#endif 121 122#if 0 123 uvmexp.traps++; 124#endif 125 126 switch (type) { 127 case EXC_RUNMODETRC|EXC_USER: 128 /* FALLTHROUGH */ 129 case EXC_TRC|EXC_USER: 130 PROC_LOCK(p); 131 frame->srr1 &= ~PSL_SE; 132 trapsignal(p, SIGTRAP, EXC_TRC); 133 PROC_UNLOCK(p); 134 break; 135 case EXC_DSI: { 136 faultbuf *fb; 137 /* 138 * Only query UVM if no interrupts are active (this applies 139 * "on-fault" as well. 140 */ 141#if 0 142 curcpu()->ci_ev_kdsi.ev_count++; 143#endif 144 if (intr_depth < 0) { 145 struct vm_map *map; 146 vm_offset_t va; 147 148#if 0 149 KERNEL_LOCK(LK_CANRECURSE|LK_EXCLUSIVE); 150#endif 151 map = kernel_map; 152 va = frame->dar; 153 if ((va >> ADDR_SR_SHFT) == USER_SR) { 154 register_t user_sr; 155 156 __asm ("mfsr %0, %1" 157 : "=r"(user_sr) : "K"(USER_SR)); 158 va &= ADDR_PIDX | ADDR_POFF; 159 va |= user_sr << ADDR_SR_SHFT; 160 /* KERNEL_PROC_LOCK(p); XXX */ 161 map = &p->p_vmspace->vm_map; 162 } 163 if (frame->dsisr & DSISR_STORE) 164 ftype = VM_PROT_WRITE; 165 else 166 ftype = VM_PROT_READ; 167 rv = vm_fault(map, trunc_page(va), ftype, 168 VM_FAULT_NORMAL); 169#if 0 170 KERNEL_UNLOCK(); 171#endif 172 if (rv == 0) 173 return; 174 if (rv == EACCES) 175 rv = EFAULT; 176 } else { 177 rv = EFAULT; 178 } 179 if ((fb = td->td_pcb->pcb_onfault) != NULL) { 180 frame->srr0 = (*fb)[0]; 181 frame->fixreg[1] = (*fb)[1]; 182 frame->fixreg[2] = (*fb)[2]; 183 frame->fixreg[3] = rv; 184 frame->cr = (*fb)[3]; 185 memcpy(&frame->fixreg[13], &(*fb)[4], 186 19 * sizeof(register_t)); 187 return; 188 } 189 printf("trap: kernel %s DSI @ %#x by %#x (DSISR %#x, err=%d)\n", 190 (frame->dsisr & DSISR_STORE) ? "write" : "read", 191 frame->dar, frame->srr0, frame->dsisr, rv); 192 goto brain_damage2; 193 } 194 case EXC_DSI|EXC_USER: 195 PROC_LOCK(p); 196 ++p->p_lock; 197 PROC_UNLOCK(p); 198#if 0 199 curcpu()->ci_ev_udsi.ev_count++; 200#endif 201 if (frame->dsisr & DSISR_STORE) 202 ftype = VM_PROT_WRITE; 203 else 204 ftype = VM_PROT_READ; 205 rv = vm_fault(&p->p_vmspace->vm_map, trunc_page(frame->dar), 206 ftype, VM_FAULT_NORMAL); 207#if 0 208 curcpu()->ci_ev_udsi_fatal.ev_count++; 209#endif 210 printf("trap: pid %d (%s): user %s DSI @ %#x " 211 "by %#x (DSISR %#x, err=%d)\n", 212 p->p_pid, p->p_comm, 213 (frame->dsisr & DSISR_STORE) ? "write" : "read", 214 frame->dar, frame->srr0, frame->dsisr, rv); 215 if (rv == ENOMEM) { 216 printf("UVM: pid %d (%s), uid %d killed: " 217 "out of swap\n", 218 p->p_pid, p->p_comm, 219 td->td_ucred ? td->td_ucred->cr_uid : -1); 220 trapsignal(p, SIGKILL, EXC_DSI); 221 } else { 222 trapsignal(p, SIGSEGV, EXC_DSI); 223 } 224 PROC_LOCK(p); 225 --p->p_lock; 226 PROC_UNLOCK(p); 227 break; 228 case EXC_ISI: 229 printf("trap: kernel ISI by %#x (SRR1 %#x)\n", 230 frame->srr0, frame->srr1); 231 goto brain_damage2; 232 case EXC_ISI|EXC_USER: 233 PROC_LOCK(p); 234 ++p->p_lock; 235 PROC_UNLOCK(p); 236#if 0 237 curcpu()->ci_ev_isi.ev_count++; 238#endif 239 ftype = VM_PROT_READ | VM_PROT_EXECUTE; 240 rv = vm_fault(&p->p_vmspace->vm_map, trunc_page(frame->srr0), 241 ftype, VM_FAULT_NORMAL); 242 if (rv == 0) { 243 PROC_LOCK(p); 244 --p->p_lock; 245 PROC_UNLOCK(p); 246 break; 247 } 248#if 0 249 curcpu()->ci_ev_isi_fatal.ev_count++; 250#endif 251 printf("trap: pid %d (%s): user ISI trap @ %#x " 252 "(SSR1=%#x)\n", 253 p->p_pid, p->p_comm, frame->srr0, frame->srr1); 254 trapsignal(p, SIGSEGV, EXC_ISI); 255 PROC_LOCK(p); 256 --p->p_lock; 257 PROC_UNLOCK(p); 258 break; 259 case EXC_SC|EXC_USER: 260#if 0 261 curcpu()->ci_ev_scalls.ev_count++; 262#endif 263 { 264 const struct sysent *callp; 265 size_t argsize; 266 register_t code, error; 267 register_t *params, rval[2]; 268 int n; 269 register_t args[10]; 270 271#if 0 272 uvmexp.syscalls++; 273#endif 274 275 code = frame->fixreg[0]; 276 callp = &p->p_sysent->sv_table[0]; 277 params = frame->fixreg + FIRSTARG; 278 n = NARGREG; 279 280 switch (code) { 281 case SYS_syscall: 282 /* 283 * code is first argument, 284 * followed by actual args. 285 */ 286 code = *params++; 287 n -= 1; 288 break; 289 case SYS___syscall: 290 params++; 291 code = *params++; 292 n -= 2; 293 break; 294 default: 295 break; 296 } 297 298 if (p->p_sysent->sv_mask) 299 code &= p->p_sysent->sv_mask; 300 callp += code; 301 argsize = callp->sy_narg & SYF_ARGMASK; 302 303 if (argsize > n * sizeof(register_t)) { 304 memcpy(args, params, n * sizeof(register_t)); 305 error = copyin(MOREARGS(frame->fixreg[1]), 306 args + n, 307 argsize - n * sizeof(register_t)); 308 if (error) 309 goto syscall_bad; 310 params = args; 311 } 312 313 /* 314 * Try to run the syscall without Giant if the syscall 315 * is MP safe. 316 */ 317 if ((callp->sy_narg & SYF_MPSAFE) == 0) 318 mtx_lock(&Giant); 319 320#ifdef KTRACE 321 if (KTRPOINT(p, KTR_SYSCALL)) 322 ktrsyscall(p, code, argsize, params); 323#endif 324 325 rval[0] = 0; 326 rval[1] = 0; 327 328 error = (*callp->sy_call)(td, params); 329 switch (error) { 330 case 0: 331 frame->fixreg[FIRSTARG] = rval[0]; 332 frame->fixreg[FIRSTARG + 1] = rval[1]; 333 frame->cr &= ~0x10000000; 334 break; 335 case ERESTART: 336 /* 337 * Set user's pc back to redo the system call. 338 */ 339 frame->srr0 -= 4; 340 break; 341 case EJUSTRETURN: 342 /* nothing to do */ 343 break; 344 default: 345syscall_bad: 346#if 0 347 if (p->p_emul->e_errno) 348 error = p->p_emul->e_errno[error]; 349#endif 350 frame->fixreg[FIRSTARG] = error; 351 frame->cr |= 0x10000000; 352 break; 353 } 354 355 /* 356 * Release Giant if we had to get it. Don't use 357 * mtx_owned(), we want to catch broken syscalls. 358 */ 359 if ((callp->sy_narg & SYF_MPSAFE) == 0) 360 mtx_unlock(&Giant); 361#ifdef KTRACE 362 if (KTRPOINT(p, KTR_SYSRET)) 363 ktrsysret(p, code, error, rval[0]); 364#endif 365 } 366 break; 367 368 case EXC_FPU|EXC_USER: 369 if ((fputhread = PCPU_GET(fputhread)) != NULL) { 370 KASSERT(fputhread != td, 371 ("floating-point already enabled")); 372 save_fpu(fputhread); 373 } 374 PCPU_SET(fputhread, td); 375 td->td_pcb->pcb_fpcpu = PCPU_GET(cpuid); 376 enable_fpu(td); 377 frame->srr1 |= PSL_FP; 378 break; 379 380#ifdef ALTIVEC 381 case EXC_VEC|EXC_USER: 382#if 0 383 curcpu()->ci_ev_vec.ev_count++; 384#endif 385 if (vecproc) { 386#if 0 387 curcpu()->ci_ev_vecsw.ev_count++; 388#endif 389 save_vec(vecproc); 390 } 391 vecproc = p; 392 enable_vec(p); 393 break; 394#endif 395 396 case EXC_AST|EXC_USER: 397 astpending = 0; /* we are about to do it */ 398 PROC_LOCK(p); 399#if 0 400 uvmexp.softs++; 401 if (p->p_flag & P_OWEUPC) { 402 p->p_flag &= ~P_OWEUPC; 403 ADDUPROF(p); 404 } 405#endif 406 /* Check whether we are being preempted. */ 407 if (want_resched) 408 mi_switch(); 409 PROC_UNLOCK(p); 410 break; 411 412 case EXC_ALI|EXC_USER: 413 PROC_LOCK(p); 414#if 0 415 curcpu()->ci_ev_ali.ev_count++; 416#endif 417 if (fix_unaligned(p, frame) != 0) { 418#if 0 419 curcpu()->ci_ev_ali_fatal.ev_count++; 420#endif 421 printf("trap: pid %d (%s): user ALI trap @ %#x " 422 "(SSR1=%#x)\n", 423 p->p_pid, p->p_comm, frame->srr0, 424 frame->srr1); 425 trapsignal(p, SIGBUS, EXC_ALI); 426 } else 427 frame->srr0 += 4; 428 PROC_UNLOCK(p); 429 break; 430 431 case EXC_PGM|EXC_USER: 432/* XXX temporarily */ 433 PROC_LOCK(p); 434#if 0 435 curcpu()->ci_ev_pgm.ev_count++; 436#endif 437 printf("trap: pid %d (%s): user PGM trap @ %#x " 438 "(SSR1=%#x)\n", 439 p->p_pid, p->p_comm, frame->srr0, frame->srr1); 440 if (frame->srr1 & 0x00020000) /* Bit 14 is set if trap */ 441 trapsignal(p, SIGTRAP, EXC_PGM); 442 else 443 trapsignal(p, SIGILL, EXC_PGM); 444 PROC_UNLOCK(p); 445 break; 446 447 case EXC_MCHK: { 448 faultbuf *fb; 449 450 if ((fb = td->td_pcb->pcb_onfault) != NULL) { 451 frame->srr0 = (*fb)[0]; 452 frame->fixreg[1] = (*fb)[1]; 453 frame->fixreg[2] = (*fb)[2]; 454 frame->fixreg[3] = EFAULT; 455 frame->cr = (*fb)[3]; 456 memcpy(&frame->fixreg[13], &(*fb)[4], 457 19 * sizeof(register_t)); 458 return; 459 } 460 goto brain_damage; 461 } 462 463 default: 464brain_damage: 465 printf("trap type %x at %x\n", type, frame->srr0); 466brain_damage2: 467#ifdef DDBX 468 if (kdb_trap(type, frame)) 469 return; 470#endif 471#ifdef TRAP_PANICWAIT 472 printf("Press a key to panic.\n"); 473 cnpollc(1); 474 cngetc(); 475 cnpollc(0); 476#endif 477 panic("trap"); 478 } 479 480#if 0 481 /* Take pending signals. */ 482 { 483 int sig; 484 485 while ((sig = CURSIG(p)) != 0) 486 postsig(sig); 487 } 488#endif 489 490 /* 491 * If someone stole the fp or vector unit while we were away, 492 * disable it 493 */ 494 if (td != PCPU_GET(fputhread) || 495 td->td_pcb->pcb_fpcpu != PCPU_GET(cpuid)) 496 frame->srr1 &= ~PSL_FP; 497#ifdef ALTIVEC 498 if (p != vecproc) 499 frame->srr1 &= ~PSL_VEC; 500#endif 501 502#if 0 503 curcpu()->ci_schedstate.spc_curpriority = p->p_priority = p->p_usrpri; 504 p->p_priority = p->p_usrpri; 505#endif 506} 507 508void child_return(void *); 509 510void 511child_return(void *arg) 512{ 513 struct thread *td = arg; 514 struct proc *p = td->td_proc; 515 struct trapframe *tf = trapframe(td); 516 517 PROC_UNLOCK(p); 518 519 tf->fixreg[FIRSTARG] = 0; 520 tf->fixreg[FIRSTARG + 1] = 1; 521 tf->cr &= ~0x10000000; 522#if 0 523 tf->srr1 &= ~(PSL_FP|PSL_VEC); /* Disable FP & AltiVec, as we can't 524 be them. */ 525 td->td_pcb->pcb_fpcpu = NULL; 526#endif 527#ifdef KTRACE 528 if (KTRPOINT(p, KTR_SYSRET)) { 529 PROC_LOCK(p); 530 ktrsysret(p, SYS_fork, 0, 0); 531 PROC_UNLOCK(p); 532 } 533#endif 534 /* Profiling? XXX */ 535#if 0 536 curcpu()->ci_schedstate.spc_curpriority = p->p_priority; 537#endif 538} 539 540static __inline void 541setusr(content) 542 int content; 543{ 544 __asm __volatile ("isync; mtsr %0,%1; isync" 545 :: "n"(USER_SR), "r"(content)); 546} 547 548int kcopy(const void *, void *, size_t); 549 550/* 551 * kcopy(const void *src, void *dst, size_t len); 552 * 553 * Copy len bytes from src to dst, aborting if we encounter a fatal 554 * page fault. 555 * 556 * kcopy() _must_ save and restore the old fault handler since it is 557 * called by uiomove(), which may be in the path of servicing a non-fatal 558 * page fault. 559 */ 560int 561kcopy(const void *src, void *dst, size_t len) 562{ 563 struct thread *td; 564 faultbuf env, *oldfault; 565 int rv; 566 567 td = PCPU_GET(curthread); 568 oldfault = td->td_pcb->pcb_onfault; 569 if ((rv = setfault(env)) != 0) { 570 td->td_pcb->pcb_onfault = oldfault; 571 return rv; 572 } 573 574 memcpy(dst, src, len); 575 576 td->td_pcb->pcb_onfault = oldfault; 577 return 0; 578} 579 580int 581badaddr(addr, size) 582 void *addr; 583 size_t size; 584{ 585 return badaddr_read(addr, size, NULL); 586} 587 588int 589badaddr_read(addr, size, rptr) 590 void *addr; 591 size_t size; 592 int *rptr; 593{ 594 struct thread *td; 595 faultbuf env; 596 int x; 597 598 /* Get rid of any stale machine checks that have been waiting. */ 599 __asm __volatile ("sync; isync"); 600 601 td = PCPU_GET(curthread); 602 603 if (setfault(env)) { 604 td->td_pcb->pcb_onfault = 0; 605 __asm __volatile ("sync"); 606 return 1; 607 } 608 609 __asm __volatile ("sync"); 610 611 switch (size) { 612 case 1: 613 x = *(volatile int8_t *)addr; 614 break; 615 case 2: 616 x = *(volatile int16_t *)addr; 617 break; 618 case 4: 619 x = *(volatile int32_t *)addr; 620 break; 621 default: 622 panic("badaddr: invalid size (%d)", size); 623 } 624 625 /* Make sure we took the machine check, if we caused one. */ 626 __asm __volatile ("sync; isync"); 627 628 td->td_pcb->pcb_onfault = 0; 629 __asm __volatile ("sync"); /* To be sure. */ 630 631 /* Use the value to avoid reorder. */ 632 if (rptr) 633 *rptr = x; 634 635 return 0; 636} 637 638/* 639 * For now, this only deals with the particular unaligned access case 640 * that gcc tends to generate. Eventually it should handle all of the 641 * possibilities that can happen on a 32-bit PowerPC in big-endian mode. 642 */ 643 644static int 645fix_unaligned(p, frame) 646 struct proc *p; 647 struct trapframe *frame; 648{ 649 int indicator = EXC_ALI_OPCODE_INDICATOR(frame->dsisr); 650 651 switch (indicator) { 652 case EXC_ALI_LFD: 653 case EXC_ALI_STFD: 654#if 0 655 { 656 int reg = EXC_ALI_RST(frame->dsisr); 657 double *fpr = &p->p_addr->u_pcb.pcb_fpu.fpr[reg]; 658 659 /* Juggle the FPU to ensure that we've initialized 660 * the FPRs, and that their current state is in 661 * the PCB. 662 */ 663 if (fpuproc != p) { 664 if (fpuproc) 665 save_fpu(fpuproc); 666 enable_fpu(p); 667 } 668 save_fpu(p); 669 670 if (indicator == EXC_ALI_LFD) { 671 if (copyin((void *)frame->dar, fpr, 672 sizeof(double)) != 0) 673 return -1; 674 enable_fpu(p); 675 } else { 676 if (copyout(fpr, (void *)frame->dar, 677 sizeof(double)) != 0) 678 return -1; 679 } 680 return 0; 681 } 682#endif 683 break; 684 } 685 686 return -1; 687} 688