1176771Sraj/*- 2176771Sraj * Copyright (C) 1995, 1996 Wolfgang Solfrank. 3176771Sraj * Copyright (C) 1995, 1996 TooLs GmbH. 4176771Sraj * All rights reserved. 5176771Sraj * 6176771Sraj * Redistribution and use in source and binary forms, with or without 7176771Sraj * modification, are permitted provided that the following conditions 8176771Sraj * are met: 9176771Sraj * 1. Redistributions of source code must retain the above copyright 10176771Sraj * notice, this list of conditions and the following disclaimer. 11176771Sraj * 2. Redistributions in binary form must reproduce the above copyright 12176771Sraj * notice, this list of conditions and the following disclaimer in the 13176771Sraj * documentation and/or other materials provided with the distribution. 14176771Sraj * 3. All advertising materials mentioning features or use of this software 15176771Sraj * must display the following acknowledgement: 16176771Sraj * This product includes software developed by TooLs GmbH. 17176771Sraj * 4. The name of TooLs GmbH may not be used to endorse or promote products 18176771Sraj * derived from this software without specific prior written permission. 19176771Sraj * 20176771Sraj * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 21176771Sraj * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 22176771Sraj * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 23176771Sraj * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24176771Sraj * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 25176771Sraj * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 26176771Sraj * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 27176771Sraj * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 28176771Sraj * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 29176771Sraj * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30176771Sraj * 31176771Sraj * $NetBSD: trap.c,v 1.58 2002/03/04 04:07:35 dbj Exp $ 32176771Sraj */ 33176771Sraj 34176771Sraj#include <sys/cdefs.h> 35176771Sraj__FBSDID("$FreeBSD: stable/10/sys/powerpc/booke/trap.c 333205 2018-05-03 07:57:08Z avg $"); 36176771Sraj 37176771Sraj#include "opt_fpu_emu.h" 38176771Sraj 39176771Sraj#include <sys/param.h> 40176771Sraj#include <sys/kdb.h> 41176771Sraj#include <sys/proc.h> 42176771Sraj#include <sys/ktr.h> 43176771Sraj#include <sys/lock.h> 44176771Sraj#include <sys/mutex.h> 45176771Sraj#include <sys/pioctl.h> 46176771Sraj#include <sys/ptrace.h> 47176771Sraj#include <sys/reboot.h> 48176771Sraj#include <sys/syscall.h> 49176771Sraj#include <sys/sysent.h> 50176771Sraj#include <sys/systm.h> 51275794Skib#include <sys/kernel.h> 52176771Sraj#include <sys/uio.h> 53176771Sraj#include <sys/signalvar.h> 54176771Sraj#include <sys/vmmeter.h> 55176771Sraj 56176771Sraj#include <security/audit/audit.h> 57176771Sraj 58176771Sraj#include <vm/vm.h> 59176771Sraj#include <vm/pmap.h> 60176771Sraj#include <vm/vm_extern.h> 61176771Sraj#include <vm/vm_param.h> 62176771Sraj#include <vm/vm_kern.h> 63176771Sraj#include <vm/vm_map.h> 64176771Sraj#include <vm/vm_page.h> 65176771Sraj 66176771Sraj#include <machine/cpu.h> 67176771Sraj#include <machine/db_machdep.h> 68176771Sraj#include <machine/frame.h> 69176771Sraj#include <machine/pcb.h> 70176771Sraj#include <machine/pmap.h> 71176771Sraj#include <machine/psl.h> 72176771Sraj#include <machine/trap.h> 73176771Sraj#include <machine/spr.h> 74176771Sraj 75176771Sraj#define FAULTBUF_LR 0 76176771Sraj#define FAULTBUF_R1 1 77176771Sraj#define FAULTBUF_R2 2 78176771Sraj#define FAULTBUF_CR 3 79176771Sraj#define FAULTBUF_CTR 4 80176771Sraj#define FAULTBUF_XER 5 81176771Sraj#define FAULTBUF_R13 6 82176771Sraj 83176771Srajstatic void trap_fatal(struct trapframe *frame); 84176771Srajstatic void printtrap(u_int vector, struct trapframe *frame, int isfatal, 85176771Sraj int user); 86176771Srajstatic int trap_pfault(struct trapframe *frame, int user); 87176771Srajstatic int fix_unaligned(struct thread *td, struct trapframe *frame); 88176771Srajstatic int handle_onfault(struct trapframe *frame); 89176771Srajstatic void syscall(struct trapframe *frame); 90176771Sraj 91176771Srajstruct powerpc_exception { 92176771Sraj u_int vector; 93176771Sraj char *name; 94176771Sraj}; 95176771Sraj 96176771Srajstatic struct powerpc_exception powerpc_exceptions[] = { 97176771Sraj { EXC_CRIT, "critical input" }, 98176771Sraj { EXC_MCHK, "machine check" }, 99176771Sraj { EXC_DSI, "data storage interrupt" }, 100176771Sraj { EXC_ISI, "instruction storage interrupt" }, 101176771Sraj { EXC_EXI, "external interrupt" }, 102176771Sraj { EXC_ALI, "alignment" }, 103176771Sraj { EXC_PGM, "program" }, 104176771Sraj { EXC_SC, "system call" }, 105176771Sraj { EXC_APU, "auxiliary proc unavailable" }, 106176771Sraj { EXC_DECR, "decrementer" }, 107176771Sraj { EXC_FIT, "fixed-interval timer" }, 108176771Sraj { EXC_WDOG, "watchdog timer" }, 109176771Sraj { EXC_DTMISS, "data tlb miss" }, 110176771Sraj { EXC_ITMISS, "instruction tlb miss" }, 111176771Sraj { EXC_DEBUG, "debug" }, 112176771Sraj { EXC_PERF, "performance monitoring" }, 113176771Sraj { EXC_LAST, NULL } 114176771Sraj}; 115176771Sraj 116176771Srajstatic const char * 117176771Srajtrapname(u_int vector) 118176771Sraj{ 119176771Sraj struct powerpc_exception *pe; 120176771Sraj 121176771Sraj for (pe = powerpc_exceptions; pe->vector != EXC_LAST; pe++) { 122176771Sraj if (pe->vector == vector) 123176771Sraj return (pe->name); 124176771Sraj } 125176771Sraj 126176771Sraj return ("unknown"); 127176771Sraj} 128176771Sraj 129176771Srajvoid 130176771Srajtrap(struct trapframe *frame) 131176771Sraj{ 132176771Sraj struct thread *td; 133176771Sraj struct proc *p; 134176771Sraj int sig, type, user; 135176771Sraj ksiginfo_t ksi; 136176771Sraj 137238032Smarcel#ifdef KDB 138238032Smarcel if (kdb_active) { 139238032Smarcel kdb_reenter(); 140238032Smarcel return; 141238032Smarcel } 142238032Smarcel#endif 143238032Smarcel 144176771Sraj PCPU_INC(cnt.v_trap); 145176771Sraj 146223485Snwhitehorn td = curthread; 147176771Sraj p = td->td_proc; 148176771Sraj 149176771Sraj type = frame->exc; 150176771Sraj sig = 0; 151176771Sraj user = (frame->srr1 & PSL_PR) ? 1 : 0; 152176771Sraj 153176771Sraj CTR3(KTR_TRAP, "trap: %s type=%s (%s)", p->p_comm, 154176771Sraj trapname(type), user ? "user" : "kernel"); 155176771Sraj 156176771Sraj if (user) { 157176771Sraj td->td_frame = frame; 158176771Sraj if (td->td_ucred != p->p_ucred) 159176771Sraj cred_update_thread(td); 160176771Sraj 161176771Sraj /* User Mode Traps */ 162176771Sraj switch (type) { 163176771Sraj case EXC_DSI: 164176771Sraj case EXC_ISI: 165176771Sraj sig = trap_pfault(frame, 1); 166176771Sraj break; 167176771Sraj 168176771Sraj case EXC_SC: 169176771Sraj syscall(frame); 170176771Sraj break; 171176771Sraj 172176771Sraj case EXC_ALI: 173176771Sraj if (fix_unaligned(td, frame) != 0) 174176771Sraj sig = SIGBUS; 175176771Sraj else 176176771Sraj frame->srr0 += 4; 177176771Sraj break; 178176771Sraj 179176771Sraj case EXC_DEBUG: /* Single stepping */ 180176771Sraj mtspr(SPR_DBSR, mfspr(SPR_DBSR)); 181176771Sraj frame->srr1 &= ~PSL_DE; 182189100Sraj frame->cpu.booke.dbcr0 &= ~(DBCR0_IDM || DBCR0_IC); 183176771Sraj sig = SIGTRAP; 184176771Sraj break; 185176771Sraj 186176771Sraj case EXC_PGM: /* Program exception */ 187266005Sian sig = ppc_instr_emulate(frame, td->td_pcb); 188176771Sraj break; 189176771Sraj 190176771Sraj default: 191176771Sraj trap_fatal(frame); 192176771Sraj } 193176771Sraj } else { 194176771Sraj /* Kernel Mode Traps */ 195176771Sraj KASSERT(cold || td->td_ucred != NULL, 196176771Sraj ("kernel trap doesn't have ucred")); 197176771Sraj 198176771Sraj switch (type) { 199176771Sraj case EXC_DEBUG: 200176771Sraj mtspr(SPR_DBSR, mfspr(SPR_DBSR)); 201176771Sraj kdb_trap(frame->exc, 0, frame); 202176771Sraj return; 203176771Sraj 204176771Sraj case EXC_DSI: 205176771Sraj if (trap_pfault(frame, 0) == 0) 206176771Sraj return; 207176771Sraj break; 208176771Sraj 209176771Sraj case EXC_MCHK: 210176771Sraj if (handle_onfault(frame)) 211176771Sraj return; 212176771Sraj break; 213176771Sraj#ifdef KDB 214176771Sraj case EXC_PGM: 215176771Sraj if (frame->cpu.booke.esr & ESR_PTR) 216176771Sraj kdb_trap(EXC_PGM, 0, frame); 217176771Sraj return; 218176771Sraj#endif 219176771Sraj default: 220176771Sraj break; 221176771Sraj } 222176771Sraj trap_fatal(frame); 223176771Sraj } 224176771Sraj 225176771Sraj if (sig != 0) { 226176771Sraj if (p->p_sysent->sv_transtrap != NULL) 227176771Sraj sig = (p->p_sysent->sv_transtrap)(sig, type); 228176771Sraj ksiginfo_init_trap(&ksi); 229176771Sraj ksi.ksi_signo = sig; 230176771Sraj ksi.ksi_code = type; /* XXX, not POSIX */ 231176771Sraj /* ksi.ksi_addr = ? */ 232176771Sraj ksi.ksi_trapno = type; 233176771Sraj trapsignal(td, &ksi); 234176771Sraj } 235176771Sraj 236176771Sraj userret(td, frame); 237176771Sraj} 238176771Sraj 239176771Srajstatic void 240176771Srajtrap_fatal(struct trapframe *frame) 241176771Sraj{ 242333205Savg#ifdef KDB 243333205Savg bool handled; 244333205Savg#endif 245176771Sraj 246176771Sraj printtrap(frame->exc, frame, 1, (frame->srr1 & PSL_PR)); 247176771Sraj#ifdef KDB 248333205Savg if (debugger_on_panic) { 249333205Savg kdb_why = KDB_WHY_TRAP; 250333205Savg handled = kdb_trap(frame->exc, 0, frame); 251333205Savg kdb_why = KDB_WHY_UNSET; 252333205Savg if (handled) 253333205Savg return; 254333205Savg } 255176771Sraj#endif 256176771Sraj panic("%s trap", trapname(frame->exc)); 257176771Sraj} 258176771Sraj 259176771Srajstatic void 260176771Srajprinttrap(u_int vector, struct trapframe *frame, int isfatal, int user) 261176771Sraj{ 262176771Sraj register_t va = 0; 263176771Sraj 264176771Sraj printf("\n"); 265176771Sraj printf("%s %s trap:\n", isfatal ? "fatal" : "handled", 266176771Sraj user ? "user" : "kernel"); 267176771Sraj printf("\n"); 268176771Sraj printf(" exception = 0x%x (%s)\n", vector, trapname(vector)); 269176771Sraj 270176771Sraj switch (vector) { 271176771Sraj case EXC_DTMISS: 272176771Sraj case EXC_DSI: 273176771Sraj va = frame->cpu.booke.dear; 274176771Sraj break; 275176771Sraj 276176771Sraj case EXC_ITMISS: 277176771Sraj case EXC_ISI: 278176771Sraj va = frame->srr0; 279176771Sraj break; 280176771Sraj } 281176771Sraj 282176771Sraj printf(" virtual address = 0x%08x\n", va); 283176771Sraj printf(" srr0 = 0x%08x\n", frame->srr0); 284176771Sraj printf(" srr1 = 0x%08x\n", frame->srr1); 285176771Sraj printf(" curthread = %p\n", curthread); 286176771Sraj if (curthread != NULL) 287176771Sraj printf(" pid = %d, comm = %s\n", 288176771Sraj curthread->td_proc->p_pid, curthread->td_proc->p_comm); 289176771Sraj printf("\n"); 290176771Sraj} 291176771Sraj 292176771Sraj/* 293176771Sraj * Handles a fatal fault when we have onfault state to recover. Returns 294176771Sraj * non-zero if there was onfault recovery state available. 295176771Sraj */ 296176771Srajstatic int 297176771Srajhandle_onfault(struct trapframe *frame) 298176771Sraj{ 299176771Sraj struct thread *td; 300176771Sraj faultbuf *fb; 301176771Sraj 302176771Sraj td = curthread; 303176771Sraj fb = td->td_pcb->pcb_onfault; 304176771Sraj if (fb != NULL) { 305176771Sraj frame->srr0 = (*fb)[FAULTBUF_LR]; 306176771Sraj frame->fixreg[1] = (*fb)[FAULTBUF_R1]; 307176771Sraj frame->fixreg[2] = (*fb)[FAULTBUF_R2]; 308176771Sraj frame->fixreg[3] = 1; 309176771Sraj frame->cr = (*fb)[FAULTBUF_CR]; 310176771Sraj frame->ctr = (*fb)[FAULTBUF_CTR]; 311176771Sraj frame->xer = (*fb)[FAULTBUF_XER]; 312176771Sraj bcopy(&(*fb)[FAULTBUF_R13], &frame->fixreg[13], 313176771Sraj 19 * sizeof(register_t)); 314176771Sraj return (1); 315176771Sraj } 316176771Sraj return (0); 317176771Sraj} 318176771Sraj 319208453Skibint 320208453Skibcpu_fetch_syscall_args(struct thread *td, struct syscall_args *sa) 321176771Sraj{ 322208453Skib struct proc *p; 323208453Skib struct trapframe *frame; 324208453Skib caddr_t params; 325208453Skib int error, n; 326176771Sraj 327176771Sraj p = td->td_proc; 328208453Skib frame = td->td_frame; 329176771Sraj 330208453Skib sa->code = frame->fixreg[0]; 331176771Sraj params = (caddr_t)(frame->fixreg + FIRSTARG); 332176771Sraj n = NARGREG; 333176771Sraj 334208453Skib if (sa->code == SYS_syscall) { 335176771Sraj /* 336176771Sraj * code is first argument, 337176771Sraj * followed by actual args. 338176771Sraj */ 339208453Skib sa->code = *(u_int *) params; 340176771Sraj params += sizeof(register_t); 341176771Sraj n -= 1; 342208453Skib } else if (sa->code == SYS___syscall) { 343176771Sraj /* 344176771Sraj * Like syscall, but code is a quad, 345176771Sraj * so as to maintain quad alignment 346176771Sraj * for the rest of the args. 347176771Sraj */ 348176771Sraj params += sizeof(register_t); 349208453Skib sa->code = *(u_int *) params; 350176771Sraj params += sizeof(register_t); 351176771Sraj n -= 2; 352176771Sraj } 353176771Sraj 354176771Sraj if (p->p_sysent->sv_mask) 355208453Skib sa->code &= p->p_sysent->sv_mask; 356208453Skib if (sa->code >= p->p_sysent->sv_size) 357208453Skib sa->callp = &p->p_sysent->sv_table[0]; 358176771Sraj else 359208453Skib sa->callp = &p->p_sysent->sv_table[sa->code]; 360208453Skib sa->narg = sa->callp->sy_narg; 361176771Sraj 362208453Skib bcopy(params, sa->args, n * sizeof(register_t)); 363208453Skib if (sa->narg > n) { 364208453Skib error = copyin(MOREARGS(frame->fixreg[1]), sa->args + n, 365208453Skib (sa->narg - n) * sizeof(register_t)); 366176771Sraj } else 367176771Sraj error = 0; 368176771Sraj 369176771Sraj if (error == 0) { 370176771Sraj td->td_retval[0] = 0; 371176771Sraj td->td_retval[1] = frame->fixreg[FIRSTARG + 1]; 372176771Sraj } 373208453Skib return (error); 374208453Skib} 375176771Sraj 376225474Skib#include "../../kern/subr_syscall.c" 377225474Skib 378208453Skibvoid 379208453Skibsyscall(struct trapframe *frame) 380208453Skib{ 381208453Skib struct thread *td; 382208453Skib struct syscall_args sa; 383208453Skib int error; 384176771Sraj 385223485Snwhitehorn td = curthread; 386208453Skib td->td_frame = frame; 387176771Sraj 388208453Skib error = syscallenter(td, &sa); 389208453Skib syscallret(td, error, &sa); 390176771Sraj} 391176771Sraj 392176771Srajstatic int 393176771Srajtrap_pfault(struct trapframe *frame, int user) 394176771Sraj{ 395176771Sraj vm_offset_t eva, va; 396176771Sraj struct thread *td; 397176771Sraj struct proc *p; 398176771Sraj vm_map_t map; 399176771Sraj vm_prot_t ftype; 400176771Sraj int rv; 401176771Sraj 402176771Sraj td = curthread; 403176771Sraj p = td->td_proc; 404176771Sraj 405176771Sraj if (frame->exc == EXC_ISI) { 406176771Sraj eva = frame->srr0; 407176771Sraj ftype = VM_PROT_READ | VM_PROT_EXECUTE; 408176771Sraj 409176771Sraj } else { 410176771Sraj eva = frame->cpu.booke.dear; 411176771Sraj if (frame->cpu.booke.esr & ESR_ST) 412176771Sraj ftype = VM_PROT_WRITE; 413176771Sraj else 414176771Sraj ftype = VM_PROT_READ; 415176771Sraj } 416176771Sraj 417176771Sraj if (user) { 418176771Sraj KASSERT(p->p_vmspace != NULL, ("trap_pfault: vmspace NULL")); 419176771Sraj map = &p->p_vmspace->vm_map; 420176771Sraj } else { 421176771Sraj if (eva < VM_MAXUSER_ADDRESS) { 422176771Sraj 423176771Sraj if (p->p_vmspace == NULL) 424176771Sraj return (SIGSEGV); 425176771Sraj 426176771Sraj map = &p->p_vmspace->vm_map; 427176771Sraj 428176771Sraj } else { 429176771Sraj map = kernel_map; 430176771Sraj } 431176771Sraj } 432176771Sraj va = trunc_page(eva); 433176771Sraj 434176771Sraj if (map != kernel_map) { 435176771Sraj /* 436176771Sraj * Keep swapout from messing with us during this 437176771Sraj * critical time. 438176771Sraj */ 439176771Sraj PROC_LOCK(p); 440176771Sraj ++p->p_lock; 441176771Sraj PROC_UNLOCK(p); 442176771Sraj 443176771Sraj /* Fault in the user page: */ 444199868Salc rv = vm_fault(map, va, ftype, VM_FAULT_NORMAL); 445176771Sraj 446176771Sraj PROC_LOCK(p); 447176771Sraj --p->p_lock; 448176771Sraj PROC_UNLOCK(p); 449176771Sraj } else { 450176771Sraj /* 451176771Sraj * Don't have to worry about process locking or stacks in the 452176771Sraj * kernel. 453176771Sraj */ 454176771Sraj rv = vm_fault(map, va, ftype, VM_FAULT_NORMAL); 455176771Sraj } 456176771Sraj 457176771Sraj if (rv == KERN_SUCCESS) 458176771Sraj return (0); 459176771Sraj 460176771Sraj if (!user && handle_onfault(frame)) 461176771Sraj return (0); 462176771Sraj 463176771Sraj return ((rv == KERN_PROTECTION_FAILURE) ? SIGBUS : SIGSEGV); 464176771Sraj} 465176771Sraj 466176771Sraj/* 467176771Sraj * For now, this only deals with the particular unaligned access case 468176771Sraj * that gcc tends to generate. Eventually it should handle all of the 469176771Sraj * possibilities that can happen on a 32-bit PowerPC in big-endian mode. 470176771Sraj */ 471176771Sraj 472176771Srajstatic int 473176771Srajfix_unaligned(struct thread *td, struct trapframe *frame) 474176771Sraj{ 475176771Sraj#if 0 476176771Sraj struct thread *fputhread; 477176771Sraj int indicator, reg; 478176771Sraj double *fpr; 479176771Sraj 480176771Sraj indicator = EXC_ALI_OPCODE_INDICATOR(frame->dsisr); 481176771Sraj 482176771Sraj switch (indicator) { 483176771Sraj case EXC_ALI_LFD: 484176771Sraj case EXC_ALI_STFD: 485176771Sraj reg = EXC_ALI_RST(frame->dsisr); 486176771Sraj fpr = &td->td_pcb->pcb_fpu.fpr[reg]; 487176771Sraj fputhread = PCPU_GET(fputhread); 488176771Sraj /* Juggle the FPU to ensure that we've initialized 489176771Sraj * the FPRs, and that their current state is in 490176771Sraj * the PCB. 491176771Sraj */ 492176771Sraj if (fputhread != td) { 493176771Sraj if (fputhread) 494176771Sraj save_fpu(fputhread); 495176771Sraj enable_fpu(td); 496176771Sraj } 497176771Sraj save_fpu(td); 498176771Sraj 499176771Sraj if (indicator == EXC_ALI_LFD) { 500176771Sraj if (copyin((void *)frame->dar, fpr, 501176771Sraj sizeof(double)) != 0) 502176771Sraj return -1; 503176771Sraj enable_fpu(td); 504176771Sraj } else { 505176771Sraj if (copyout(fpr, (void *)frame->dar, 506176771Sraj sizeof(double)) != 0) 507176771Sraj return -1; 508176771Sraj } 509176771Sraj return 0; 510176771Sraj break; 511176771Sraj } 512176771Sraj 513176771Sraj#endif 514176771Sraj return (-1); 515176771Sraj} 516176771Sraj 517176771Sraj#ifdef KDB 518176771Srajint db_trap_glue(struct trapframe *); 519176771Srajint 520176771Srajdb_trap_glue(struct trapframe *tf) 521176771Sraj{ 522176771Sraj if (!(tf->srr1 & PSL_PR)) 523176771Sraj return (kdb_trap(tf->exc, 0, tf)); 524176771Sraj return (0); 525176771Sraj} 526176771Sraj#endif 527