trap.c revision 93452
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 93452 2002-03-30 20:44:31Z alc $"; 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/ktr.h> 45#include <sys/lock.h> 46#include <sys/mutex.h> 47#include <sys/pioctl.h> 48#include <sys/reboot.h> 49#include <sys/syscall.h> 50#include <sys/sysent.h> 51#include <sys/systm.h> 52#include <sys/uio.h> 53#include <sys/user.h> 54#ifdef KTRACE 55#include <sys/ktrace.h> 56#endif 57#include <sys/vmmeter.h> 58 59#include <vm/vm.h> 60#include <vm/pmap.h> 61#include <vm/vm_extern.h> 62#include <vm/vm_kern.h> 63#include <vm/vm_map.h> 64#include <vm/vm_param.h> 65 66#include <machine/cpu.h> 67#include <machine/frame.h> 68#include <machine/pcb.h> 69#include <machine/psl.h> 70#include <machine/trap.h> 71 72/* These definitions should probably be somewhere else XXX */ 73#define FIRSTARG 3 /* first argument is in reg 3 */ 74#define NARGREG 8 /* 8 args are in registers */ 75#define MOREARGS(sp) ((caddr_t)((int)(sp) + 8)) /* more args go here */ 76 77#ifdef WITNESS 78extern char *syscallnames[]; 79#endif 80 81#if 0 /* XXX: not used yet */ 82static int fix_unaligned(struct proc *p, struct trapframe *frame); 83#endif 84static void trap_fatal(struct trapframe *frame); 85static void printtrap(int vector, struct trapframe *frame, int isfatal, 86 int user); 87static int trap_pfault(struct trapframe *frame, int user); 88static int handle_onfault (struct trapframe *frame); 89 90static const char *ppc_exception_names[] = { 91 "reserved 0", /* 0 */ 92 "reset", /* 1 */ 93 "machine check", /* 2 */ 94 "data storage interrupt", /* 3 */ 95 "instruction storage interrupt", /* 4 */ 96 "external interrupt", /* 5 */ 97 "alignment interrupt", /* 6 */ 98 "program interrupt", /* 7 */ 99 "floating point unavailable", /* 8 */ 100 "decrementer interrupt", /* 9 */ 101 "reserved", /* 10 */ 102 "reserved", /* 11 */ 103 "system call", /* 12 */ 104 "trace", /* 13 */ 105 "floating point assist", /* 14 */ 106 "performance monitoring", /* 15 */ 107 "instruction tlb miss", /* 16 */ 108 "data load tlb miss", /* 17 */ 109 "data store tlb miss", /* 18 */ 110 "instruction breakpoint", /* 19 */ 111 "system management interrupt", /* 20 */ 112 "reserved 21", /* 21 */ 113 "reserved 22", /* 22 */ 114 "reserved 23", /* 23 */ 115 "reserved 24", /* 24 */ 116 "reserved 25", /* 25 */ 117 "reserved 26", /* 26 */ 118 "reserved 27", /* 27 */ 119 "reserved 28", /* 28 */ 120 "reserved 29", /* 29 */ 121 "reserved 30", /* 30 */ 122 "reserved 31", /* 31 */ 123 "reserved 32", /* 32 */ 124 "reserved 33", /* 33 */ 125 "reserved 34", /* 34 */ 126 "reserved 35", /* 35 */ 127 "reserved 36", /* 36 */ 128 "reserved 37", /* 37 */ 129 "reserved 38", /* 38 */ 130 "reserved 39", /* 39 */ 131 "reserved 40", /* 40 */ 132 "reserved 41", /* 41 */ 133 "reserved 42", /* 42 */ 134 "reserved 43", /* 43 */ 135 "reserved 44", /* 44 */ 136 "reserved 45", /* 45 */ 137 "reserved 46", /* 46 */ 138 "reserved 47", /* 47 */ 139}; 140 141static void 142printtrap(int vector, struct trapframe *frame, int isfatal, int user) 143{ 144 145 printf("\n"); 146 printf("%s %s trap:\n", isfatal ? "fatal" : "handled", 147 user ? "user" : "kernel"); 148 printf("\n"); 149 printf(" exception = 0x%x (%s)\n", vector >> 8, 150 ppc_exception_names[vector >> 8]); 151 switch (vector) { 152 case EXC_DSI: 153 printf(" virtual address = 0x%x\n", frame->dar); 154 break; 155 case EXC_ISI: 156 printf(" virtual address = 0x%x\n", frame->srr0); 157 break; 158 } 159 printf(" srr0 = 0x%x", frame->srr0); 160 printf(" curthread = %p\n", curthread); 161 if (curthread != NULL) 162 printf(" pid = %d, comm = %s\n", 163 curthread->td_proc->p_pid, curthread->td_proc->p_comm); 164 printf("\n"); 165} 166 167static void 168trap_fatal(struct trapframe *frame) 169{ 170 171 printtrap(frame->exc, frame, 1, (frame->srr1 & PSL_PR)); 172#ifdef DDB 173 if ((debugger_on_panic || db_active) && kdb_trap(frame->exc, 0, frame)) 174 return; 175#endif 176 panic("%s Trap", ppc_exception_names[frame->exc >> 8]); 177} 178 179/* 180 * Handles a fatal fault when we have onfault state to recover. Returns 181 * non-zero if there was onfault recovery state available. 182 */ 183static int 184handle_onfault (struct trapframe *frame) 185{ 186 struct thread *td; 187 faultbuf *fb; 188 189 td = curthread; 190 fb = td->td_pcb->pcb_onfault; 191 if (fb != NULL) { 192 frame->srr0 = (*fb)[0]; 193 frame->fixreg[1] = (*fb)[1]; 194 frame->fixreg[2] = (*fb)[2]; 195 frame->cr = (*fb)[3]; 196 bcopy(&(*fb)[4], &frame->fixreg[13], 197 19 * sizeof(register_t)); 198 return (1); 199 } 200 return (0); 201} 202 203void 204trap(struct trapframe *frame) 205{ 206 struct thread *td; 207 struct proc *p; 208 int sig, type, user; 209 u_int sticks, ucode; 210 211 atomic_add_int(&cnt.v_trap, 1); 212 213 td = curthread; 214 p = td->td_proc; 215 216 type = frame->exc; 217 ucode = type; 218 sig = 0; 219 user = (frame->srr1 & PSL_PR); 220 sticks = 0; 221 222 CTR3(KTR_TRAP, "trap: %s type=%s (%s)", p->p_comm, 223 ppc_exception_names[type >> 8], 224 user ? "user" : "kernel"); 225 226 if (user) { 227 sticks = td->td_kse->ke_sticks; 228 td->td_frame = frame; 229 if (td->td_ucred != p->p_ucred) 230 cred_update_thread(td); 231 232 /* User Mode Traps */ 233 switch (type) { 234 case EXC_TRC: 235 frame->srr1 &= ~PSL_SE; 236 sig = SIGTRAP; 237 break; 238 case EXC_DSI: 239 case EXC_ISI: 240 sig = trap_pfault(frame, 1); 241 break; 242 case EXC_SC: 243 syscall(frame); 244 break; 245 case EXC_FPU: 246 enable_fpu(PCPU_GET(curpcb)); 247 frame->srr1 |= PSL_FP; 248 break; 249 250 case EXC_ALI: 251#if 0 252 if (fix_unaligned(p, frame) != 0) 253#endif 254 sig = SIGBUS; 255#if 0 256 else 257 frame->srr0 += 4; 258#endif 259 break; 260 261 case EXC_PGM: 262 /* XXX temporarily */ 263 /* XXX: Magic Number? */ 264 if (frame->srr1 & 0x0002000) 265 sig = SIGTRAP; 266 else 267 sig = SIGILL; 268 break; 269 270 default: 271 trap_fatal(frame); 272 } 273 } else { 274 /* Kernel Mode Traps */ 275 276 KASSERT(cold || td->td_ucred != NULL, 277 ("kernel trap doesn't have ucred")); 278 switch (type) { 279 case EXC_DSI: 280 if (trap_pfault(frame, 0) == 0) 281 return; 282 break; 283 case EXC_MCHK: 284 if (handle_onfault(frame)) 285 return; 286 break; 287 default: 288 trap_fatal(frame); 289 } 290 /* NOTREACHED */ 291 } 292 if (sig != 0) { 293 if (p->p_sysent->sv_transtrap != NULL) 294 sig = (p->p_sysent->sv_transtrap)(sig, type); 295 trapsignal(p, sig, ucode); 296 } 297 userret(td, frame, sticks); 298 mtx_assert(&Giant, MA_NOTOWNED); 299#ifdef DIAGNOSTIC 300 cred_free_thread(td); 301#endif 302} 303 304void 305syscall(struct trapframe *frame) 306{ 307 caddr_t params; 308 struct sysent *callp; 309 struct thread *td; 310 struct proc *p; 311 int error, n; 312 size_t narg; 313 register_t args[10]; 314 u_int code; 315 316 td = curthread; 317 p = td->td_proc; 318 319 atomic_add_int(&cnt.v_syscall, 1); 320 321 code = frame->fixreg[0]; 322 params = (caddr_t) (frame->fixreg + FIRSTARG); 323 324 if (p->p_sysent->sv_prepsyscall) 325 /* 326 * The prep code is MP aware. 327 */ 328 (*p->p_sysent->sv_prepsyscall)(frame, args, &code, ¶ms); 329 else if (code == SYS_syscall) 330 /* 331 * code is first argument, 332 * followed by actual args. 333 */ 334 code = *params++; 335 else if (code == SYS___syscall) { 336 /* 337 * Like syscall, but code is a quad, 338 * so as to maintain quad alignment 339 * for the rest of the args. 340 */ 341 params++; 342 code = *params++; 343 } 344 345 if (p->p_sysent->sv_mask) 346 code &= p->p_sysent->sv_mask; 347 348 if (code >= p->p_sysent->sv_size) 349 callp = &p->p_sysent->sv_table[0]; 350 else 351 callp = &p->p_sysent->sv_table[code]; 352 353 narg = callp->sy_narg & SYF_ARGMASK; 354 355 n = NARGREG - (params - (caddr_t)(frame->fixreg + FIRSTARG)); 356 if (narg > n * sizeof(register_t)) { 357 bcopy(params, args, n * sizeof(register_t)); 358 if (error = copyin(MOREARGS(frame->fixreg[1]), args + n, 359 narg - n * sizeof(register_t))) { 360#ifdef KTRACE 361 /* Can't get all the arguments! */ 362 if (KTRPOINT(p, KTR_SYSCALL)) 363 ktrsyscall(p->p_tracep, code, narg, args); 364#endif 365 goto bad; 366 } 367 params = (caddr_t) args; 368 } 369 370 /* 371 * Try to run the syscall without Giant if the syscall is MP safe. 372 */ 373 if ((callp->sy_narg & SYF_MPSAFE) == 0) 374 mtx_lock(&Giant); 375 376#ifdef KTRACE 377 if (KTRPOINT(p, KTR_SYSCALL)) 378 ktrsyscall(p->p_tracep, code, narg, params); 379#endif 380 td->td_retval[0] = 0; 381 td->td_retval[1] = frame->fixreg[FIRSTARG + 1]; 382 383 STOPEVENT(p, S_SCE, narg); 384 385 error = (*callp->sy_call)(td, args); 386 switch (error) { 387 case 0: 388 frame->fixreg[FIRSTARG] = td->td_retval[0]; 389 frame->fixreg[FIRSTARG + 1] = td->td_retval[1]; 390 /* XXX: Magic number */ 391 frame->cr &= ~0x10000000; 392 break; 393 case ERESTART: 394 /* 395 * Set user's pc back to redo the system call. 396 */ 397 frame->srr0 -= 4; 398 break; 399 case EJUSTRETURN: 400 /* nothing to do */ 401 break; 402 default: 403bad: 404 if (p->p_sysent->sv_errsize) { 405 if (error >= p->p_sysent->sv_errsize) 406 error = -1; /* XXX */ 407 else 408 error = p->p_sysent->sv_errtbl[error]; 409 } 410 frame->fixreg[FIRSTARG] = error; 411 /* XXX: Magic number: Carry Flag Equivalent? */ 412 frame->cr |= 0x10000000; 413 break; 414 } 415 416 417#ifdef KTRACE 418 if (KTRPOINT(p, KTR_SYSRET)) 419 ktrsysret(p->p_tracep, code, error, td->td_retval[0]); 420#endif 421 422 if ((callp->sy_narg & SYF_MPSAFE) == 0) 423 mtx_unlock(&Giant); 424 425 /* 426 * Does the comment in the i386 code about errno apply here? 427 */ 428 STOPEVENT(p, S_SCX, code); 429 430#ifdef WITNESS 431 if (witness_list(td)) { 432 panic("system call %s returning with mutex(s) held\n", 433 syscallnames[code]); 434 } 435#endif 436 mtx_assert(&sched_lock, MA_NOTOWNED); 437 mtx_assert(&Giant, MA_NOTOWNED); 438} 439 440static int 441trap_pfault(struct trapframe *frame, int user) 442{ 443 vm_offset_t eva, va; 444 struct thread *td; 445 struct proc *p; 446 vm_map_t map; 447 vm_prot_t ftype; 448 int rv; 449 450 td = curthread; 451 p = td->td_proc; 452 if (frame->exc == EXC_ISI) { 453 eva = frame->srr0; 454 ftype = VM_PROT_READ | VM_PROT_EXECUTE; 455 } else { 456 eva = frame->dar; 457 if (frame->dsisr & DSISR_STORE) 458 ftype = VM_PROT_READ | VM_PROT_WRITE; 459 else 460 ftype = VM_PROT_READ; 461 } 462 463 if ((eva >> ADDR_SR_SHFT) != USER_SR) { 464 if (user) 465 return (SIGSEGV); 466 map = kernel_map; 467 } else { 468 u_int user_sr; 469 470 if (p->p_vmspace == NULL) 471 return (SIGSEGV); 472 473 __asm ("mfsr %0, %1" 474 : "=r"(user_sr) 475 : "K"(USER_SR)); 476 eva &= ADDR_PIDX | ADDR_POFF; 477 eva |= user_sr << ADDR_SR_SHFT; 478 map = &p->p_vmspace->vm_map; 479 } 480 va = trunc_page(eva); 481 482 mtx_lock(&Giant); 483 if (map != kernel_map) { 484 /* 485 * Keep swapout from messing with us during this 486 * critical time. 487 */ 488 PROC_LOCK(p); 489 ++p->p_lock; 490 PROC_UNLOCK(p); 491 492 /* 493 * Grow the stack if necessary 494 */ 495 /* vm_map_growstack returns failure only if va falls into 496 * a growable stack region and the stack growth 497 * fails. It succeeds if va was not within 498 * a growable stack region, or if the stack 499 * growth succeeded. 500 */ 501 if (vm_map_growstack(p, va) != KERN_SUCCESS) 502 rv = KERN_FAILURE; 503 else 504 /* Fault in the user page: */ 505 rv = vm_fault(map, va, ftype, 506 (ftype & VM_PROT_WRITE) ? VM_FAULT_DIRTY 507 : VM_FAULT_NORMAL); 508 509 PROC_LOCK(p); 510 --p->p_lock; 511 PROC_UNLOCK(p); 512 } else { 513 /* 514 * Don't have to worry about process locking or stacks in the 515 * kernel. 516 */ 517 rv = vm_fault(map, va, ftype, VM_FAULT_NORMAL); 518 } 519 mtx_unlock(&Giant); 520 521 if (rv == KERN_SUCCESS) 522 return (0); 523 524 if (!user && handle_onfault(frame)) 525 return (0); 526 527 return (SIGSEGV); 528} 529 530#if 0 /* XXX: child_return not used */ 531/* 532 * XXX: the trapframe return values should be setup in vm_machdep.c in 533 * cpu_fork(). 534 */ 535void 536child_return(void *arg) 537{ 538 struct proc *p; 539 struct trapframe *tf; 540 541 p = arg; 542 tf = trapframe(p); 543 544 tf->fixreg[FIRSTARG] = 0; 545 tf->fixreg[FIRSTARG + 1] = 1; 546 tf->cr &= ~0x10000000; 547 tf->srr1 &= ~PSL_FP; /* Disable FPU, as we can't be fpuproc */ 548#ifdef KTRACE 549 if (KTRPOINT(p, KTR_SYSRET)) 550 ktrsysret(p, SYS_fork, 0, 0); 551#endif 552 /* Profiling? XXX */ 553 curcpu()->ci_schedstate.spc_curpriority = p->p_priority; 554} 555#endif 556 557#if 0 /* XXX: not used yet */ 558/* 559 * kcopy(const void *src, void *dst, size_t len); 560 * 561 * Copy len bytes from src to dst, aborting if we encounter a fatal 562 * page fault. 563 * 564 * kcopy() _must_ save and restore the old fault handler since it is 565 * called by uiomove(), which may be in the path of servicing a non-fatal 566 * page fault. 567 */ 568int 569kcopy(const void *src, void *dst, size_t len) 570{ 571 faultbuf env, *oldfault; 572 573 oldfault = PCPU_GET(curpcb)->pcb_onfault; 574 if (setfault(env)) { 575 PCPU_GET(curpcb)->pcb_onfault = oldfault; 576 return EFAULT; 577 } 578 579 bcopy(src, dst, len); 580 581 PCPU_GET(curpcb)->pcb_onfault = oldfault; 582 return 0; 583} 584 585int 586badaddr(void *addr, size_t size) 587{ 588 589 return badaddr_read(addr, size, NULL); 590} 591 592int 593badaddr_read(void *addr, size_t size, int *rptr) 594{ 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 if (setfault(env)) { 602 PCPU_GET(curpcb)->pcb_onfault = 0; 603 __asm __volatile ("sync"); 604 return 1; 605 } 606 607 __asm __volatile ("sync"); 608 609 switch (size) { 610 case 1: 611 x = *(volatile int8_t *)addr; 612 break; 613 case 2: 614 x = *(volatile int16_t *)addr; 615 break; 616 case 4: 617 x = *(volatile int32_t *)addr; 618 break; 619 default: 620 panic("badaddr: invalid size (%d)", size); 621 } 622 623 /* Make sure we took the machine check, if we caused one. */ 624 __asm __volatile ("sync; isync"); 625 626 PCPU_GET(curpcb)->pcb_onfault = 0; 627 __asm __volatile ("sync"); /* To be sure. */ 628 629 /* Use the value to avoid reorder. */ 630 if (rptr) 631 *rptr = x; 632 633 return 0; 634} 635#endif 636 637/* 638 * For now, this only deals with the particular unaligned access case 639 * that gcc tends to generate. Eventually it should handle all of the 640 * possibilities that can happen on a 32-bit PowerPC in big-endian mode. 641 */ 642 643#if 0 /* XXX: Not used yet */ 644static int 645fix_unaligned(p, frame) 646 struct proc *p; 647 struct trapframe *frame; 648{ 649 int indicator; 650 651 indicator = EXC_ALI_OPCODE_INDICATOR(frame->dsisr); 652 653 switch (indicator) { 654 case EXC_ALI_LFD: 655 case EXC_ALI_STFD: 656 { 657 int reg = EXC_ALI_RST(frame->dsisr); 658 double *fpr = &p->p_addr->u_pcb.pcb_fpu.fpr[reg]; 659 660 /* Juggle the FPU to ensure that we've initialized 661 * the FPRs, and that their current state is in 662 * the PCB. 663 */ 664 if (!(pcb->pcb_flags & PCB_FPU)) 665 enable_fpu(PCPU_GET(curpcb)); 666 frame->srr1 |= PSL_FP; 667 } 668 save_fpu(PCPU_GET(curpcb)); 669 670 if (indicator == EXC_ALI_LFD) { 671 if (copyin((void *)frame->dar, fpr, 672 sizeof(double)) != 0) 673 return -1; 674 if (!(pcb->pcb_flags & PCB_FPU)) 675 enable_fpu(PCPU_GET(curpcb)); 676 frame->srr1 |= PSL_FP; 677 } 678 } else { 679 if (copyout(fpr, (void *)frame->dar, 680 sizeof(double)) != 0) 681 return -1; 682 } 683 return 0; 684 } 685 break; 686 } 687 688 return -1; 689} 690#endif 691