1139825Simp/*- 277957Sbenno * Copyright (C) 1995, 1996 Wolfgang Solfrank. 377957Sbenno * Copyright (C) 1995, 1996 TooLs GmbH. 477957Sbenno * All rights reserved. 577957Sbenno * 677957Sbenno * Redistribution and use in source and binary forms, with or without 777957Sbenno * modification, are permitted provided that the following conditions 877957Sbenno * are met: 977957Sbenno * 1. Redistributions of source code must retain the above copyright 1077957Sbenno * notice, this list of conditions and the following disclaimer. 1177957Sbenno * 2. Redistributions in binary form must reproduce the above copyright 1277957Sbenno * notice, this list of conditions and the following disclaimer in the 1377957Sbenno * documentation and/or other materials provided with the distribution. 1477957Sbenno * 3. All advertising materials mentioning features or use of this software 1577957Sbenno * must display the following acknowledgement: 1677957Sbenno * This product includes software developed by TooLs GmbH. 1777957Sbenno * 4. The name of TooLs GmbH may not be used to endorse or promote products 1877957Sbenno * derived from this software without specific prior written permission. 1977957Sbenno * 2077957Sbenno * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 2177957Sbenno * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 2277957Sbenno * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2377957Sbenno * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 2477957Sbenno * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 2577957Sbenno * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 2677957Sbenno * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 2777957Sbenno * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 2877957Sbenno * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 2977957Sbenno * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3077957Sbenno * 3196255Sbenno * $NetBSD: trap.c,v 1.58 2002/03/04 04:07:35 dbj Exp $ 3277957Sbenno */ 3377957Sbenno 34113038Sobrien#include <sys/cdefs.h> 35113038Sobrien__FBSDID("$FreeBSD: stable/11/sys/powerpc/powerpc/trap.c 344905 2019-03-08 00:20:37Z jhb $"); 3677957Sbenno 3777957Sbenno#include <sys/param.h> 38132074Sgrehan#include <sys/kdb.h> 3996938Sbenno#include <sys/proc.h> 4096938Sbenno#include <sys/ktr.h> 4186067Smp#include <sys/lock.h> 4286067Smp#include <sys/mutex.h> 4396938Sbenno#include <sys/pioctl.h> 44160764Sjhb#include <sys/ptrace.h> 4577957Sbenno#include <sys/reboot.h> 4677957Sbenno#include <sys/syscall.h> 4796938Sbenno#include <sys/sysent.h> 4896255Sbenno#include <sys/systm.h> 49275683Sandreast#include <sys/kernel.h> 5096906Sbenno#include <sys/uio.h> 51143633Sgrehan#include <sys/signalvar.h> 5296938Sbenno#include <sys/vmmeter.h> 5377957Sbenno 54162361Srwatson#include <security/audit/audit.h> 55162361Srwatson 5677957Sbenno#include <vm/vm.h> 5786067Smp#include <vm/pmap.h> 5886067Smp#include <vm/vm_extern.h> 5996255Sbenno#include <vm/vm_param.h> 6077957Sbenno#include <vm/vm_kern.h> 6186067Smp#include <vm/vm_map.h> 6296255Sbenno#include <vm/vm_page.h> 6377957Sbenno 64209975Snwhitehorn#include <machine/_inttypes.h> 65188860Snwhitehorn#include <machine/altivec.h> 6677957Sbenno#include <machine/cpu.h> 6796255Sbenno#include <machine/db_machdep.h> 6896255Sbenno#include <machine/fpu.h> 6977957Sbenno#include <machine/frame.h> 7077957Sbenno#include <machine/pcb.h> 7177957Sbenno#include <machine/psl.h> 7277957Sbenno#include <machine/trap.h> 7396255Sbenno#include <machine/spr.h> 7496255Sbenno#include <machine/sr.h> 7577957Sbenno 76293636Snwhitehorn/* Below matches setjmp.S */ 77293636Snwhitehorn#define FAULTBUF_LR 21 78281096Sjhibbits#define FAULTBUF_R1 1 79281096Sjhibbits#define FAULTBUF_R2 2 80293636Snwhitehorn#define FAULTBUF_CR 22 81293636Snwhitehorn#define FAULTBUF_R14 3 82281096Sjhibbits 83316369Sjhibbits#define MOREARGS(sp) ((caddr_t)((uintptr_t)(sp) + \ 84316369Sjhibbits sizeof(struct callframe) - 3*sizeof(register_t))) /* more args go here */ 85316369Sjhibbits 8696938Sbennostatic void trap_fatal(struct trapframe *frame); 8796938Sbennostatic void printtrap(u_int vector, struct trapframe *frame, int isfatal, 8896938Sbenno int user); 8996938Sbennostatic int trap_pfault(struct trapframe *frame, int user); 9096938Sbennostatic int fix_unaligned(struct thread *td, struct trapframe *frame); 9196938Sbennostatic int handle_onfault(struct trapframe *frame); 9296938Sbennostatic void syscall(struct trapframe *frame); 9396938Sbenno 94209975Snwhitehorn#ifdef __powerpc64__ 95230123Snwhitehorn void handle_kernel_slb_spill(int, register_t, register_t); 96230123Snwhitehornstatic int handle_user_slb_spill(pmap_t pm, vm_offset_t addr); 97230123Snwhitehornextern int n_slbs; 98209975Snwhitehorn#endif 99209975Snwhitehorn 10096938Sbennostruct powerpc_exception { 10196938Sbenno u_int vector; 10296938Sbenno char *name; 10396938Sbenno}; 10496938Sbenno 105242723Sjhibbits#ifdef KDTRACE_HOOKS 106242723Sjhibbits#include <sys/dtrace_bsd.h> 107242723Sjhibbits 108248457Sjhibbitsint (*dtrace_invop_jump_addr)(struct trapframe *); 109242723Sjhibbits#endif 110242723Sjhibbits 11196938Sbennostatic struct powerpc_exception powerpc_exceptions[] = { 112281096Sjhibbits { EXC_CRIT, "critical input" }, 113281096Sjhibbits { EXC_RST, "system reset" }, 114281096Sjhibbits { EXC_MCHK, "machine check" }, 115281096Sjhibbits { EXC_DSI, "data storage interrupt" }, 116281096Sjhibbits { EXC_DSE, "data segment exception" }, 117281096Sjhibbits { EXC_ISI, "instruction storage interrupt" }, 118281096Sjhibbits { EXC_ISE, "instruction segment exception" }, 119281096Sjhibbits { EXC_EXI, "external interrupt" }, 120281096Sjhibbits { EXC_ALI, "alignment" }, 121281096Sjhibbits { EXC_PGM, "program" }, 122281096Sjhibbits { EXC_FPU, "floating-point unavailable" }, 123281096Sjhibbits { EXC_APU, "auxiliary proc unavailable" }, 124281096Sjhibbits { EXC_DECR, "decrementer" }, 125281096Sjhibbits { EXC_FIT, "fixed-interval timer" }, 126281096Sjhibbits { EXC_WDOG, "watchdog timer" }, 127281096Sjhibbits { EXC_SC, "system call" }, 128281096Sjhibbits { EXC_TRC, "trace" }, 129281096Sjhibbits { EXC_FPA, "floating-point assist" }, 130281096Sjhibbits { EXC_DEBUG, "debug" }, 131281096Sjhibbits { EXC_PERF, "performance monitoring" }, 132281096Sjhibbits { EXC_VEC, "altivec unavailable" }, 133281096Sjhibbits { EXC_VSX, "vsx unavailable" }, 134281096Sjhibbits { EXC_ITMISS, "instruction tlb miss" }, 135281096Sjhibbits { EXC_DLMISS, "data load tlb miss" }, 136281096Sjhibbits { EXC_DSMISS, "data store tlb miss" }, 137281096Sjhibbits { EXC_BPT, "instruction breakpoint" }, 138281096Sjhibbits { EXC_SMI, "system management" }, 139281096Sjhibbits { EXC_VECAST_G4, "altivec assist" }, 140281096Sjhibbits { EXC_THRM, "thermal management" }, 141281096Sjhibbits { EXC_RUNMODETRC, "run mode/trace" }, 142281096Sjhibbits { EXC_LAST, NULL } 14396938Sbenno}; 14496938Sbenno 14596938Sbennostatic const char * 14696938Sbennotrapname(u_int vector) 14796938Sbenno{ 14896938Sbenno struct powerpc_exception *pe; 14996938Sbenno 150281096Sjhibbits for (pe = powerpc_exceptions; pe->vector != EXC_LAST; pe++) { 15196938Sbenno if (pe->vector == vector) 15296938Sbenno return (pe->name); 15396938Sbenno } 15496938Sbenno 15596938Sbenno return ("unknown"); 15696938Sbenno} 15796938Sbenno 15896255Sbennovoid 15996906Sbennotrap(struct trapframe *frame) 16086067Smp{ 161112429Sgrehan struct thread *td; 16296906Sbenno struct proc *p; 163256543Sjhibbits#ifdef KDTRACE_HOOKS 164256543Sjhibbits uint32_t inst; 165256543Sjhibbits#endif 16696938Sbenno int sig, type, user; 167155455Sphk u_int ucode; 168151316Sdavidxu ksiginfo_t ksi; 16986067Smp 170170291Sattilio PCPU_INC(cnt.v_trap); 17196938Sbenno 172223485Snwhitehorn td = curthread; 17396906Sbenno p = td->td_proc; 17486067Smp 17596938Sbenno type = ucode = frame->exc; 17696938Sbenno sig = 0; 17796938Sbenno user = frame->srr1 & PSL_PR; 17886067Smp 179173601Sjulian CTR3(KTR_TRAP, "trap: %s type=%s (%s)", td->td_name, 18096938Sbenno trapname(type), user ? "user" : "kernel"); 18186067Smp 182242723Sjhibbits#ifdef KDTRACE_HOOKS 183242723Sjhibbits /* 184242723Sjhibbits * A trap can occur while DTrace executes a probe. Before 185242723Sjhibbits * executing the probe, DTrace blocks re-scheduling and sets 186268600Smarkj * a flag in its per-cpu flags to indicate that it doesn't 187242723Sjhibbits * want to fault. On returning from the probe, the no-fault 188242723Sjhibbits * flag is cleared and finally re-scheduling is enabled. 189242723Sjhibbits * 190242723Sjhibbits * If the DTrace kernel module has registered a trap handler, 191242723Sjhibbits * call it and if it returns non-zero, assume that it has 192242723Sjhibbits * handled the trap and modified the trap frame so that this 193242723Sjhibbits * function can return normally. 194242723Sjhibbits */ 195276142Smarkj if (dtrace_trap_func != NULL && (*dtrace_trap_func)(frame, type) != 0) 196248457Sjhibbits return; 197242723Sjhibbits#endif 198242723Sjhibbits 19996938Sbenno if (user) { 200155455Sphk td->td_pticks = 0; 20196938Sbenno td->td_frame = frame; 202284214Smjg if (td->td_cowgen != p->p_cowgen) 203284214Smjg thread_cow_update(td); 20486067Smp 20596938Sbenno /* User Mode Traps */ 20696938Sbenno switch (type) { 20796938Sbenno case EXC_RUNMODETRC: 20896938Sbenno case EXC_TRC: 20996938Sbenno frame->srr1 &= ~PSL_SE; 21096938Sbenno sig = SIGTRAP; 211269701Sjhibbits ucode = TRAP_TRACE; 21296938Sbenno break; 21377957Sbenno 214209975Snwhitehorn#ifdef __powerpc64__ 215209975Snwhitehorn case EXC_ISE: 216209975Snwhitehorn case EXC_DSE: 217230123Snwhitehorn if (handle_user_slb_spill(&p->p_vmspace->vm_pmap, 218279601Snwhitehorn (type == EXC_ISE) ? frame->srr0 : frame->dar) != 0){ 219209975Snwhitehorn sig = SIGSEGV; 220269701Sjhibbits ucode = SEGV_MAPERR; 221269701Sjhibbits } 222209975Snwhitehorn break; 223209975Snwhitehorn#endif 22496938Sbenno case EXC_DSI: 22596938Sbenno case EXC_ISI: 22696938Sbenno sig = trap_pfault(frame, 1); 227269701Sjhibbits if (sig == SIGSEGV) 228269701Sjhibbits ucode = SEGV_MAPERR; 22996938Sbenno break; 23096938Sbenno 23196938Sbenno case EXC_SC: 23296938Sbenno syscall(frame); 23396938Sbenno break; 23496938Sbenno 23596938Sbenno case EXC_FPU: 236112429Sgrehan KASSERT((td->td_pcb->pcb_flags & PCB_FPU) != PCB_FPU, 237112429Sgrehan ("FPU already enabled for thread")); 23896938Sbenno enable_fpu(td); 23996938Sbenno break; 24096938Sbenno 24196938Sbenno case EXC_VEC: 242188860Snwhitehorn KASSERT((td->td_pcb->pcb_flags & PCB_VEC) != PCB_VEC, 243188860Snwhitehorn ("Altivec already enabled for thread")); 24496938Sbenno enable_vec(td); 24596938Sbenno break; 246188860Snwhitehorn 247279189Snwhitehorn case EXC_VSX: 248279189Snwhitehorn KASSERT((td->td_pcb->pcb_flags & PCB_VSX) != PCB_VSX, 249279189Snwhitehorn ("VSX already enabled for thread")); 250279189Snwhitehorn if (!(td->td_pcb->pcb_flags & PCB_VEC)) 251279189Snwhitehorn enable_vec(td); 252279189Snwhitehorn if (!(td->td_pcb->pcb_flags & PCB_FPU)) 253279189Snwhitehorn save_fpu(td); 254279189Snwhitehorn td->td_pcb->pcb_flags |= PCB_VSX; 255279189Snwhitehorn enable_fpu(td); 256279189Snwhitehorn break; 257279189Snwhitehorn 258292072Sjhibbits case EXC_VECAST_E: 259213456Snwhitehorn case EXC_VECAST_G4: 260213456Snwhitehorn case EXC_VECAST_G5: 261213456Snwhitehorn /* 262213456Snwhitehorn * We get a VPU assist exception for IEEE mode 263213456Snwhitehorn * vector operations on denormalized floats. 264213456Snwhitehorn * Emulating this is a giant pain, so for now, 265213456Snwhitehorn * just switch off IEEE mode and treat them as 266213456Snwhitehorn * zero. 267213456Snwhitehorn */ 268213456Snwhitehorn 269213456Snwhitehorn save_vec(td); 270213456Snwhitehorn td->td_pcb->pcb_vec.vscr |= ALTIVEC_VSCR_NJ; 271213456Snwhitehorn enable_vec(td); 272148568Sgrehan break; 27396938Sbenno 27496938Sbenno case EXC_ALI: 275269701Sjhibbits if (fix_unaligned(td, frame) != 0) { 27696938Sbenno sig = SIGBUS; 277269701Sjhibbits ucode = BUS_ADRALN; 278269701Sjhibbits } 27977957Sbenno else 28096938Sbenno frame->srr0 += 4; 28196938Sbenno break; 28296938Sbenno 283281096Sjhibbits case EXC_DEBUG: /* Single stepping */ 284281096Sjhibbits mtspr(SPR_DBSR, mfspr(SPR_DBSR)); 285281096Sjhibbits frame->srr1 &= ~PSL_DE; 286316369Sjhibbits frame->cpu.booke.dbcr0 &= ~(DBCR0_IDM | DBCR0_IC); 287281096Sjhibbits sig = SIGTRAP; 288281096Sjhibbits ucode = TRAP_TRACE; 289281096Sjhibbits break; 290281096Sjhibbits 29196938Sbenno case EXC_PGM: 292191261Snwhitehorn /* Identify the trap reason */ 293281096Sjhibbits#ifdef AIM 294256543Sjhibbits if (frame->srr1 & EXC_PGM_TRAP) { 295281096Sjhibbits#else 296281096Sjhibbits if (frame->cpu.booke.esr & ESR_PTR) { 297281096Sjhibbits#endif 298256543Sjhibbits#ifdef KDTRACE_HOOKS 299256543Sjhibbits inst = fuword32((const void *)frame->srr0); 300275268Sjhibbits if (inst == 0x0FFFDDDD && 301275268Sjhibbits dtrace_pid_probe_ptr != NULL) { 302327551Smarkj (*dtrace_pid_probe_ptr)(frame); 303256543Sjhibbits break; 304256543Sjhibbits } 305256543Sjhibbits#endif 306256542Sjhibbits sig = SIGTRAP; 307269701Sjhibbits ucode = TRAP_BRKPT; 308258259Snwhitehorn } else { 309258259Snwhitehorn sig = ppc_instr_emulate(frame, td->td_pcb); 310269701Sjhibbits if (sig == SIGILL) { 311269701Sjhibbits if (frame->srr1 & EXC_PGM_PRIV) 312269701Sjhibbits ucode = ILL_PRVOPC; 313269701Sjhibbits else if (frame->srr1 & EXC_PGM_ILLEGAL) 314269701Sjhibbits ucode = ILL_ILLOPC; 315269701Sjhibbits } else if (sig == SIGFPE) 316269701Sjhibbits ucode = FPE_FLTINV; /* Punt for now, invalid operation. */ 317258259Snwhitehorn } 31896938Sbenno break; 31996938Sbenno 320268880Snwhitehorn case EXC_MCHK: 321268880Snwhitehorn /* 322268880Snwhitehorn * Note that this may not be recoverable for the user 323268880Snwhitehorn * process, depending on the type of machine check, 324268880Snwhitehorn * but it at least prevents the kernel from dying. 325268880Snwhitehorn */ 326268880Snwhitehorn sig = SIGBUS; 327269701Sjhibbits ucode = BUS_OBJERR; 328268880Snwhitehorn break; 329268880Snwhitehorn 33096938Sbenno default: 33196938Sbenno trap_fatal(frame); 33277957Sbenno } 33396938Sbenno } else { 33496938Sbenno /* Kernel Mode Traps */ 33596938Sbenno 33696938Sbenno KASSERT(cold || td->td_ucred != NULL, 33796938Sbenno ("kernel trap doesn't have ucred")); 33896938Sbenno switch (type) { 339248457Sjhibbits#ifdef KDTRACE_HOOKS 340248457Sjhibbits case EXC_PGM: 341248457Sjhibbits if (frame->srr1 & EXC_PGM_TRAP) { 342275268Sjhibbits if (*(uint32_t *)frame->srr0 == EXC_DTRACE) { 343248457Sjhibbits if (dtrace_invop_jump_addr != NULL) { 344248457Sjhibbits dtrace_invop_jump_addr(frame); 345255165Sjhibbits return; 346248457Sjhibbits } 347248457Sjhibbits } 348248457Sjhibbits } 349255165Sjhibbits break; 350248457Sjhibbits#endif 351209975Snwhitehorn#ifdef __powerpc64__ 352214574Snwhitehorn case EXC_DSE: 353279601Snwhitehorn if ((frame->dar & SEGMENT_MASK) == USER_ADDR) { 354214574Snwhitehorn __asm __volatile ("slbmte %0, %1" :: 355230123Snwhitehorn "r"(td->td_pcb->pcb_cpu.aim.usr_vsid), 356230123Snwhitehorn "r"(USER_SLB_SLBE)); 357214574Snwhitehorn return; 358214574Snwhitehorn } 359230123Snwhitehorn break; 360209975Snwhitehorn#endif 361230123Snwhitehorn case EXC_DSI: 362230123Snwhitehorn if (trap_pfault(frame, 0) == 0) 363230123Snwhitehorn return; 364230123Snwhitehorn break; 36596938Sbenno case EXC_MCHK: 36696938Sbenno if (handle_onfault(frame)) 36796938Sbenno return; 36896938Sbenno break; 36996938Sbenno default: 370132994Sgrehan break; 37196255Sbenno } 372132994Sgrehan trap_fatal(frame); 37386067Smp } 37496938Sbenno 37596938Sbenno if (sig != 0) { 37696938Sbenno if (p->p_sysent->sv_transtrap != NULL) 37796938Sbenno sig = (p->p_sysent->sv_transtrap)(sig, type); 378151316Sdavidxu ksiginfo_init_trap(&ksi); 379151316Sdavidxu ksi.ksi_signo = sig; 380151316Sdavidxu ksi.ksi_code = (int) ucode; /* XXX, not POSIX */ 381151316Sdavidxu /* ksi.ksi_addr = ? */ 382151316Sdavidxu ksi.ksi_trapno = type; 383151316Sdavidxu trapsignal(td, &ksi); 38496938Sbenno } 38596938Sbenno 386155455Sphk userret(td, frame); 38796938Sbenno} 38896938Sbenno 38996938Sbennostatic void 39096938Sbennotrap_fatal(struct trapframe *frame) 39196938Sbenno{ 392333204Savg#ifdef KDB 393333204Savg bool handled; 394333204Savg#endif 39596938Sbenno 39696938Sbenno printtrap(frame->exc, frame, 1, (frame->srr1 & PSL_PR)); 397132074Sgrehan#ifdef KDB 398344905Sjhb if (debugger_on_trap) { 399333204Savg kdb_why = KDB_WHY_TRAP; 400333204Savg handled = kdb_trap(frame->exc, 0, frame); 401333204Savg kdb_why = KDB_WHY_UNSET; 402333204Savg if (handled) 403333204Savg return; 404333204Savg } 40596938Sbenno#endif 40696938Sbenno panic("%s trap", trapname(frame->exc)); 40796938Sbenno} 40896938Sbenno 40996938Sbennostatic void 41096938Sbennoprinttrap(u_int vector, struct trapframe *frame, int isfatal, int user) 41196938Sbenno{ 412285144Sjhibbits uint16_t ver; 413291463Sjhibbits#ifdef BOOKE 414291463Sjhibbits vm_paddr_t pa; 415291463Sjhibbits#endif 41696938Sbenno 41796938Sbenno printf("\n"); 41896938Sbenno printf("%s %s trap:\n", isfatal ? "fatal" : "handled", 41996938Sbenno user ? "user" : "kernel"); 42096938Sbenno printf("\n"); 421230123Snwhitehorn printf(" exception = 0x%x (%s)\n", vector, trapname(vector)); 42296938Sbenno switch (vector) { 423209975Snwhitehorn case EXC_DSE: 42496938Sbenno case EXC_DSI: 425281262Sjhibbits case EXC_DTMISS: 426279601Snwhitehorn printf(" virtual address = 0x%" PRIxPTR "\n", frame->dar); 427281262Sjhibbits#ifdef AIM 428286821Sjhibbits printf(" dsisr = 0x%lx\n", 429286821Sjhibbits (u_long)frame->cpu.aim.dsisr); 430281262Sjhibbits#endif 43196255Sbenno break; 432209975Snwhitehorn case EXC_ISE: 43396255Sbenno case EXC_ISI: 434281262Sjhibbits case EXC_ITMISS: 435209975Snwhitehorn printf(" virtual address = 0x%" PRIxPTR "\n", frame->srr0); 43696255Sbenno break; 437285144Sjhibbits case EXC_MCHK: 438285144Sjhibbits ver = mfpvr() >> 16; 439285144Sjhibbits#if defined(AIM) 440285144Sjhibbits if (MPC745X_P(ver)) 441285227Sjhibbits printf(" msssr0 = 0x%lx\n", 442285227Sjhibbits (u_long)mfspr(SPR_MSSSR0)); 443285144Sjhibbits#elif defined(BOOKE) 444291463Sjhibbits pa = mfspr(SPR_MCARU); 445298560Sjhibbits pa = (pa << 32) | (u_register_t)mfspr(SPR_MCAR); 446291463Sjhibbits printf(" mcsr = 0x%lx\n", (u_long)mfspr(SPR_MCSR)); 447291463Sjhibbits printf(" mcar = 0x%jx\n", (uintmax_t)pa); 448285144Sjhibbits#endif 449285144Sjhibbits break; 45096938Sbenno } 451281262Sjhibbits#ifdef BOOKE 452281262Sjhibbits printf(" esr = 0x%" PRIxPTR "\n", 453281262Sjhibbits frame->cpu.booke.esr); 454281262Sjhibbits#endif 455209975Snwhitehorn printf(" srr0 = 0x%" PRIxPTR "\n", frame->srr0); 456286821Sjhibbits printf(" srr1 = 0x%lx\n", (u_long)frame->srr1); 457209975Snwhitehorn printf(" lr = 0x%" PRIxPTR "\n", frame->lr); 45896938Sbenno printf(" curthread = %p\n", curthread); 45996938Sbenno if (curthread != NULL) 46096938Sbenno printf(" pid = %d, comm = %s\n", 461173600Sjulian curthread->td_proc->p_pid, curthread->td_name); 46296938Sbenno printf("\n"); 46396938Sbenno} 46486067Smp 46596938Sbenno/* 46696938Sbenno * Handles a fatal fault when we have onfault state to recover. Returns 46796938Sbenno * non-zero if there was onfault recovery state available. 46896938Sbenno */ 46996938Sbennostatic int 47096938Sbennohandle_onfault(struct trapframe *frame) 47196938Sbenno{ 47296938Sbenno struct thread *td; 473293636Snwhitehorn jmp_buf *fb; 47486067Smp 47596938Sbenno td = curthread; 47696938Sbenno fb = td->td_pcb->pcb_onfault; 47796938Sbenno if (fb != NULL) { 478293636Snwhitehorn frame->srr0 = (*fb)->_jb[FAULTBUF_LR]; 479293636Snwhitehorn frame->fixreg[1] = (*fb)->_jb[FAULTBUF_R1]; 480293636Snwhitehorn frame->fixreg[2] = (*fb)->_jb[FAULTBUF_R2]; 481131867Sgrehan frame->fixreg[3] = 1; 482293636Snwhitehorn frame->cr = (*fb)->_jb[FAULTBUF_CR]; 483293636Snwhitehorn bcopy(&(*fb)->_jb[FAULTBUF_R14], &frame->fixreg[14], 484293636Snwhitehorn 18 * sizeof(register_t)); 485293636Snwhitehorn td->td_pcb->pcb_onfault = NULL; /* Returns twice, not thrice */ 48696938Sbenno return (1); 48796938Sbenno } 48896938Sbenno return (0); 48996938Sbenno} 49086067Smp 491208453Skibint 492321343Skibcpu_fetch_syscall_args(struct thread *td) 49396938Sbenno{ 494208453Skib struct proc *p; 495208453Skib struct trapframe *frame; 496321343Skib struct syscall_args *sa; 497208453Skib caddr_t params; 498209975Snwhitehorn size_t argsz; 499209975Snwhitehorn int error, n, i; 50086067Smp 50196938Sbenno p = td->td_proc; 502208453Skib frame = td->td_frame; 503321343Skib sa = &td->td_sa; 50486067Smp 505208453Skib sa->code = frame->fixreg[0]; 50696938Sbenno params = (caddr_t)(frame->fixreg + FIRSTARG); 50796938Sbenno n = NARGREG; 508131698Sgrehan 509208453Skib if (sa->code == SYS_syscall) { 51096938Sbenno /* 51196938Sbenno * code is first argument, 51296938Sbenno * followed by actual args. 51396938Sbenno */ 514209975Snwhitehorn sa->code = *(register_t *) params; 515103607Sgrehan params += sizeof(register_t); 51696938Sbenno n -= 1; 517208453Skib } else if (sa->code == SYS___syscall) { 51896938Sbenno /* 51996938Sbenno * Like syscall, but code is a quad, 52096938Sbenno * so as to maintain quad alignment 52196938Sbenno * for the rest of the args. 52296938Sbenno */ 523217896Sdchagin if (SV_PROC_FLAG(p, SV_ILP32)) { 524209975Snwhitehorn params += sizeof(register_t); 525209975Snwhitehorn sa->code = *(register_t *) params; 526209975Snwhitehorn params += sizeof(register_t); 527209975Snwhitehorn n -= 2; 528209975Snwhitehorn } else { 529209975Snwhitehorn sa->code = *(register_t *) params; 530209975Snwhitehorn params += sizeof(register_t); 531209975Snwhitehorn n -= 1; 532209975Snwhitehorn } 53396938Sbenno } 53496452Sbenno 53596938Sbenno if (p->p_sysent->sv_mask) 536208453Skib sa->code &= p->p_sysent->sv_mask; 537208453Skib if (sa->code >= p->p_sysent->sv_size) 538208453Skib sa->callp = &p->p_sysent->sv_table[0]; 539208453Skib else 540208453Skib sa->callp = &p->p_sysent->sv_table[sa->code]; 54186067Smp 542208453Skib sa->narg = sa->callp->sy_narg; 54386067Smp 544217896Sdchagin if (SV_PROC_FLAG(p, SV_ILP32)) { 545209975Snwhitehorn argsz = sizeof(uint32_t); 546209975Snwhitehorn 547209975Snwhitehorn for (i = 0; i < n; i++) 548209975Snwhitehorn sa->args[i] = ((u_register_t *)(params))[i] & 549209975Snwhitehorn 0xffffffff; 550209975Snwhitehorn } else { 551209975Snwhitehorn argsz = sizeof(uint64_t); 552209975Snwhitehorn 553209975Snwhitehorn for (i = 0; i < n; i++) 554209975Snwhitehorn sa->args[i] = ((u_register_t *)(params))[i]; 555209975Snwhitehorn } 556209975Snwhitehorn 557209975Snwhitehorn if (sa->narg > n) 558208453Skib error = copyin(MOREARGS(frame->fixreg[1]), sa->args + n, 559209975Snwhitehorn (sa->narg - n) * argsz); 560209975Snwhitehorn else 56198001Sjhb error = 0; 56298001Sjhb 563209975Snwhitehorn#ifdef __powerpc64__ 564217896Sdchagin if (SV_PROC_FLAG(p, SV_ILP32) && sa->narg > n) { 565209975Snwhitehorn /* Expand the size of arguments copied from the stack */ 566209975Snwhitehorn 567209975Snwhitehorn for (i = sa->narg; i >= n; i--) 568209975Snwhitehorn sa->args[i] = ((uint32_t *)(&sa->args[n]))[i-n]; 569209975Snwhitehorn } 570209975Snwhitehorn#endif 571209975Snwhitehorn 57298001Sjhb if (error == 0) { 57398001Sjhb td->td_retval[0] = 0; 57498001Sjhb td->td_retval[1] = frame->fixreg[FIRSTARG + 1]; 57598001Sjhb } 576208453Skib return (error); 577208453Skib} 57877957Sbenno 579225474Skib#include "../../kern/subr_syscall.c" 580225474Skib 581208453Skibvoid 582208453Skibsyscall(struct trapframe *frame) 583208453Skib{ 584208453Skib struct thread *td; 585208453Skib int error; 586199135Skib 587223485Snwhitehorn td = curthread; 588208453Skib td->td_frame = frame; 589160773Sjhb 590214749Snwhitehorn#ifdef __powerpc64__ 591214739Snwhitehorn /* 592214739Snwhitehorn * Speculatively restore last user SLB segment, which we know is 593214739Snwhitehorn * invalid already, since we are likely to do copyin()/copyout(). 594214739Snwhitehorn */ 595214739Snwhitehorn __asm __volatile ("slbmte %0, %1; isync" :: 596214739Snwhitehorn "r"(td->td_pcb->pcb_cpu.aim.usr_vsid), "r"(USER_SLB_SLBE)); 597214749Snwhitehorn#endif 598214739Snwhitehorn 599321343Skib error = syscallenter(td); 600321343Skib syscallret(td, error); 60177957Sbenno} 60277957Sbenno 603209975Snwhitehorn#ifdef __powerpc64__ 604230123Snwhitehorn/* Handle kernel SLB faults -- runs in real mode, all seat belts off */ 605230123Snwhitehornvoid 606230123Snwhitehornhandle_kernel_slb_spill(int type, register_t dar, register_t srr0) 607230123Snwhitehorn{ 608230123Snwhitehorn struct slb *slbcache; 609230123Snwhitehorn uint64_t slbe, slbv; 610230123Snwhitehorn uint64_t esid, addr; 611230123Snwhitehorn int i; 612230123Snwhitehorn 613230123Snwhitehorn addr = (type == EXC_ISE) ? srr0 : dar; 614230123Snwhitehorn slbcache = PCPU_GET(slb); 615230123Snwhitehorn esid = (uintptr_t)addr >> ADDR_SR_SHFT; 616230123Snwhitehorn slbe = (esid << SLBE_ESID_SHIFT) | SLBE_VALID; 617230123Snwhitehorn 618230123Snwhitehorn /* See if the hardware flushed this somehow (can happen in LPARs) */ 619230123Snwhitehorn for (i = 0; i < n_slbs; i++) 620230123Snwhitehorn if (slbcache[i].slbe == (slbe | (uint64_t)i)) 621230123Snwhitehorn return; 622230123Snwhitehorn 623230123Snwhitehorn /* Not in the map, needs to actually be added */ 624230123Snwhitehorn slbv = kernel_va_to_slbv(addr); 625230123Snwhitehorn if (slbcache[USER_SLB_SLOT].slbe == 0) { 626230123Snwhitehorn for (i = 0; i < n_slbs; i++) { 627230123Snwhitehorn if (i == USER_SLB_SLOT) 628230123Snwhitehorn continue; 629230123Snwhitehorn if (!(slbcache[i].slbe & SLBE_VALID)) 630230123Snwhitehorn goto fillkernslb; 631230123Snwhitehorn } 632230123Snwhitehorn 633230123Snwhitehorn if (i == n_slbs) 634230123Snwhitehorn slbcache[USER_SLB_SLOT].slbe = 1; 635230123Snwhitehorn } 636230123Snwhitehorn 637230123Snwhitehorn /* Sacrifice a random SLB entry that is not the user entry */ 638230123Snwhitehorn i = mftb() % n_slbs; 639230123Snwhitehorn if (i == USER_SLB_SLOT) 640230123Snwhitehorn i = (i+1) % n_slbs; 641230123Snwhitehorn 642230123Snwhitehornfillkernslb: 643230123Snwhitehorn /* Write new entry */ 644230123Snwhitehorn slbcache[i].slbv = slbv; 645230123Snwhitehorn slbcache[i].slbe = slbe | (uint64_t)i; 646230123Snwhitehorn 647230123Snwhitehorn /* Trap handler will restore from cache on exit */ 648230123Snwhitehorn} 649230123Snwhitehorn 650209975Snwhitehornstatic int 651230123Snwhitehornhandle_user_slb_spill(pmap_t pm, vm_offset_t addr) 652209975Snwhitehorn{ 653212722Snwhitehorn struct slb *user_entry; 654212715Snwhitehorn uint64_t esid; 655212715Snwhitehorn int i; 656209975Snwhitehorn 657212715Snwhitehorn esid = (uintptr_t)addr >> ADDR_SR_SHFT; 658212715Snwhitehorn 659209975Snwhitehorn PMAP_LOCK(pm); 660212715Snwhitehorn user_entry = user_va_to_slb_entry(pm, addr); 661212715Snwhitehorn 662212715Snwhitehorn if (user_entry == NULL) { 663212715Snwhitehorn /* allocate_vsid auto-spills it */ 664212722Snwhitehorn (void)allocate_user_vsid(pm, esid, 0); 665212715Snwhitehorn } else { 666209975Snwhitehorn /* 667209975Snwhitehorn * Check that another CPU has not already mapped this. 668209975Snwhitehorn * XXX: Per-thread SLB caches would be better. 669209975Snwhitehorn */ 670212722Snwhitehorn for (i = 0; i < pm->pm_slb_len; i++) 671212722Snwhitehorn if (pm->pm_slb[i] == user_entry) 672209975Snwhitehorn break; 673209975Snwhitehorn 674212722Snwhitehorn if (i == pm->pm_slb_len) 675212722Snwhitehorn slb_insert_user(pm, user_entry); 676209975Snwhitehorn } 677209975Snwhitehorn PMAP_UNLOCK(pm); 678209975Snwhitehorn 679209975Snwhitehorn return (0); 680209975Snwhitehorn} 681209975Snwhitehorn#endif 682209975Snwhitehorn 68396938Sbennostatic int 68496938Sbennotrap_pfault(struct trapframe *frame, int user) 68577957Sbenno{ 68696938Sbenno vm_offset_t eva, va; 68796938Sbenno struct thread *td; 68896938Sbenno struct proc *p; 68996938Sbenno vm_map_t map; 69096938Sbenno vm_prot_t ftype; 69196938Sbenno int rv; 692281096Sjhibbits#ifdef AIM 693209975Snwhitehorn register_t user_sr; 694281096Sjhibbits#endif 69577957Sbenno 69696938Sbenno td = curthread; 69796906Sbenno p = td->td_proc; 69896938Sbenno if (frame->exc == EXC_ISI) { 69996938Sbenno eva = frame->srr0; 700217341Snwhitehorn ftype = VM_PROT_EXECUTE; 701217341Snwhitehorn if (frame->srr1 & SRR1_ISI_PFAULT) 702217341Snwhitehorn ftype |= VM_PROT_READ; 70396938Sbenno } else { 704279601Snwhitehorn eva = frame->dar; 705281096Sjhibbits#ifdef BOOKE 706281096Sjhibbits if (frame->cpu.booke.esr & ESR_ST) 707281096Sjhibbits#else 708176742Sraj if (frame->cpu.aim.dsisr & DSISR_STORE) 709281096Sjhibbits#endif 710103607Sgrehan ftype = VM_PROT_WRITE; 71196938Sbenno else 71296938Sbenno ftype = VM_PROT_READ; 71396938Sbenno } 71496906Sbenno 71596938Sbenno if (user) { 716281096Sjhibbits KASSERT(p->p_vmspace != NULL, ("trap_pfault: vmspace NULL")); 71796938Sbenno map = &p->p_vmspace->vm_map; 71896938Sbenno } else { 719281096Sjhibbits#ifdef BOOKE 720281096Sjhibbits if (eva < VM_MAXUSER_ADDRESS) { 721281096Sjhibbits#else 722209975Snwhitehorn if ((eva >> ADDR_SR_SHFT) == (USER_ADDR >> ADDR_SR_SHFT)) { 723281096Sjhibbits#endif 724209975Snwhitehorn map = &p->p_vmspace->vm_map; 725209975Snwhitehorn 726281096Sjhibbits#ifdef AIM 727212715Snwhitehorn user_sr = td->td_pcb->pcb_cpu.aim.usr_segm; 72896938Sbenno eva &= ADDR_PIDX | ADDR_POFF; 72996938Sbenno eva |= user_sr << ADDR_SR_SHFT; 730281096Sjhibbits#endif 73196938Sbenno } else { 73296938Sbenno map = kernel_map; 73396938Sbenno } 73496938Sbenno } 73596938Sbenno va = trunc_page(eva); 73677957Sbenno 737287625Skib /* Fault in the page. */ 738287625Skib rv = vm_fault(map, va, ftype, VM_FAULT_NORMAL); 739287625Skib /* 740287625Skib * XXXDTRACE: add dtrace_doubletrap_func here? 741287625Skib */ 74296938Sbenno 74396938Sbenno if (rv == KERN_SUCCESS) 74496938Sbenno return (0); 74596938Sbenno 74696938Sbenno if (!user && handle_onfault(frame)) 74796938Sbenno return (0); 74896938Sbenno 74996938Sbenno return (SIGSEGV); 75077957Sbenno} 75177957Sbenno 75277957Sbenno/* 75377957Sbenno * For now, this only deals with the particular unaligned access case 75477957Sbenno * that gcc tends to generate. Eventually it should handle all of the 75577957Sbenno * possibilities that can happen on a 32-bit PowerPC in big-endian mode. 75677957Sbenno */ 75777957Sbenno 75877957Sbennostatic int 75996906Sbennofix_unaligned(struct thread *td, struct trapframe *frame) 76077957Sbenno{ 76196906Sbenno struct thread *fputhread; 76296906Sbenno int indicator, reg; 76396906Sbenno double *fpr; 76477957Sbenno 765176742Sraj indicator = EXC_ALI_OPCODE_INDICATOR(frame->cpu.aim.dsisr); 76696906Sbenno 76777957Sbenno switch (indicator) { 76877957Sbenno case EXC_ALI_LFD: 76977957Sbenno case EXC_ALI_STFD: 770176742Sraj reg = EXC_ALI_RST(frame->cpu.aim.dsisr); 771279189Snwhitehorn fpr = &td->td_pcb->pcb_fpu.fpr[reg].fpr; 77296906Sbenno fputhread = PCPU_GET(fputhread); 77377957Sbenno 77496906Sbenno /* Juggle the FPU to ensure that we've initialized 77596906Sbenno * the FPRs, and that their current state is in 77696906Sbenno * the PCB. 77796906Sbenno */ 77896906Sbenno if (fputhread != td) { 77996906Sbenno if (fputhread) 78096906Sbenno save_fpu(fputhread); 78196906Sbenno enable_fpu(td); 78296906Sbenno } 78396906Sbenno save_fpu(td); 78477957Sbenno 78596906Sbenno if (indicator == EXC_ALI_LFD) { 786279601Snwhitehorn if (copyin((void *)frame->dar, fpr, 78796906Sbenno sizeof(double)) != 0) 788281096Sjhibbits return (-1); 78996906Sbenno enable_fpu(td); 79096906Sbenno } else { 791279601Snwhitehorn if (copyout(fpr, (void *)frame->dar, 79296906Sbenno sizeof(double)) != 0) 793281096Sjhibbits return (-1); 79477957Sbenno } 795281096Sjhibbits return (0); 79677957Sbenno break; 79777957Sbenno } 79877957Sbenno 799281096Sjhibbits return (-1); 80077957Sbenno} 801204197Snwhitehorn 802281096Sjhibbits#ifdef KDB 803281096Sjhibbitsint db_trap_glue(struct trapframe *); /* Called from trap_subr.S */ 804281096Sjhibbits 805281096Sjhibbitsint 806281096Sjhibbitsdb_trap_glue(struct trapframe *frame) 807281096Sjhibbits{ 808281096Sjhibbits if (!(frame->srr1 & PSL_PR) 809281096Sjhibbits && (frame->exc == EXC_TRC || frame->exc == EXC_RUNMODETRC 810281261Sjhibbits#ifdef AIM 811281096Sjhibbits || (frame->exc == EXC_PGM 812287188Sjhibbits && (frame->srr1 & EXC_PGM_TRAP)) 813281261Sjhibbits#else 814281261Sjhibbits || (frame->exc == EXC_DEBUG) 815281261Sjhibbits#endif 816281096Sjhibbits || frame->exc == EXC_BPT 817281096Sjhibbits || frame->exc == EXC_DSI)) { 818281096Sjhibbits int type = frame->exc; 819281096Sjhibbits 820281096Sjhibbits /* Ignore DTrace traps. */ 821281096Sjhibbits if (*(uint32_t *)frame->srr0 == EXC_DTRACE) 822281096Sjhibbits return (0); 823281261Sjhibbits#ifdef AIM 824287188Sjhibbits if (type == EXC_PGM && (frame->srr1 & EXC_PGM_TRAP)) { 825281261Sjhibbits#else 826281261Sjhibbits if (frame->cpu.booke.esr & ESR_PTR) { 827281261Sjhibbits#endif 828281096Sjhibbits type = T_BREAKPOINT; 829281096Sjhibbits } 830281096Sjhibbits return (kdb_trap(type, 0, frame)); 831281096Sjhibbits } 832281096Sjhibbits 833281096Sjhibbits return (0); 834281096Sjhibbits} 835281096Sjhibbits#endif 836