trap.c revision 333205
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 333205 2018-05-03 07:57:08Z avg $"); 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#ifdef KDB 243 bool handled; 244#endif 245 246 printtrap(frame->exc, frame, 1, (frame->srr1 & PSL_PR)); 247#ifdef KDB 248 if (debugger_on_panic) { 249 kdb_why = KDB_WHY_TRAP; 250 handled = kdb_trap(frame->exc, 0, frame); 251 kdb_why = KDB_WHY_UNSET; 252 if (handled) 253 return; 254 } 255#endif 256 panic("%s trap", trapname(frame->exc)); 257} 258 259static void 260printtrap(u_int vector, struct trapframe *frame, int isfatal, int user) 261{ 262 register_t va = 0; 263 264 printf("\n"); 265 printf("%s %s trap:\n", isfatal ? "fatal" : "handled", 266 user ? "user" : "kernel"); 267 printf("\n"); 268 printf(" exception = 0x%x (%s)\n", vector, trapname(vector)); 269 270 switch (vector) { 271 case EXC_DTMISS: 272 case EXC_DSI: 273 va = frame->cpu.booke.dear; 274 break; 275 276 case EXC_ITMISS: 277 case EXC_ISI: 278 va = frame->srr0; 279 break; 280 } 281 282 printf(" virtual address = 0x%08x\n", va); 283 printf(" srr0 = 0x%08x\n", frame->srr0); 284 printf(" srr1 = 0x%08x\n", frame->srr1); 285 printf(" curthread = %p\n", curthread); 286 if (curthread != NULL) 287 printf(" pid = %d, comm = %s\n", 288 curthread->td_proc->p_pid, curthread->td_proc->p_comm); 289 printf("\n"); 290} 291 292/* 293 * Handles a fatal fault when we have onfault state to recover. Returns 294 * non-zero if there was onfault recovery state available. 295 */ 296static int 297handle_onfault(struct trapframe *frame) 298{ 299 struct thread *td; 300 faultbuf *fb; 301 302 td = curthread; 303 fb = td->td_pcb->pcb_onfault; 304 if (fb != NULL) { 305 frame->srr0 = (*fb)[FAULTBUF_LR]; 306 frame->fixreg[1] = (*fb)[FAULTBUF_R1]; 307 frame->fixreg[2] = (*fb)[FAULTBUF_R2]; 308 frame->fixreg[3] = 1; 309 frame->cr = (*fb)[FAULTBUF_CR]; 310 frame->ctr = (*fb)[FAULTBUF_CTR]; 311 frame->xer = (*fb)[FAULTBUF_XER]; 312 bcopy(&(*fb)[FAULTBUF_R13], &frame->fixreg[13], 313 19 * sizeof(register_t)); 314 return (1); 315 } 316 return (0); 317} 318 319int 320cpu_fetch_syscall_args(struct thread *td, struct syscall_args *sa) 321{ 322 struct proc *p; 323 struct trapframe *frame; 324 caddr_t params; 325 int error, n; 326 327 p = td->td_proc; 328 frame = td->td_frame; 329 330 sa->code = frame->fixreg[0]; 331 params = (caddr_t)(frame->fixreg + FIRSTARG); 332 n = NARGREG; 333 334 if (sa->code == SYS_syscall) { 335 /* 336 * code is first argument, 337 * followed by actual args. 338 */ 339 sa->code = *(u_int *) params; 340 params += sizeof(register_t); 341 n -= 1; 342 } else if (sa->code == SYS___syscall) { 343 /* 344 * Like syscall, but code is a quad, 345 * so as to maintain quad alignment 346 * for the rest of the args. 347 */ 348 params += sizeof(register_t); 349 sa->code = *(u_int *) params; 350 params += sizeof(register_t); 351 n -= 2; 352 } 353 354 if (p->p_sysent->sv_mask) 355 sa->code &= p->p_sysent->sv_mask; 356 if (sa->code >= p->p_sysent->sv_size) 357 sa->callp = &p->p_sysent->sv_table[0]; 358 else 359 sa->callp = &p->p_sysent->sv_table[sa->code]; 360 sa->narg = sa->callp->sy_narg; 361 362 bcopy(params, sa->args, n * sizeof(register_t)); 363 if (sa->narg > n) { 364 error = copyin(MOREARGS(frame->fixreg[1]), sa->args + n, 365 (sa->narg - n) * sizeof(register_t)); 366 } else 367 error = 0; 368 369 if (error == 0) { 370 td->td_retval[0] = 0; 371 td->td_retval[1] = frame->fixreg[FIRSTARG + 1]; 372 } 373 return (error); 374} 375 376#include "../../kern/subr_syscall.c" 377 378void 379syscall(struct trapframe *frame) 380{ 381 struct thread *td; 382 struct syscall_args sa; 383 int error; 384 385 td = curthread; 386 td->td_frame = frame; 387 388 error = syscallenter(td, &sa); 389 syscallret(td, error, &sa); 390} 391 392static int 393trap_pfault(struct trapframe *frame, int user) 394{ 395 vm_offset_t eva, va; 396 struct thread *td; 397 struct proc *p; 398 vm_map_t map; 399 vm_prot_t ftype; 400 int rv; 401 402 td = curthread; 403 p = td->td_proc; 404 405 if (frame->exc == EXC_ISI) { 406 eva = frame->srr0; 407 ftype = VM_PROT_READ | VM_PROT_EXECUTE; 408 409 } else { 410 eva = frame->cpu.booke.dear; 411 if (frame->cpu.booke.esr & ESR_ST) 412 ftype = VM_PROT_WRITE; 413 else 414 ftype = VM_PROT_READ; 415 } 416 417 if (user) { 418 KASSERT(p->p_vmspace != NULL, ("trap_pfault: vmspace NULL")); 419 map = &p->p_vmspace->vm_map; 420 } else { 421 if (eva < VM_MAXUSER_ADDRESS) { 422 423 if (p->p_vmspace == NULL) 424 return (SIGSEGV); 425 426 map = &p->p_vmspace->vm_map; 427 428 } else { 429 map = kernel_map; 430 } 431 } 432 va = trunc_page(eva); 433 434 if (map != kernel_map) { 435 /* 436 * Keep swapout from messing with us during this 437 * critical time. 438 */ 439 PROC_LOCK(p); 440 ++p->p_lock; 441 PROC_UNLOCK(p); 442 443 /* Fault in the user page: */ 444 rv = vm_fault(map, va, ftype, VM_FAULT_NORMAL); 445 446 PROC_LOCK(p); 447 --p->p_lock; 448 PROC_UNLOCK(p); 449 } else { 450 /* 451 * Don't have to worry about process locking or stacks in the 452 * kernel. 453 */ 454 rv = vm_fault(map, va, ftype, VM_FAULT_NORMAL); 455 } 456 457 if (rv == KERN_SUCCESS) 458 return (0); 459 460 if (!user && handle_onfault(frame)) 461 return (0); 462 463 return ((rv == KERN_PROTECTION_FAILURE) ? SIGBUS : SIGSEGV); 464} 465 466/* 467 * For now, this only deals with the particular unaligned access case 468 * that gcc tends to generate. Eventually it should handle all of the 469 * possibilities that can happen on a 32-bit PowerPC in big-endian mode. 470 */ 471 472static int 473fix_unaligned(struct thread *td, struct trapframe *frame) 474{ 475#if 0 476 struct thread *fputhread; 477 int indicator, reg; 478 double *fpr; 479 480 indicator = EXC_ALI_OPCODE_INDICATOR(frame->dsisr); 481 482 switch (indicator) { 483 case EXC_ALI_LFD: 484 case EXC_ALI_STFD: 485 reg = EXC_ALI_RST(frame->dsisr); 486 fpr = &td->td_pcb->pcb_fpu.fpr[reg]; 487 fputhread = PCPU_GET(fputhread); 488 /* Juggle the FPU to ensure that we've initialized 489 * the FPRs, and that their current state is in 490 * the PCB. 491 */ 492 if (fputhread != td) { 493 if (fputhread) 494 save_fpu(fputhread); 495 enable_fpu(td); 496 } 497 save_fpu(td); 498 499 if (indicator == EXC_ALI_LFD) { 500 if (copyin((void *)frame->dar, fpr, 501 sizeof(double)) != 0) 502 return -1; 503 enable_fpu(td); 504 } else { 505 if (copyout(fpr, (void *)frame->dar, 506 sizeof(double)) != 0) 507 return -1; 508 } 509 return 0; 510 break; 511 } 512 513#endif 514 return (-1); 515} 516 517#ifdef KDB 518int db_trap_glue(struct trapframe *); 519int 520db_trap_glue(struct trapframe *tf) 521{ 522 if (!(tf->srr1 & PSL_PR)) 523 return (kdb_trap(tf->exc, 0, tf)); 524 return (0); 525} 526#endif 527