trap.c revision 266004
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#include <sys/cdefs.h> 35__FBSDID("$FreeBSD: stable/10/sys/powerpc/booke/trap.c 266004 2014-05-14 04:42:38Z ian $"); 36 37#include "opt_fpu_emu.h" 38 39#include <sys/param.h> 40#include <sys/kdb.h> 41#include <sys/proc.h> 42#include <sys/ktr.h> 43#include <sys/lock.h> 44#include <sys/mutex.h> 45#include <sys/pioctl.h> 46#include <sys/ptrace.h> 47#include <sys/reboot.h> 48#include <sys/syscall.h> 49#include <sys/sysent.h> 50#include <sys/systm.h> 51#include <sys/uio.h> 52#include <sys/signalvar.h> 53#include <sys/vmmeter.h> 54 55#include <security/audit/audit.h> 56 57#include <vm/vm.h> 58#include <vm/pmap.h> 59#include <vm/vm_extern.h> 60#include <vm/vm_param.h> 61#include <vm/vm_kern.h> 62#include <vm/vm_map.h> 63#include <vm/vm_page.h> 64 65#include <machine/cpu.h> 66#include <machine/db_machdep.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 74#ifdef FPU_EMU 75#include <powerpc/fpu/fpu_extern.h> 76#endif 77 78#define FAULTBUF_LR 0 79#define FAULTBUF_R1 1 80#define FAULTBUF_R2 2 81#define FAULTBUF_CR 3 82#define FAULTBUF_CTR 4 83#define FAULTBUF_XER 5 84#define FAULTBUF_R13 6 85 86static void trap_fatal(struct trapframe *frame); 87static void printtrap(u_int vector, struct trapframe *frame, int isfatal, 88 int user); 89static int trap_pfault(struct trapframe *frame, int user); 90static int fix_unaligned(struct thread *td, struct trapframe *frame); 91static int handle_onfault(struct trapframe *frame); 92static void syscall(struct trapframe *frame); 93 94int setfault(faultbuf); /* defined in locore.S */ 95 96/* Why are these not defined in a header? */ 97int badaddr(void *, size_t); 98int badaddr_read(void *, size_t, int *); 99 100struct powerpc_exception { 101 u_int vector; 102 char *name; 103}; 104 105static struct powerpc_exception powerpc_exceptions[] = { 106 { EXC_CRIT, "critical input" }, 107 { EXC_MCHK, "machine check" }, 108 { EXC_DSI, "data storage interrupt" }, 109 { EXC_ISI, "instruction storage interrupt" }, 110 { EXC_EXI, "external interrupt" }, 111 { EXC_ALI, "alignment" }, 112 { EXC_PGM, "program" }, 113 { EXC_SC, "system call" }, 114 { EXC_APU, "auxiliary proc unavailable" }, 115 { EXC_DECR, "decrementer" }, 116 { EXC_FIT, "fixed-interval timer" }, 117 { EXC_WDOG, "watchdog timer" }, 118 { EXC_DTMISS, "data tlb miss" }, 119 { EXC_ITMISS, "instruction tlb miss" }, 120 { EXC_DEBUG, "debug" }, 121 { EXC_PERF, "performance monitoring" }, 122 { EXC_LAST, NULL } 123}; 124 125static const char * 126trapname(u_int vector) 127{ 128 struct powerpc_exception *pe; 129 130 for (pe = powerpc_exceptions; pe->vector != EXC_LAST; pe++) { 131 if (pe->vector == vector) 132 return (pe->name); 133 } 134 135 return ("unknown"); 136} 137 138void 139trap(struct trapframe *frame) 140{ 141 struct thread *td; 142 struct proc *p; 143 int sig, type, user; 144 ksiginfo_t ksi; 145 146#ifdef KDB 147 if (kdb_active) { 148 kdb_reenter(); 149 return; 150 } 151#endif 152 153 PCPU_INC(cnt.v_trap); 154 155 td = curthread; 156 p = td->td_proc; 157 158 type = frame->exc; 159 sig = 0; 160 user = (frame->srr1 & PSL_PR) ? 1 : 0; 161 162 CTR3(KTR_TRAP, "trap: %s type=%s (%s)", p->p_comm, 163 trapname(type), user ? "user" : "kernel"); 164 165 if (user) { 166 td->td_frame = frame; 167 if (td->td_ucred != p->p_ucred) 168 cred_update_thread(td); 169 170 /* User Mode Traps */ 171 switch (type) { 172 case EXC_DSI: 173 case EXC_ISI: 174 sig = trap_pfault(frame, 1); 175 break; 176 177 case EXC_SC: 178 syscall(frame); 179 break; 180 181 case EXC_ALI: 182 if (fix_unaligned(td, frame) != 0) 183 sig = SIGBUS; 184 else 185 frame->srr0 += 4; 186 break; 187 188 case EXC_DEBUG: /* Single stepping */ 189 mtspr(SPR_DBSR, mfspr(SPR_DBSR)); 190 frame->srr1 &= ~PSL_DE; 191 frame->cpu.booke.dbcr0 &= ~(DBCR0_IDM || DBCR0_IC); 192 sig = SIGTRAP; 193 break; 194 195 case EXC_PGM: /* Program exception */ 196#ifdef FPU_EMU 197 if (!(td->td_pcb->pcb_flags & PCB_FPREGS)) { 198 bzero(&td->td_pcb->pcb_fpu, 199 sizeof(td->td_pcb->pcb_fpu)); 200 td->td_pcb->pcb_flags |= PCB_FPREGS; 201 } 202 sig = fpu_emulate(frame, 203 (struct fpreg *)&td->td_pcb->pcb_fpu); 204#else 205 /* XXX SIGILL for non-trap instructions. */ 206 sig = SIGTRAP; 207#endif 208 break; 209 210 default: 211 trap_fatal(frame); 212 } 213 } else { 214 /* Kernel Mode Traps */ 215 KASSERT(cold || td->td_ucred != NULL, 216 ("kernel trap doesn't have ucred")); 217 218 switch (type) { 219 case EXC_DEBUG: 220 mtspr(SPR_DBSR, mfspr(SPR_DBSR)); 221 kdb_trap(frame->exc, 0, frame); 222 return; 223 224 case EXC_DSI: 225 if (trap_pfault(frame, 0) == 0) 226 return; 227 break; 228 229 case EXC_MCHK: 230 if (handle_onfault(frame)) 231 return; 232 break; 233#ifdef KDB 234 case EXC_PGM: 235 if (frame->cpu.booke.esr & ESR_PTR) 236 kdb_trap(EXC_PGM, 0, frame); 237 return; 238#endif 239 default: 240 break; 241 } 242 trap_fatal(frame); 243 } 244 245 if (sig != 0) { 246 if (p->p_sysent->sv_transtrap != NULL) 247 sig = (p->p_sysent->sv_transtrap)(sig, type); 248 ksiginfo_init_trap(&ksi); 249 ksi.ksi_signo = sig; 250 ksi.ksi_code = type; /* XXX, not POSIX */ 251 /* ksi.ksi_addr = ? */ 252 ksi.ksi_trapno = type; 253 trapsignal(td, &ksi); 254 } 255 256 userret(td, frame); 257} 258 259static void 260trap_fatal(struct trapframe *frame) 261{ 262 263 printtrap(frame->exc, frame, 1, (frame->srr1 & PSL_PR)); 264#ifdef KDB 265 if ((debugger_on_panic || kdb_active) && 266 kdb_trap(frame->exc, 0, frame)) 267 return; 268#endif 269 panic("%s trap", trapname(frame->exc)); 270} 271 272static void 273printtrap(u_int vector, struct trapframe *frame, int isfatal, int user) 274{ 275 register_t va = 0; 276 277 printf("\n"); 278 printf("%s %s trap:\n", isfatal ? "fatal" : "handled", 279 user ? "user" : "kernel"); 280 printf("\n"); 281 printf(" exception = 0x%x (%s)\n", vector, trapname(vector)); 282 283 switch (vector) { 284 case EXC_DTMISS: 285 case EXC_DSI: 286 va = frame->cpu.booke.dear; 287 break; 288 289 case EXC_ITMISS: 290 case EXC_ISI: 291 va = frame->srr0; 292 break; 293 } 294 295 printf(" virtual address = 0x%08x\n", va); 296 printf(" srr0 = 0x%08x\n", frame->srr0); 297 printf(" srr1 = 0x%08x\n", frame->srr1); 298 printf(" curthread = %p\n", curthread); 299 if (curthread != NULL) 300 printf(" pid = %d, comm = %s\n", 301 curthread->td_proc->p_pid, curthread->td_proc->p_comm); 302 printf("\n"); 303} 304 305/* 306 * Handles a fatal fault when we have onfault state to recover. Returns 307 * non-zero if there was onfault recovery state available. 308 */ 309static int 310handle_onfault(struct trapframe *frame) 311{ 312 struct thread *td; 313 faultbuf *fb; 314 315 td = curthread; 316 fb = td->td_pcb->pcb_onfault; 317 if (fb != NULL) { 318 frame->srr0 = (*fb)[FAULTBUF_LR]; 319 frame->fixreg[1] = (*fb)[FAULTBUF_R1]; 320 frame->fixreg[2] = (*fb)[FAULTBUF_R2]; 321 frame->fixreg[3] = 1; 322 frame->cr = (*fb)[FAULTBUF_CR]; 323 frame->ctr = (*fb)[FAULTBUF_CTR]; 324 frame->xer = (*fb)[FAULTBUF_XER]; 325 bcopy(&(*fb)[FAULTBUF_R13], &frame->fixreg[13], 326 19 * sizeof(register_t)); 327 return (1); 328 } 329 return (0); 330} 331 332int 333cpu_fetch_syscall_args(struct thread *td, struct syscall_args *sa) 334{ 335 struct proc *p; 336 struct trapframe *frame; 337 caddr_t params; 338 int error, n; 339 340 p = td->td_proc; 341 frame = td->td_frame; 342 343 sa->code = frame->fixreg[0]; 344 params = (caddr_t)(frame->fixreg + FIRSTARG); 345 n = NARGREG; 346 347 if (sa->code == SYS_syscall) { 348 /* 349 * code is first argument, 350 * followed by actual args. 351 */ 352 sa->code = *(u_int *) params; 353 params += sizeof(register_t); 354 n -= 1; 355 } else if (sa->code == SYS___syscall) { 356 /* 357 * Like syscall, but code is a quad, 358 * so as to maintain quad alignment 359 * for the rest of the args. 360 */ 361 params += sizeof(register_t); 362 sa->code = *(u_int *) params; 363 params += sizeof(register_t); 364 n -= 2; 365 } 366 367 if (p->p_sysent->sv_mask) 368 sa->code &= p->p_sysent->sv_mask; 369 if (sa->code >= p->p_sysent->sv_size) 370 sa->callp = &p->p_sysent->sv_table[0]; 371 else 372 sa->callp = &p->p_sysent->sv_table[sa->code]; 373 sa->narg = sa->callp->sy_narg; 374 375 bcopy(params, sa->args, n * sizeof(register_t)); 376 if (sa->narg > n) { 377 error = copyin(MOREARGS(frame->fixreg[1]), sa->args + n, 378 (sa->narg - n) * sizeof(register_t)); 379 } else 380 error = 0; 381 382 if (error == 0) { 383 td->td_retval[0] = 0; 384 td->td_retval[1] = frame->fixreg[FIRSTARG + 1]; 385 } 386 return (error); 387} 388 389#include "../../kern/subr_syscall.c" 390 391void 392syscall(struct trapframe *frame) 393{ 394 struct thread *td; 395 struct syscall_args sa; 396 int error; 397 398 td = curthread; 399 td->td_frame = frame; 400 401 error = syscallenter(td, &sa); 402 syscallret(td, error, &sa); 403} 404 405static int 406trap_pfault(struct trapframe *frame, int user) 407{ 408 vm_offset_t eva, va; 409 struct thread *td; 410 struct proc *p; 411 vm_map_t map; 412 vm_prot_t ftype; 413 int rv; 414 415 td = curthread; 416 p = td->td_proc; 417 418 if (frame->exc == EXC_ISI) { 419 eva = frame->srr0; 420 ftype = VM_PROT_READ | VM_PROT_EXECUTE; 421 422 } else { 423 eva = frame->cpu.booke.dear; 424 if (frame->cpu.booke.esr & ESR_ST) 425 ftype = VM_PROT_WRITE; 426 else 427 ftype = VM_PROT_READ; 428 } 429 430 if (user) { 431 KASSERT(p->p_vmspace != NULL, ("trap_pfault: vmspace NULL")); 432 map = &p->p_vmspace->vm_map; 433 } else { 434 if (eva < VM_MAXUSER_ADDRESS) { 435 436 if (p->p_vmspace == NULL) 437 return (SIGSEGV); 438 439 map = &p->p_vmspace->vm_map; 440 441 } else { 442 map = kernel_map; 443 } 444 } 445 va = trunc_page(eva); 446 447 if (map != kernel_map) { 448 /* 449 * Keep swapout from messing with us during this 450 * critical time. 451 */ 452 PROC_LOCK(p); 453 ++p->p_lock; 454 PROC_UNLOCK(p); 455 456 /* Fault in the user page: */ 457 rv = vm_fault(map, va, ftype, VM_FAULT_NORMAL); 458 459 PROC_LOCK(p); 460 --p->p_lock; 461 PROC_UNLOCK(p); 462 } else { 463 /* 464 * Don't have to worry about process locking or stacks in the 465 * kernel. 466 */ 467 rv = vm_fault(map, va, ftype, VM_FAULT_NORMAL); 468 } 469 470 if (rv == KERN_SUCCESS) 471 return (0); 472 473 if (!user && handle_onfault(frame)) 474 return (0); 475 476 return ((rv == KERN_PROTECTION_FAILURE) ? SIGBUS : SIGSEGV); 477} 478 479int 480badaddr(void *addr, size_t size) 481{ 482 483 return (badaddr_read(addr, size, NULL)); 484} 485 486int 487badaddr_read(void *addr, size_t size, int *rptr) 488{ 489 struct thread *td; 490 faultbuf env; 491 int x; 492 493 /* Get rid of any stale machine checks that have been waiting. */ 494 __asm __volatile ("sync; isync"); 495 496 td = curthread; 497 498 if (setfault(env)) { 499 td->td_pcb->pcb_onfault = 0; 500 __asm __volatile ("sync"); 501 return (1); 502 } 503 504 __asm __volatile ("sync"); 505 506 switch (size) { 507 case 1: 508 x = *(volatile int8_t *)addr; 509 break; 510 case 2: 511 x = *(volatile int16_t *)addr; 512 break; 513 case 4: 514 x = *(volatile int32_t *)addr; 515 break; 516 default: 517 panic("badaddr: invalid size (%d)", size); 518 } 519 520 /* Make sure we took the machine check, if we caused one. */ 521 __asm __volatile ("sync; isync"); 522 523 td->td_pcb->pcb_onfault = 0; 524 __asm __volatile ("sync"); /* To be sure. */ 525 526 /* Use the value to avoid reorder. */ 527 if (rptr) 528 *rptr = x; 529 530 return (0); 531} 532 533/* 534 * For now, this only deals with the particular unaligned access case 535 * that gcc tends to generate. Eventually it should handle all of the 536 * possibilities that can happen on a 32-bit PowerPC in big-endian mode. 537 */ 538 539static int 540fix_unaligned(struct thread *td, struct trapframe *frame) 541{ 542#if 0 543 struct thread *fputhread; 544 int indicator, reg; 545 double *fpr; 546 547 indicator = EXC_ALI_OPCODE_INDICATOR(frame->dsisr); 548 549 switch (indicator) { 550 case EXC_ALI_LFD: 551 case EXC_ALI_STFD: 552 reg = EXC_ALI_RST(frame->dsisr); 553 fpr = &td->td_pcb->pcb_fpu.fpr[reg]; 554 fputhread = PCPU_GET(fputhread); 555 /* Juggle the FPU to ensure that we've initialized 556 * the FPRs, and that their current state is in 557 * the PCB. 558 */ 559 if (fputhread != td) { 560 if (fputhread) 561 save_fpu(fputhread); 562 enable_fpu(td); 563 } 564 save_fpu(td); 565 566 if (indicator == EXC_ALI_LFD) { 567 if (copyin((void *)frame->dar, fpr, 568 sizeof(double)) != 0) 569 return -1; 570 enable_fpu(td); 571 } else { 572 if (copyout(fpr, (void *)frame->dar, 573 sizeof(double)) != 0) 574 return -1; 575 } 576 return 0; 577 break; 578 } 579 580#endif 581 return (-1); 582} 583 584#ifdef KDB 585int db_trap_glue(struct trapframe *); 586int 587db_trap_glue(struct trapframe *tf) 588{ 589 if (!(tf->srr1 & PSL_PR)) 590 return (kdb_trap(tf->exc, 0, tf)); 591 return (0); 592} 593#endif 594