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