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