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