128cbb9b1SJustin Hibbits /*- 228cbb9b1SJustin Hibbits * Copyright (C) 1995, 1996 Wolfgang Solfrank. 328cbb9b1SJustin Hibbits * Copyright (C) 1995, 1996 TooLs GmbH. 428cbb9b1SJustin Hibbits * All rights reserved. 528cbb9b1SJustin Hibbits * 628cbb9b1SJustin Hibbits * Redistribution and use in source and binary forms, with or without 728cbb9b1SJustin Hibbits * modification, are permitted provided that the following conditions 828cbb9b1SJustin Hibbits * are met: 928cbb9b1SJustin Hibbits * 1. Redistributions of source code must retain the above copyright 1028cbb9b1SJustin Hibbits * notice, this list of conditions and the following disclaimer. 1128cbb9b1SJustin Hibbits * 2. Redistributions in binary form must reproduce the above copyright 1228cbb9b1SJustin Hibbits * notice, this list of conditions and the following disclaimer in the 1328cbb9b1SJustin Hibbits * documentation and/or other materials provided with the distribution. 1428cbb9b1SJustin Hibbits * 3. All advertising materials mentioning features or use of this software 1528cbb9b1SJustin Hibbits * must display the following acknowledgement: 1628cbb9b1SJustin Hibbits * This product includes software developed by TooLs GmbH. 1728cbb9b1SJustin Hibbits * 4. The name of TooLs GmbH may not be used to endorse or promote products 1828cbb9b1SJustin Hibbits * derived from this software without specific prior written permission. 1928cbb9b1SJustin Hibbits * 2028cbb9b1SJustin Hibbits * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 2128cbb9b1SJustin Hibbits * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 2228cbb9b1SJustin Hibbits * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2328cbb9b1SJustin Hibbits * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 2428cbb9b1SJustin Hibbits * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 2528cbb9b1SJustin Hibbits * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 2628cbb9b1SJustin Hibbits * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 2728cbb9b1SJustin Hibbits * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 2828cbb9b1SJustin Hibbits * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 2928cbb9b1SJustin Hibbits * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3028cbb9b1SJustin Hibbits * 3128cbb9b1SJustin Hibbits * $NetBSD: trap.c,v 1.58 2002/03/04 04:07:35 dbj Exp $ 3228cbb9b1SJustin Hibbits */ 3328cbb9b1SJustin Hibbits 3428cbb9b1SJustin Hibbits #include <sys/cdefs.h> 3528cbb9b1SJustin Hibbits __FBSDID("$FreeBSD$"); 3628cbb9b1SJustin Hibbits 3728cbb9b1SJustin Hibbits #include <sys/param.h> 3828cbb9b1SJustin Hibbits #include <sys/kdb.h> 3928cbb9b1SJustin Hibbits #include <sys/proc.h> 4028cbb9b1SJustin Hibbits #include <sys/ktr.h> 4128cbb9b1SJustin Hibbits #include <sys/lock.h> 4228cbb9b1SJustin Hibbits #include <sys/mutex.h> 4328cbb9b1SJustin Hibbits #include <sys/pioctl.h> 4428cbb9b1SJustin Hibbits #include <sys/ptrace.h> 4528cbb9b1SJustin Hibbits #include <sys/reboot.h> 4628cbb9b1SJustin Hibbits #include <sys/syscall.h> 4728cbb9b1SJustin Hibbits #include <sys/sysent.h> 4828cbb9b1SJustin Hibbits #include <sys/systm.h> 4928cbb9b1SJustin Hibbits #include <sys/kernel.h> 5028cbb9b1SJustin Hibbits #include <sys/uio.h> 5128cbb9b1SJustin Hibbits #include <sys/signalvar.h> 5228cbb9b1SJustin Hibbits #include <sys/vmmeter.h> 5328cbb9b1SJustin Hibbits 5428cbb9b1SJustin Hibbits #include <security/audit/audit.h> 5528cbb9b1SJustin Hibbits 5628cbb9b1SJustin Hibbits #include <vm/vm.h> 5728cbb9b1SJustin Hibbits #include <vm/pmap.h> 5828cbb9b1SJustin Hibbits #include <vm/vm_extern.h> 5928cbb9b1SJustin Hibbits #include <vm/vm_param.h> 6028cbb9b1SJustin Hibbits #include <vm/vm_kern.h> 6128cbb9b1SJustin Hibbits #include <vm/vm_map.h> 6228cbb9b1SJustin Hibbits #include <vm/vm_page.h> 6328cbb9b1SJustin Hibbits 6428cbb9b1SJustin Hibbits #include <machine/_inttypes.h> 6528cbb9b1SJustin Hibbits #include <machine/altivec.h> 6628cbb9b1SJustin Hibbits #include <machine/cpu.h> 6728cbb9b1SJustin Hibbits #include <machine/db_machdep.h> 6828cbb9b1SJustin Hibbits #include <machine/fpu.h> 6928cbb9b1SJustin Hibbits #include <machine/frame.h> 7028cbb9b1SJustin Hibbits #include <machine/pcb.h> 7128cbb9b1SJustin Hibbits #include <machine/psl.h> 7228cbb9b1SJustin Hibbits #include <machine/trap.h> 7328cbb9b1SJustin Hibbits #include <machine/spr.h> 7428cbb9b1SJustin Hibbits #include <machine/sr.h> 7528cbb9b1SJustin Hibbits 76a18c313eSNathan Whitehorn /* Below matches setjmp.S */ 77a18c313eSNathan Whitehorn #define FAULTBUF_LR 21 7828cbb9b1SJustin Hibbits #define FAULTBUF_R1 1 7928cbb9b1SJustin Hibbits #define FAULTBUF_R2 2 80a18c313eSNathan Whitehorn #define FAULTBUF_CR 22 81a18c313eSNathan Whitehorn #define FAULTBUF_R14 3 8228cbb9b1SJustin Hibbits 833e7e31bdSJustin Hibbits #define MOREARGS(sp) ((caddr_t)((uintptr_t)(sp) + \ 843e7e31bdSJustin Hibbits sizeof(struct callframe) - 3*sizeof(register_t))) /* more args go here */ 853e7e31bdSJustin Hibbits 8628cbb9b1SJustin Hibbits static void trap_fatal(struct trapframe *frame); 8728cbb9b1SJustin Hibbits static void printtrap(u_int vector, struct trapframe *frame, int isfatal, 8828cbb9b1SJustin Hibbits int user); 8928cbb9b1SJustin Hibbits static int trap_pfault(struct trapframe *frame, int user); 9028cbb9b1SJustin Hibbits static int fix_unaligned(struct thread *td, struct trapframe *frame); 9128cbb9b1SJustin Hibbits static int handle_onfault(struct trapframe *frame); 9228cbb9b1SJustin Hibbits static void syscall(struct trapframe *frame); 9328cbb9b1SJustin Hibbits 94d5a30121SJustin Hibbits #if defined(__powerpc64__) && defined(AIM) 9528cbb9b1SJustin Hibbits void handle_kernel_slb_spill(int, register_t, register_t); 9628cbb9b1SJustin Hibbits static int handle_user_slb_spill(pmap_t pm, vm_offset_t addr); 9728cbb9b1SJustin Hibbits extern int n_slbs; 98be2bd024SLeandro Lupori static void normalize_inputs(void); 9928cbb9b1SJustin Hibbits #endif 10028cbb9b1SJustin Hibbits 101ec75f647SNathan Whitehorn extern vm_offset_t __startkernel; 102ec75f647SNathan Whitehorn 10315fc4ab7SJustin Hibbits #ifdef KDB 10415fc4ab7SJustin Hibbits int db_trap_glue(struct trapframe *); /* Called from trap_subr.S */ 10515fc4ab7SJustin Hibbits #endif 10615fc4ab7SJustin Hibbits 10728cbb9b1SJustin Hibbits struct powerpc_exception { 10828cbb9b1SJustin Hibbits u_int vector; 10928cbb9b1SJustin Hibbits char *name; 11028cbb9b1SJustin Hibbits }; 11128cbb9b1SJustin Hibbits 11228cbb9b1SJustin Hibbits #ifdef KDTRACE_HOOKS 11328cbb9b1SJustin Hibbits #include <sys/dtrace_bsd.h> 11428cbb9b1SJustin Hibbits 11528cbb9b1SJustin Hibbits int (*dtrace_invop_jump_addr)(struct trapframe *); 11628cbb9b1SJustin Hibbits #endif 11728cbb9b1SJustin Hibbits 11828cbb9b1SJustin Hibbits static struct powerpc_exception powerpc_exceptions[] = { 11928cbb9b1SJustin Hibbits { EXC_CRIT, "critical input" }, 12028cbb9b1SJustin Hibbits { EXC_RST, "system reset" }, 12128cbb9b1SJustin Hibbits { EXC_MCHK, "machine check" }, 12228cbb9b1SJustin Hibbits { EXC_DSI, "data storage interrupt" }, 12328cbb9b1SJustin Hibbits { EXC_DSE, "data segment exception" }, 12428cbb9b1SJustin Hibbits { EXC_ISI, "instruction storage interrupt" }, 12528cbb9b1SJustin Hibbits { EXC_ISE, "instruction segment exception" }, 12628cbb9b1SJustin Hibbits { EXC_EXI, "external interrupt" }, 12728cbb9b1SJustin Hibbits { EXC_ALI, "alignment" }, 12828cbb9b1SJustin Hibbits { EXC_PGM, "program" }, 129ec75f647SNathan Whitehorn { EXC_HEA, "hypervisor emulation assistance" }, 13028cbb9b1SJustin Hibbits { EXC_FPU, "floating-point unavailable" }, 13128cbb9b1SJustin Hibbits { EXC_APU, "auxiliary proc unavailable" }, 13228cbb9b1SJustin Hibbits { EXC_DECR, "decrementer" }, 13328cbb9b1SJustin Hibbits { EXC_FIT, "fixed-interval timer" }, 13428cbb9b1SJustin Hibbits { EXC_WDOG, "watchdog timer" }, 13528cbb9b1SJustin Hibbits { EXC_SC, "system call" }, 13628cbb9b1SJustin Hibbits { EXC_TRC, "trace" }, 13728cbb9b1SJustin Hibbits { EXC_FPA, "floating-point assist" }, 13828cbb9b1SJustin Hibbits { EXC_DEBUG, "debug" }, 13928cbb9b1SJustin Hibbits { EXC_PERF, "performance monitoring" }, 14028cbb9b1SJustin Hibbits { EXC_VEC, "altivec unavailable" }, 14128cbb9b1SJustin Hibbits { EXC_VSX, "vsx unavailable" }, 1427cd4e55cSJustin Hibbits { EXC_FAC, "facility unavailable" }, 14328cbb9b1SJustin Hibbits { EXC_ITMISS, "instruction tlb miss" }, 14428cbb9b1SJustin Hibbits { EXC_DLMISS, "data load tlb miss" }, 14528cbb9b1SJustin Hibbits { EXC_DSMISS, "data store tlb miss" }, 14628cbb9b1SJustin Hibbits { EXC_BPT, "instruction breakpoint" }, 14728cbb9b1SJustin Hibbits { EXC_SMI, "system management" }, 14828cbb9b1SJustin Hibbits { EXC_VECAST_G4, "altivec assist" }, 14928cbb9b1SJustin Hibbits { EXC_THRM, "thermal management" }, 15028cbb9b1SJustin Hibbits { EXC_RUNMODETRC, "run mode/trace" }, 151be2bd024SLeandro Lupori { EXC_SOFT_PATCH, "soft patch exception" }, 15228cbb9b1SJustin Hibbits { EXC_LAST, NULL } 15328cbb9b1SJustin Hibbits }; 15428cbb9b1SJustin Hibbits 155bf1b9296SJustin Hibbits #define ESR_BITMASK \ 156bf1b9296SJustin Hibbits "\20" \ 157bf1b9296SJustin Hibbits "\040b0\037b1\036b2\035b3\034PIL\033PRR\032PTR\031FP" \ 158bf1b9296SJustin Hibbits "\030ST\027b9\026DLK\025ILK\024b12\023b13\022BO\021PIE" \ 159bf1b9296SJustin Hibbits "\020b16\017b17\016b18\015b19\014b20\013b21\012b22\011b23" \ 160bf1b9296SJustin Hibbits "\010SPE\007EPID\006b26\005b27\004b28\003b29\002b30\001b31" 161bf1b9296SJustin Hibbits #define MCSR_BITMASK \ 162bf1b9296SJustin Hibbits "\20" \ 163bf1b9296SJustin Hibbits "\040MCP\037ICERR\036DCERR\035TLBPERR\034L2MMU_MHIT\033b5\032b6\031b7" \ 164bf1b9296SJustin Hibbits "\030b8\027b9\026b10\025NMI\024MAV\023MEA\022b14\021IF" \ 165bf1b9296SJustin Hibbits "\020LD\017ST\016LDG\015b19\014b20\013b21\012b22\011b23" \ 166bf1b9296SJustin Hibbits "\010b24\007b25\006b26\005b27\004b28\003b29\002TLBSYNC\001BSL2_ERR" 167bf1b9296SJustin Hibbits #define MSSSR_BITMASK \ 168bf1b9296SJustin Hibbits "\20" \ 169bf1b9296SJustin Hibbits "\040b0\037b1\036b2\035b3\034b4\033b5\032b6\031b7" \ 170bf1b9296SJustin Hibbits "\030b8\027b9\026b10\025b11\024b12\023L2TAG\022L2DAT\021L3TAG" \ 171bf1b9296SJustin Hibbits "\020L3DAT\017APE\016DPE\015TEA\014b20\013b21\012b22\011b23" \ 172bf1b9296SJustin Hibbits "\010b24\007b25\006b26\005b27\004b28\003b29\002b30\001b31" 173bf1b9296SJustin Hibbits 174bf1b9296SJustin Hibbits 17528cbb9b1SJustin Hibbits static const char * 17628cbb9b1SJustin Hibbits trapname(u_int vector) 17728cbb9b1SJustin Hibbits { 17828cbb9b1SJustin Hibbits struct powerpc_exception *pe; 17928cbb9b1SJustin Hibbits 18028cbb9b1SJustin Hibbits for (pe = powerpc_exceptions; pe->vector != EXC_LAST; pe++) { 18128cbb9b1SJustin Hibbits if (pe->vector == vector) 18228cbb9b1SJustin Hibbits return (pe->name); 18328cbb9b1SJustin Hibbits } 18428cbb9b1SJustin Hibbits 18528cbb9b1SJustin Hibbits return ("unknown"); 18628cbb9b1SJustin Hibbits } 18728cbb9b1SJustin Hibbits 188a72b9513SJustin Hibbits static inline bool 189a72b9513SJustin Hibbits frame_is_trap_inst(struct trapframe *frame) 190a72b9513SJustin Hibbits { 191a72b9513SJustin Hibbits #ifdef AIM 192a72b9513SJustin Hibbits return (frame->exc == EXC_PGM && frame->srr1 & EXC_PGM_TRAP); 193a72b9513SJustin Hibbits #else 1949ae2eed9SJustin Hibbits return ((frame->cpu.booke.esr & ESR_PTR) != 0); 195a72b9513SJustin Hibbits #endif 196a72b9513SJustin Hibbits } 197a72b9513SJustin Hibbits 19828cbb9b1SJustin Hibbits void 19928cbb9b1SJustin Hibbits trap(struct trapframe *frame) 20028cbb9b1SJustin Hibbits { 20128cbb9b1SJustin Hibbits struct thread *td; 20228cbb9b1SJustin Hibbits struct proc *p; 20328cbb9b1SJustin Hibbits #ifdef KDTRACE_HOOKS 20428cbb9b1SJustin Hibbits uint32_t inst; 20528cbb9b1SJustin Hibbits #endif 20628cbb9b1SJustin Hibbits int sig, type, user; 20728cbb9b1SJustin Hibbits u_int ucode; 20828cbb9b1SJustin Hibbits ksiginfo_t ksi; 209ac2605b1SJustin Hibbits register_t fscr; 21028cbb9b1SJustin Hibbits 21183c9dea1SGleb Smirnoff VM_CNT_INC(v_trap); 21228cbb9b1SJustin Hibbits 213bda8aa77SJustin Hibbits #ifdef KDB 214bda8aa77SJustin Hibbits if (kdb_active) { 215bda8aa77SJustin Hibbits kdb_reenter(); 216bda8aa77SJustin Hibbits return; 217bda8aa77SJustin Hibbits } 218bda8aa77SJustin Hibbits #endif 219bda8aa77SJustin Hibbits 22028cbb9b1SJustin Hibbits td = curthread; 22128cbb9b1SJustin Hibbits p = td->td_proc; 22228cbb9b1SJustin Hibbits 22328cbb9b1SJustin Hibbits type = ucode = frame->exc; 22428cbb9b1SJustin Hibbits sig = 0; 22528cbb9b1SJustin Hibbits user = frame->srr1 & PSL_PR; 22628cbb9b1SJustin Hibbits 22728cbb9b1SJustin Hibbits CTR3(KTR_TRAP, "trap: %s type=%s (%s)", td->td_name, 22828cbb9b1SJustin Hibbits trapname(type), user ? "user" : "kernel"); 22928cbb9b1SJustin Hibbits 23028cbb9b1SJustin Hibbits #ifdef KDTRACE_HOOKS 23128cbb9b1SJustin Hibbits /* 23228cbb9b1SJustin Hibbits * A trap can occur while DTrace executes a probe. Before 23328cbb9b1SJustin Hibbits * executing the probe, DTrace blocks re-scheduling and sets 23428cbb9b1SJustin Hibbits * a flag in its per-cpu flags to indicate that it doesn't 23528cbb9b1SJustin Hibbits * want to fault. On returning from the probe, the no-fault 23628cbb9b1SJustin Hibbits * flag is cleared and finally re-scheduling is enabled. 23728cbb9b1SJustin Hibbits * 23828cbb9b1SJustin Hibbits * If the DTrace kernel module has registered a trap handler, 23928cbb9b1SJustin Hibbits * call it and if it returns non-zero, assume that it has 24028cbb9b1SJustin Hibbits * handled the trap and modified the trap frame so that this 24128cbb9b1SJustin Hibbits * function can return normally. 24228cbb9b1SJustin Hibbits */ 24328cbb9b1SJustin Hibbits if (dtrace_trap_func != NULL && (*dtrace_trap_func)(frame, type) != 0) 24428cbb9b1SJustin Hibbits return; 24528cbb9b1SJustin Hibbits #endif 24628cbb9b1SJustin Hibbits 24728cbb9b1SJustin Hibbits if (user) { 24828cbb9b1SJustin Hibbits td->td_pticks = 0; 24928cbb9b1SJustin Hibbits td->td_frame = frame; 2504ea6a9a2SMateusz Guzik if (td->td_cowgen != p->p_cowgen) 2514ea6a9a2SMateusz Guzik thread_cow_update(td); 25228cbb9b1SJustin Hibbits 25328cbb9b1SJustin Hibbits /* User Mode Traps */ 25428cbb9b1SJustin Hibbits switch (type) { 25528cbb9b1SJustin Hibbits case EXC_RUNMODETRC: 25628cbb9b1SJustin Hibbits case EXC_TRC: 25728cbb9b1SJustin Hibbits frame->srr1 &= ~PSL_SE; 25828cbb9b1SJustin Hibbits sig = SIGTRAP; 25928cbb9b1SJustin Hibbits ucode = TRAP_TRACE; 26028cbb9b1SJustin Hibbits break; 26128cbb9b1SJustin Hibbits 262d5a30121SJustin Hibbits #if defined(__powerpc64__) && defined(AIM) 26328cbb9b1SJustin Hibbits case EXC_ISE: 26428cbb9b1SJustin Hibbits case EXC_DSE: 26528cbb9b1SJustin Hibbits if (handle_user_slb_spill(&p->p_vmspace->vm_pmap, 26628cbb9b1SJustin Hibbits (type == EXC_ISE) ? frame->srr0 : frame->dar) != 0){ 26728cbb9b1SJustin Hibbits sig = SIGSEGV; 26828cbb9b1SJustin Hibbits ucode = SEGV_MAPERR; 26928cbb9b1SJustin Hibbits } 27028cbb9b1SJustin Hibbits break; 27128cbb9b1SJustin Hibbits #endif 27228cbb9b1SJustin Hibbits case EXC_DSI: 27328cbb9b1SJustin Hibbits case EXC_ISI: 27428cbb9b1SJustin Hibbits sig = trap_pfault(frame, 1); 27528cbb9b1SJustin Hibbits if (sig == SIGSEGV) 27628cbb9b1SJustin Hibbits ucode = SEGV_MAPERR; 27728cbb9b1SJustin Hibbits break; 27828cbb9b1SJustin Hibbits 27928cbb9b1SJustin Hibbits case EXC_SC: 28028cbb9b1SJustin Hibbits syscall(frame); 28128cbb9b1SJustin Hibbits break; 28228cbb9b1SJustin Hibbits 28328cbb9b1SJustin Hibbits case EXC_FPU: 28428cbb9b1SJustin Hibbits KASSERT((td->td_pcb->pcb_flags & PCB_FPU) != PCB_FPU, 28528cbb9b1SJustin Hibbits ("FPU already enabled for thread")); 28628cbb9b1SJustin Hibbits enable_fpu(td); 28728cbb9b1SJustin Hibbits break; 28828cbb9b1SJustin Hibbits 28928cbb9b1SJustin Hibbits case EXC_VEC: 29028cbb9b1SJustin Hibbits KASSERT((td->td_pcb->pcb_flags & PCB_VEC) != PCB_VEC, 29128cbb9b1SJustin Hibbits ("Altivec already enabled for thread")); 29228cbb9b1SJustin Hibbits enable_vec(td); 29328cbb9b1SJustin Hibbits break; 29428cbb9b1SJustin Hibbits 29528cbb9b1SJustin Hibbits case EXC_VSX: 29628cbb9b1SJustin Hibbits KASSERT((td->td_pcb->pcb_flags & PCB_VSX) != PCB_VSX, 29728cbb9b1SJustin Hibbits ("VSX already enabled for thread")); 29828cbb9b1SJustin Hibbits if (!(td->td_pcb->pcb_flags & PCB_VEC)) 29928cbb9b1SJustin Hibbits enable_vec(td); 30028cbb9b1SJustin Hibbits if (!(td->td_pcb->pcb_flags & PCB_FPU)) 30128cbb9b1SJustin Hibbits save_fpu(td); 30228cbb9b1SJustin Hibbits td->td_pcb->pcb_flags |= PCB_VSX; 30328cbb9b1SJustin Hibbits enable_fpu(td); 30428cbb9b1SJustin Hibbits break; 30528cbb9b1SJustin Hibbits 3067cd4e55cSJustin Hibbits case EXC_FAC: 307ac2605b1SJustin Hibbits fscr = mfspr(SPR_FSCR); 308ac2605b1SJustin Hibbits if ((fscr & FSCR_IC_MASK) == FSCR_IC_HTM) { 309ac2605b1SJustin Hibbits CTR0(KTR_TRAP, "Hardware Transactional Memory subsystem disabled"); 310ac2605b1SJustin Hibbits } 311ac2605b1SJustin Hibbits sig = SIGILL; 312ac2605b1SJustin Hibbits ucode = ILL_ILLOPC; 313ac2605b1SJustin Hibbits break; 314838070d5SWojciech Macek case EXC_HEA: 3157cd4e55cSJustin Hibbits sig = SIGILL; 3167cd4e55cSJustin Hibbits ucode = ILL_ILLOPC; 3177cd4e55cSJustin Hibbits break; 3187cd4e55cSJustin Hibbits 319541c5806SJustin Hibbits case EXC_VECAST_E: 32028cbb9b1SJustin Hibbits case EXC_VECAST_G4: 32128cbb9b1SJustin Hibbits case EXC_VECAST_G5: 32228cbb9b1SJustin Hibbits /* 32328cbb9b1SJustin Hibbits * We get a VPU assist exception for IEEE mode 32428cbb9b1SJustin Hibbits * vector operations on denormalized floats. 32528cbb9b1SJustin Hibbits * Emulating this is a giant pain, so for now, 32628cbb9b1SJustin Hibbits * just switch off IEEE mode and treat them as 32728cbb9b1SJustin Hibbits * zero. 32828cbb9b1SJustin Hibbits */ 32928cbb9b1SJustin Hibbits 33028cbb9b1SJustin Hibbits save_vec(td); 33128cbb9b1SJustin Hibbits td->td_pcb->pcb_vec.vscr |= ALTIVEC_VSCR_NJ; 33228cbb9b1SJustin Hibbits enable_vec(td); 33328cbb9b1SJustin Hibbits break; 33428cbb9b1SJustin Hibbits 33528cbb9b1SJustin Hibbits case EXC_ALI: 33628cbb9b1SJustin Hibbits if (fix_unaligned(td, frame) != 0) { 33728cbb9b1SJustin Hibbits sig = SIGBUS; 33828cbb9b1SJustin Hibbits ucode = BUS_ADRALN; 33928cbb9b1SJustin Hibbits } 34028cbb9b1SJustin Hibbits else 34128cbb9b1SJustin Hibbits frame->srr0 += 4; 34228cbb9b1SJustin Hibbits break; 34328cbb9b1SJustin Hibbits 34428cbb9b1SJustin Hibbits case EXC_DEBUG: /* Single stepping */ 34528cbb9b1SJustin Hibbits mtspr(SPR_DBSR, mfspr(SPR_DBSR)); 34628cbb9b1SJustin Hibbits frame->srr1 &= ~PSL_DE; 347fa133b6bSJustin Hibbits frame->cpu.booke.dbcr0 &= ~(DBCR0_IDM | DBCR0_IC); 34828cbb9b1SJustin Hibbits sig = SIGTRAP; 34928cbb9b1SJustin Hibbits ucode = TRAP_TRACE; 35028cbb9b1SJustin Hibbits break; 35128cbb9b1SJustin Hibbits 35228cbb9b1SJustin Hibbits case EXC_PGM: 35328cbb9b1SJustin Hibbits /* Identify the trap reason */ 354a72b9513SJustin Hibbits if (frame_is_trap_inst(frame)) { 35528cbb9b1SJustin Hibbits #ifdef KDTRACE_HOOKS 35628cbb9b1SJustin Hibbits inst = fuword32((const void *)frame->srr0); 35728cbb9b1SJustin Hibbits if (inst == 0x0FFFDDDD && 35828cbb9b1SJustin Hibbits dtrace_pid_probe_ptr != NULL) { 3595bab6234SMark Johnston (*dtrace_pid_probe_ptr)(frame); 36028cbb9b1SJustin Hibbits break; 36128cbb9b1SJustin Hibbits } 36228cbb9b1SJustin Hibbits #endif 36328cbb9b1SJustin Hibbits sig = SIGTRAP; 36428cbb9b1SJustin Hibbits ucode = TRAP_BRKPT; 36528cbb9b1SJustin Hibbits } else { 36628cbb9b1SJustin Hibbits sig = ppc_instr_emulate(frame, td->td_pcb); 36728cbb9b1SJustin Hibbits if (sig == SIGILL) { 36828cbb9b1SJustin Hibbits if (frame->srr1 & EXC_PGM_PRIV) 36928cbb9b1SJustin Hibbits ucode = ILL_PRVOPC; 37028cbb9b1SJustin Hibbits else if (frame->srr1 & EXC_PGM_ILLEGAL) 37128cbb9b1SJustin Hibbits ucode = ILL_ILLOPC; 37228cbb9b1SJustin Hibbits } else if (sig == SIGFPE) 37328cbb9b1SJustin Hibbits ucode = FPE_FLTINV; /* Punt for now, invalid operation. */ 37428cbb9b1SJustin Hibbits } 37528cbb9b1SJustin Hibbits break; 37628cbb9b1SJustin Hibbits 37728cbb9b1SJustin Hibbits case EXC_MCHK: 37828cbb9b1SJustin Hibbits /* 37928cbb9b1SJustin Hibbits * Note that this may not be recoverable for the user 38028cbb9b1SJustin Hibbits * process, depending on the type of machine check, 38128cbb9b1SJustin Hibbits * but it at least prevents the kernel from dying. 38228cbb9b1SJustin Hibbits */ 38328cbb9b1SJustin Hibbits sig = SIGBUS; 38428cbb9b1SJustin Hibbits ucode = BUS_OBJERR; 38528cbb9b1SJustin Hibbits break; 38628cbb9b1SJustin Hibbits 387be2bd024SLeandro Lupori #if defined(__powerpc64__) && defined(AIM) 388be2bd024SLeandro Lupori case EXC_SOFT_PATCH: 389be2bd024SLeandro Lupori /* 390be2bd024SLeandro Lupori * Point to the instruction that generated the exception to execute it again, 391be2bd024SLeandro Lupori * and normalize the register values. 392be2bd024SLeandro Lupori */ 393be2bd024SLeandro Lupori frame->srr0 -= 4; 394be2bd024SLeandro Lupori normalize_inputs(); 395be2bd024SLeandro Lupori break; 396be2bd024SLeandro Lupori #endif 397be2bd024SLeandro Lupori 39828cbb9b1SJustin Hibbits default: 39928cbb9b1SJustin Hibbits trap_fatal(frame); 40028cbb9b1SJustin Hibbits } 40128cbb9b1SJustin Hibbits } else { 40228cbb9b1SJustin Hibbits /* Kernel Mode Traps */ 40328cbb9b1SJustin Hibbits 40428cbb9b1SJustin Hibbits KASSERT(cold || td->td_ucred != NULL, 40528cbb9b1SJustin Hibbits ("kernel trap doesn't have ucred")); 40628cbb9b1SJustin Hibbits switch (type) { 40728cbb9b1SJustin Hibbits case EXC_PGM: 40815fc4ab7SJustin Hibbits #ifdef KDTRACE_HOOKS 409a72b9513SJustin Hibbits if (frame_is_trap_inst(frame)) { 41028cbb9b1SJustin Hibbits if (*(uint32_t *)frame->srr0 == EXC_DTRACE) { 41128cbb9b1SJustin Hibbits if (dtrace_invop_jump_addr != NULL) { 41228cbb9b1SJustin Hibbits dtrace_invop_jump_addr(frame); 41328cbb9b1SJustin Hibbits return; 41428cbb9b1SJustin Hibbits } 41528cbb9b1SJustin Hibbits } 41628cbb9b1SJustin Hibbits } 41728cbb9b1SJustin Hibbits #endif 41815fc4ab7SJustin Hibbits #ifdef KDB 41915fc4ab7SJustin Hibbits if (db_trap_glue(frame)) 42015fc4ab7SJustin Hibbits return; 42115fc4ab7SJustin Hibbits #endif 42215fc4ab7SJustin Hibbits break; 423d5a30121SJustin Hibbits #if defined(__powerpc64__) && defined(AIM) 42428cbb9b1SJustin Hibbits case EXC_DSE: 425eb1baf72SNathan Whitehorn if (td->td_pcb->pcb_cpu.aim.usr_vsid != 0 && 426eb1baf72SNathan Whitehorn (frame->dar & SEGMENT_MASK) == USER_ADDR) { 42728cbb9b1SJustin Hibbits __asm __volatile ("slbmte %0, %1" :: 42828cbb9b1SJustin Hibbits "r"(td->td_pcb->pcb_cpu.aim.usr_vsid), 42928cbb9b1SJustin Hibbits "r"(USER_SLB_SLBE)); 43028cbb9b1SJustin Hibbits return; 43128cbb9b1SJustin Hibbits } 43228cbb9b1SJustin Hibbits break; 43328cbb9b1SJustin Hibbits #endif 43428cbb9b1SJustin Hibbits case EXC_DSI: 43528cbb9b1SJustin Hibbits if (trap_pfault(frame, 0) == 0) 43628cbb9b1SJustin Hibbits return; 43728cbb9b1SJustin Hibbits break; 43828cbb9b1SJustin Hibbits case EXC_MCHK: 43928cbb9b1SJustin Hibbits if (handle_onfault(frame)) 44028cbb9b1SJustin Hibbits return; 44128cbb9b1SJustin Hibbits break; 44228cbb9b1SJustin Hibbits default: 44328cbb9b1SJustin Hibbits break; 44428cbb9b1SJustin Hibbits } 44528cbb9b1SJustin Hibbits trap_fatal(frame); 44628cbb9b1SJustin Hibbits } 44728cbb9b1SJustin Hibbits 44828cbb9b1SJustin Hibbits if (sig != 0) { 44928cbb9b1SJustin Hibbits if (p->p_sysent->sv_transtrap != NULL) 45028cbb9b1SJustin Hibbits sig = (p->p_sysent->sv_transtrap)(sig, type); 45128cbb9b1SJustin Hibbits ksiginfo_init_trap(&ksi); 45228cbb9b1SJustin Hibbits ksi.ksi_signo = sig; 45328cbb9b1SJustin Hibbits ksi.ksi_code = (int) ucode; /* XXX, not POSIX */ 45424dd643dSJustin Hibbits ksi.ksi_addr = (void *)frame->srr0; 45528cbb9b1SJustin Hibbits ksi.ksi_trapno = type; 45628cbb9b1SJustin Hibbits trapsignal(td, &ksi); 45728cbb9b1SJustin Hibbits } 45828cbb9b1SJustin Hibbits 45928cbb9b1SJustin Hibbits userret(td, frame); 46028cbb9b1SJustin Hibbits } 46128cbb9b1SJustin Hibbits 46228cbb9b1SJustin Hibbits static void 46328cbb9b1SJustin Hibbits trap_fatal(struct trapframe *frame) 46428cbb9b1SJustin Hibbits { 465f3f6ecb4SAndriy Gapon #ifdef KDB 466f3f6ecb4SAndriy Gapon bool handled; 467f3f6ecb4SAndriy Gapon #endif 46828cbb9b1SJustin Hibbits 46928cbb9b1SJustin Hibbits printtrap(frame->exc, frame, 1, (frame->srr1 & PSL_PR)); 47028cbb9b1SJustin Hibbits #ifdef KDB 471b317cfd4SJohn Baldwin if (debugger_on_trap) { 472f3f6ecb4SAndriy Gapon kdb_why = KDB_WHY_TRAP; 473f3f6ecb4SAndriy Gapon handled = kdb_trap(frame->exc, 0, frame); 474f3f6ecb4SAndriy Gapon kdb_why = KDB_WHY_UNSET; 475f3f6ecb4SAndriy Gapon if (handled) 47628cbb9b1SJustin Hibbits return; 477f3f6ecb4SAndriy Gapon } 47828cbb9b1SJustin Hibbits #endif 47928cbb9b1SJustin Hibbits panic("%s trap", trapname(frame->exc)); 48028cbb9b1SJustin Hibbits } 48128cbb9b1SJustin Hibbits 48228cbb9b1SJustin Hibbits static void 483fcc491a3SJustin Hibbits cpu_printtrap(u_int vector, struct trapframe *frame, int isfatal, int user) 484fcc491a3SJustin Hibbits { 485fcc491a3SJustin Hibbits #ifdef AIM 486fcc491a3SJustin Hibbits uint16_t ver; 487fcc491a3SJustin Hibbits 488fcc491a3SJustin Hibbits switch (vector) { 489fcc491a3SJustin Hibbits case EXC_DSE: 490fcc491a3SJustin Hibbits case EXC_DSI: 491fcc491a3SJustin Hibbits case EXC_DTMISS: 492fcc491a3SJustin Hibbits printf(" dsisr = 0x%lx\n", 493fcc491a3SJustin Hibbits (u_long)frame->cpu.aim.dsisr); 494fcc491a3SJustin Hibbits break; 495fcc491a3SJustin Hibbits case EXC_MCHK: 496fcc491a3SJustin Hibbits ver = mfpvr() >> 16; 497fcc491a3SJustin Hibbits if (MPC745X_P(ver)) 498fcc491a3SJustin Hibbits printf(" msssr0 = 0x%b\n", 499fcc491a3SJustin Hibbits (int)mfspr(SPR_MSSSR0), MSSSR_BITMASK); 500fcc491a3SJustin Hibbits break; 501fcc491a3SJustin Hibbits } 502fcc491a3SJustin Hibbits #elif defined(BOOKE) 503fcc491a3SJustin Hibbits vm_paddr_t pa; 504fcc491a3SJustin Hibbits 505fcc491a3SJustin Hibbits switch (vector) { 506fcc491a3SJustin Hibbits case EXC_MCHK: 507fcc491a3SJustin Hibbits pa = mfspr(SPR_MCARU); 508fcc491a3SJustin Hibbits pa = (pa << 32) | (u_register_t)mfspr(SPR_MCAR); 509fcc491a3SJustin Hibbits printf(" mcsr = 0x%b\n", 510fcc491a3SJustin Hibbits (int)mfspr(SPR_MCSR), MCSR_BITMASK); 511fcc491a3SJustin Hibbits printf(" mcar = 0x%jx\n", (uintmax_t)pa); 512fcc491a3SJustin Hibbits } 513fcc491a3SJustin Hibbits printf(" esr = 0x%b\n", 514fcc491a3SJustin Hibbits (int)frame->cpu.booke.esr, ESR_BITMASK); 515fcc491a3SJustin Hibbits #endif 516fcc491a3SJustin Hibbits } 517fcc491a3SJustin Hibbits 518fcc491a3SJustin Hibbits static void 51928cbb9b1SJustin Hibbits printtrap(u_int vector, struct trapframe *frame, int isfatal, int user) 52028cbb9b1SJustin Hibbits { 52128cbb9b1SJustin Hibbits 52228cbb9b1SJustin Hibbits printf("\n"); 52328cbb9b1SJustin Hibbits printf("%s %s trap:\n", isfatal ? "fatal" : "handled", 52428cbb9b1SJustin Hibbits user ? "user" : "kernel"); 52528cbb9b1SJustin Hibbits printf("\n"); 52628cbb9b1SJustin Hibbits printf(" exception = 0x%x (%s)\n", vector, trapname(vector)); 52728cbb9b1SJustin Hibbits switch (vector) { 52828cbb9b1SJustin Hibbits case EXC_DSE: 52928cbb9b1SJustin Hibbits case EXC_DSI: 53039a4b70fSJustin Hibbits case EXC_DTMISS: 53128cbb9b1SJustin Hibbits printf(" virtual address = 0x%" PRIxPTR "\n", frame->dar); 53228cbb9b1SJustin Hibbits break; 53328cbb9b1SJustin Hibbits case EXC_ISE: 53428cbb9b1SJustin Hibbits case EXC_ISI: 53539a4b70fSJustin Hibbits case EXC_ITMISS: 53628cbb9b1SJustin Hibbits printf(" virtual address = 0x%" PRIxPTR "\n", frame->srr0); 53728cbb9b1SJustin Hibbits break; 538398973f8SJustin Hibbits case EXC_MCHK: 539398973f8SJustin Hibbits break; 54028cbb9b1SJustin Hibbits } 541fcc491a3SJustin Hibbits cpu_printtrap(vector, frame, isfatal, user); 542ec75f647SNathan Whitehorn printf(" srr0 = 0x%" PRIxPTR " (0x%" PRIxPTR ")\n", 5434e05ac24SNathan Whitehorn frame->srr0, frame->srr0 - (register_t)(__startkernel - KERNBASE)); 544cf5aa326SJustin Hibbits printf(" srr1 = 0x%lx\n", (u_long)frame->srr1); 5453762bafaSJustin Hibbits printf(" current msr = 0x%" PRIxPTR "\n", mfmsr()); 546ec75f647SNathan Whitehorn printf(" lr = 0x%" PRIxPTR " (0x%" PRIxPTR ")\n", 5474e05ac24SNathan Whitehorn frame->lr, frame->lr - (register_t)(__startkernel - KERNBASE)); 54828cbb9b1SJustin Hibbits printf(" curthread = %p\n", curthread); 54928cbb9b1SJustin Hibbits if (curthread != NULL) 55028cbb9b1SJustin Hibbits printf(" pid = %d, comm = %s\n", 55128cbb9b1SJustin Hibbits curthread->td_proc->p_pid, curthread->td_name); 55228cbb9b1SJustin Hibbits printf("\n"); 55328cbb9b1SJustin Hibbits } 55428cbb9b1SJustin Hibbits 55528cbb9b1SJustin Hibbits /* 55628cbb9b1SJustin Hibbits * Handles a fatal fault when we have onfault state to recover. Returns 55728cbb9b1SJustin Hibbits * non-zero if there was onfault recovery state available. 55828cbb9b1SJustin Hibbits */ 55928cbb9b1SJustin Hibbits static int 56028cbb9b1SJustin Hibbits handle_onfault(struct trapframe *frame) 56128cbb9b1SJustin Hibbits { 56228cbb9b1SJustin Hibbits struct thread *td; 563a18c313eSNathan Whitehorn jmp_buf *fb; 56428cbb9b1SJustin Hibbits 56528cbb9b1SJustin Hibbits td = curthread; 56628cbb9b1SJustin Hibbits fb = td->td_pcb->pcb_onfault; 56728cbb9b1SJustin Hibbits if (fb != NULL) { 568a18c313eSNathan Whitehorn frame->srr0 = (*fb)->_jb[FAULTBUF_LR]; 569a18c313eSNathan Whitehorn frame->fixreg[1] = (*fb)->_jb[FAULTBUF_R1]; 570a18c313eSNathan Whitehorn frame->fixreg[2] = (*fb)->_jb[FAULTBUF_R2]; 57128cbb9b1SJustin Hibbits frame->fixreg[3] = 1; 572a18c313eSNathan Whitehorn frame->cr = (*fb)->_jb[FAULTBUF_CR]; 573a18c313eSNathan Whitehorn bcopy(&(*fb)->_jb[FAULTBUF_R14], &frame->fixreg[14], 574a18c313eSNathan Whitehorn 18 * sizeof(register_t)); 575a18c313eSNathan Whitehorn td->td_pcb->pcb_onfault = NULL; /* Returns twice, not thrice */ 57628cbb9b1SJustin Hibbits return (1); 57728cbb9b1SJustin Hibbits } 57828cbb9b1SJustin Hibbits return (0); 57928cbb9b1SJustin Hibbits } 58028cbb9b1SJustin Hibbits 58128cbb9b1SJustin Hibbits int 5822d88da2fSKonstantin Belousov cpu_fetch_syscall_args(struct thread *td) 58328cbb9b1SJustin Hibbits { 58428cbb9b1SJustin Hibbits struct proc *p; 58528cbb9b1SJustin Hibbits struct trapframe *frame; 5862d88da2fSKonstantin Belousov struct syscall_args *sa; 58728cbb9b1SJustin Hibbits caddr_t params; 58828cbb9b1SJustin Hibbits size_t argsz; 58928cbb9b1SJustin Hibbits int error, n, i; 59028cbb9b1SJustin Hibbits 59128cbb9b1SJustin Hibbits p = td->td_proc; 59228cbb9b1SJustin Hibbits frame = td->td_frame; 5932d88da2fSKonstantin Belousov sa = &td->td_sa; 59428cbb9b1SJustin Hibbits 59528cbb9b1SJustin Hibbits sa->code = frame->fixreg[0]; 59628cbb9b1SJustin Hibbits params = (caddr_t)(frame->fixreg + FIRSTARG); 59728cbb9b1SJustin Hibbits n = NARGREG; 59828cbb9b1SJustin Hibbits 59928cbb9b1SJustin Hibbits if (sa->code == SYS_syscall) { 60028cbb9b1SJustin Hibbits /* 60128cbb9b1SJustin Hibbits * code is first argument, 60228cbb9b1SJustin Hibbits * followed by actual args. 60328cbb9b1SJustin Hibbits */ 60428cbb9b1SJustin Hibbits sa->code = *(register_t *) params; 60528cbb9b1SJustin Hibbits params += sizeof(register_t); 60628cbb9b1SJustin Hibbits n -= 1; 60728cbb9b1SJustin Hibbits } else if (sa->code == SYS___syscall) { 60828cbb9b1SJustin Hibbits /* 60928cbb9b1SJustin Hibbits * Like syscall, but code is a quad, 61028cbb9b1SJustin Hibbits * so as to maintain quad alignment 61128cbb9b1SJustin Hibbits * for the rest of the args. 61228cbb9b1SJustin Hibbits */ 61328cbb9b1SJustin Hibbits if (SV_PROC_FLAG(p, SV_ILP32)) { 61428cbb9b1SJustin Hibbits params += sizeof(register_t); 61528cbb9b1SJustin Hibbits sa->code = *(register_t *) params; 61628cbb9b1SJustin Hibbits params += sizeof(register_t); 61728cbb9b1SJustin Hibbits n -= 2; 61828cbb9b1SJustin Hibbits } else { 61928cbb9b1SJustin Hibbits sa->code = *(register_t *) params; 62028cbb9b1SJustin Hibbits params += sizeof(register_t); 62128cbb9b1SJustin Hibbits n -= 1; 62228cbb9b1SJustin Hibbits } 62328cbb9b1SJustin Hibbits } 62428cbb9b1SJustin Hibbits 62528cbb9b1SJustin Hibbits if (p->p_sysent->sv_mask) 62628cbb9b1SJustin Hibbits sa->code &= p->p_sysent->sv_mask; 62728cbb9b1SJustin Hibbits if (sa->code >= p->p_sysent->sv_size) 62828cbb9b1SJustin Hibbits sa->callp = &p->p_sysent->sv_table[0]; 62928cbb9b1SJustin Hibbits else 63028cbb9b1SJustin Hibbits sa->callp = &p->p_sysent->sv_table[sa->code]; 63128cbb9b1SJustin Hibbits 63228cbb9b1SJustin Hibbits sa->narg = sa->callp->sy_narg; 63328cbb9b1SJustin Hibbits 63428cbb9b1SJustin Hibbits if (SV_PROC_FLAG(p, SV_ILP32)) { 63528cbb9b1SJustin Hibbits argsz = sizeof(uint32_t); 63628cbb9b1SJustin Hibbits 63728cbb9b1SJustin Hibbits for (i = 0; i < n; i++) 63828cbb9b1SJustin Hibbits sa->args[i] = ((u_register_t *)(params))[i] & 63928cbb9b1SJustin Hibbits 0xffffffff; 64028cbb9b1SJustin Hibbits } else { 64128cbb9b1SJustin Hibbits argsz = sizeof(uint64_t); 64228cbb9b1SJustin Hibbits 64328cbb9b1SJustin Hibbits for (i = 0; i < n; i++) 64428cbb9b1SJustin Hibbits sa->args[i] = ((u_register_t *)(params))[i]; 64528cbb9b1SJustin Hibbits } 64628cbb9b1SJustin Hibbits 64728cbb9b1SJustin Hibbits if (sa->narg > n) 64828cbb9b1SJustin Hibbits error = copyin(MOREARGS(frame->fixreg[1]), sa->args + n, 64928cbb9b1SJustin Hibbits (sa->narg - n) * argsz); 65028cbb9b1SJustin Hibbits else 65128cbb9b1SJustin Hibbits error = 0; 65228cbb9b1SJustin Hibbits 65328cbb9b1SJustin Hibbits #ifdef __powerpc64__ 65428cbb9b1SJustin Hibbits if (SV_PROC_FLAG(p, SV_ILP32) && sa->narg > n) { 65528cbb9b1SJustin Hibbits /* Expand the size of arguments copied from the stack */ 65628cbb9b1SJustin Hibbits 65728cbb9b1SJustin Hibbits for (i = sa->narg; i >= n; i--) 65828cbb9b1SJustin Hibbits sa->args[i] = ((uint32_t *)(&sa->args[n]))[i-n]; 65928cbb9b1SJustin Hibbits } 66028cbb9b1SJustin Hibbits #endif 66128cbb9b1SJustin Hibbits 66228cbb9b1SJustin Hibbits if (error == 0) { 66328cbb9b1SJustin Hibbits td->td_retval[0] = 0; 66428cbb9b1SJustin Hibbits td->td_retval[1] = frame->fixreg[FIRSTARG + 1]; 66528cbb9b1SJustin Hibbits } 66628cbb9b1SJustin Hibbits return (error); 66728cbb9b1SJustin Hibbits } 66828cbb9b1SJustin Hibbits 66928cbb9b1SJustin Hibbits #include "../../kern/subr_syscall.c" 67028cbb9b1SJustin Hibbits 67128cbb9b1SJustin Hibbits void 67228cbb9b1SJustin Hibbits syscall(struct trapframe *frame) 67328cbb9b1SJustin Hibbits { 67428cbb9b1SJustin Hibbits struct thread *td; 67528cbb9b1SJustin Hibbits int error; 67628cbb9b1SJustin Hibbits 67728cbb9b1SJustin Hibbits td = curthread; 67828cbb9b1SJustin Hibbits td->td_frame = frame; 67928cbb9b1SJustin Hibbits 680d5a30121SJustin Hibbits #if defined(__powerpc64__) && defined(AIM) 68128cbb9b1SJustin Hibbits /* 68228cbb9b1SJustin Hibbits * Speculatively restore last user SLB segment, which we know is 68328cbb9b1SJustin Hibbits * invalid already, since we are likely to do copyin()/copyout(). 68428cbb9b1SJustin Hibbits */ 685e649493cSNathan Whitehorn if (td->td_pcb->pcb_cpu.aim.usr_vsid != 0) 68628cbb9b1SJustin Hibbits __asm __volatile ("slbmte %0, %1; isync" :: 68728cbb9b1SJustin Hibbits "r"(td->td_pcb->pcb_cpu.aim.usr_vsid), "r"(USER_SLB_SLBE)); 68828cbb9b1SJustin Hibbits #endif 68928cbb9b1SJustin Hibbits 6902d88da2fSKonstantin Belousov error = syscallenter(td); 6912d88da2fSKonstantin Belousov syscallret(td, error); 69228cbb9b1SJustin Hibbits } 69328cbb9b1SJustin Hibbits 694d5a30121SJustin Hibbits #if defined(__powerpc64__) && defined(AIM) 69528cbb9b1SJustin Hibbits /* Handle kernel SLB faults -- runs in real mode, all seat belts off */ 69628cbb9b1SJustin Hibbits void 69728cbb9b1SJustin Hibbits handle_kernel_slb_spill(int type, register_t dar, register_t srr0) 69828cbb9b1SJustin Hibbits { 69928cbb9b1SJustin Hibbits struct slb *slbcache; 70028cbb9b1SJustin Hibbits uint64_t slbe, slbv; 70128cbb9b1SJustin Hibbits uint64_t esid, addr; 70228cbb9b1SJustin Hibbits int i; 70328cbb9b1SJustin Hibbits 70428cbb9b1SJustin Hibbits addr = (type == EXC_ISE) ? srr0 : dar; 705bce6d88bSJustin Hibbits slbcache = PCPU_GET(aim.slb); 70628cbb9b1SJustin Hibbits esid = (uintptr_t)addr >> ADDR_SR_SHFT; 70728cbb9b1SJustin Hibbits slbe = (esid << SLBE_ESID_SHIFT) | SLBE_VALID; 70828cbb9b1SJustin Hibbits 70928cbb9b1SJustin Hibbits /* See if the hardware flushed this somehow (can happen in LPARs) */ 71028cbb9b1SJustin Hibbits for (i = 0; i < n_slbs; i++) 71128cbb9b1SJustin Hibbits if (slbcache[i].slbe == (slbe | (uint64_t)i)) 71228cbb9b1SJustin Hibbits return; 71328cbb9b1SJustin Hibbits 71428cbb9b1SJustin Hibbits /* Not in the map, needs to actually be added */ 71528cbb9b1SJustin Hibbits slbv = kernel_va_to_slbv(addr); 71628cbb9b1SJustin Hibbits if (slbcache[USER_SLB_SLOT].slbe == 0) { 71728cbb9b1SJustin Hibbits for (i = 0; i < n_slbs; i++) { 71828cbb9b1SJustin Hibbits if (i == USER_SLB_SLOT) 71928cbb9b1SJustin Hibbits continue; 72028cbb9b1SJustin Hibbits if (!(slbcache[i].slbe & SLBE_VALID)) 72128cbb9b1SJustin Hibbits goto fillkernslb; 72228cbb9b1SJustin Hibbits } 72328cbb9b1SJustin Hibbits 72428cbb9b1SJustin Hibbits if (i == n_slbs) 72528cbb9b1SJustin Hibbits slbcache[USER_SLB_SLOT].slbe = 1; 72628cbb9b1SJustin Hibbits } 72728cbb9b1SJustin Hibbits 72828cbb9b1SJustin Hibbits /* Sacrifice a random SLB entry that is not the user entry */ 72928cbb9b1SJustin Hibbits i = mftb() % n_slbs; 73028cbb9b1SJustin Hibbits if (i == USER_SLB_SLOT) 73128cbb9b1SJustin Hibbits i = (i+1) % n_slbs; 73228cbb9b1SJustin Hibbits 73328cbb9b1SJustin Hibbits fillkernslb: 73428cbb9b1SJustin Hibbits /* Write new entry */ 73528cbb9b1SJustin Hibbits slbcache[i].slbv = slbv; 73628cbb9b1SJustin Hibbits slbcache[i].slbe = slbe | (uint64_t)i; 73728cbb9b1SJustin Hibbits 73828cbb9b1SJustin Hibbits /* Trap handler will restore from cache on exit */ 73928cbb9b1SJustin Hibbits } 74028cbb9b1SJustin Hibbits 74128cbb9b1SJustin Hibbits static int 74228cbb9b1SJustin Hibbits handle_user_slb_spill(pmap_t pm, vm_offset_t addr) 74328cbb9b1SJustin Hibbits { 74428cbb9b1SJustin Hibbits struct slb *user_entry; 74528cbb9b1SJustin Hibbits uint64_t esid; 74628cbb9b1SJustin Hibbits int i; 74728cbb9b1SJustin Hibbits 748e649493cSNathan Whitehorn if (pm->pm_slb == NULL) 749e649493cSNathan Whitehorn return (-1); 750e649493cSNathan Whitehorn 75128cbb9b1SJustin Hibbits esid = (uintptr_t)addr >> ADDR_SR_SHFT; 75228cbb9b1SJustin Hibbits 75328cbb9b1SJustin Hibbits PMAP_LOCK(pm); 75428cbb9b1SJustin Hibbits user_entry = user_va_to_slb_entry(pm, addr); 75528cbb9b1SJustin Hibbits 75628cbb9b1SJustin Hibbits if (user_entry == NULL) { 75728cbb9b1SJustin Hibbits /* allocate_vsid auto-spills it */ 75828cbb9b1SJustin Hibbits (void)allocate_user_vsid(pm, esid, 0); 75928cbb9b1SJustin Hibbits } else { 76028cbb9b1SJustin Hibbits /* 76128cbb9b1SJustin Hibbits * Check that another CPU has not already mapped this. 76228cbb9b1SJustin Hibbits * XXX: Per-thread SLB caches would be better. 76328cbb9b1SJustin Hibbits */ 76428cbb9b1SJustin Hibbits for (i = 0; i < pm->pm_slb_len; i++) 76528cbb9b1SJustin Hibbits if (pm->pm_slb[i] == user_entry) 76628cbb9b1SJustin Hibbits break; 76728cbb9b1SJustin Hibbits 76828cbb9b1SJustin Hibbits if (i == pm->pm_slb_len) 76928cbb9b1SJustin Hibbits slb_insert_user(pm, user_entry); 77028cbb9b1SJustin Hibbits } 77128cbb9b1SJustin Hibbits PMAP_UNLOCK(pm); 77228cbb9b1SJustin Hibbits 77328cbb9b1SJustin Hibbits return (0); 77428cbb9b1SJustin Hibbits } 77528cbb9b1SJustin Hibbits #endif 77628cbb9b1SJustin Hibbits 77728cbb9b1SJustin Hibbits static int 77828cbb9b1SJustin Hibbits trap_pfault(struct trapframe *frame, int user) 77928cbb9b1SJustin Hibbits { 78028cbb9b1SJustin Hibbits vm_offset_t eva, va; 78128cbb9b1SJustin Hibbits struct thread *td; 78228cbb9b1SJustin Hibbits struct proc *p; 78328cbb9b1SJustin Hibbits vm_map_t map; 78428cbb9b1SJustin Hibbits vm_prot_t ftype; 785eb1baf72SNathan Whitehorn int rv, is_user; 78628cbb9b1SJustin Hibbits 78728cbb9b1SJustin Hibbits td = curthread; 78828cbb9b1SJustin Hibbits p = td->td_proc; 78928cbb9b1SJustin Hibbits if (frame->exc == EXC_ISI) { 79028cbb9b1SJustin Hibbits eva = frame->srr0; 79128cbb9b1SJustin Hibbits ftype = VM_PROT_EXECUTE; 79228cbb9b1SJustin Hibbits if (frame->srr1 & SRR1_ISI_PFAULT) 79328cbb9b1SJustin Hibbits ftype |= VM_PROT_READ; 79428cbb9b1SJustin Hibbits } else { 79528cbb9b1SJustin Hibbits eva = frame->dar; 79628cbb9b1SJustin Hibbits #ifdef BOOKE 79728cbb9b1SJustin Hibbits if (frame->cpu.booke.esr & ESR_ST) 79828cbb9b1SJustin Hibbits #else 79928cbb9b1SJustin Hibbits if (frame->cpu.aim.dsisr & DSISR_STORE) 80028cbb9b1SJustin Hibbits #endif 80128cbb9b1SJustin Hibbits ftype = VM_PROT_WRITE; 80228cbb9b1SJustin Hibbits else 80328cbb9b1SJustin Hibbits ftype = VM_PROT_READ; 80428cbb9b1SJustin Hibbits } 80528cbb9b1SJustin Hibbits 80628cbb9b1SJustin Hibbits if (user) { 80728cbb9b1SJustin Hibbits KASSERT(p->p_vmspace != NULL, ("trap_pfault: vmspace NULL")); 80828cbb9b1SJustin Hibbits map = &p->p_vmspace->vm_map; 80928cbb9b1SJustin Hibbits } else { 810eb1baf72SNathan Whitehorn rv = pmap_decode_kernel_ptr(eva, &is_user, &eva); 811eb1baf72SNathan Whitehorn if (rv != 0) 812eb1baf72SNathan Whitehorn return (SIGSEGV); 81328cbb9b1SJustin Hibbits 814eb1baf72SNathan Whitehorn if (is_user) 815eb1baf72SNathan Whitehorn map = &p->p_vmspace->vm_map; 816eb1baf72SNathan Whitehorn else 81728cbb9b1SJustin Hibbits map = kernel_map; 81828cbb9b1SJustin Hibbits } 81928cbb9b1SJustin Hibbits va = trunc_page(eva); 82028cbb9b1SJustin Hibbits 8211fa67124SKonstantin Belousov /* Fault in the page. */ 82228cbb9b1SJustin Hibbits rv = vm_fault(map, va, ftype, VM_FAULT_NORMAL); 82328cbb9b1SJustin Hibbits /* 82428cbb9b1SJustin Hibbits * XXXDTRACE: add dtrace_doubletrap_func here? 82528cbb9b1SJustin Hibbits */ 82628cbb9b1SJustin Hibbits 82728cbb9b1SJustin Hibbits if (rv == KERN_SUCCESS) 82828cbb9b1SJustin Hibbits return (0); 82928cbb9b1SJustin Hibbits 83028cbb9b1SJustin Hibbits if (!user && handle_onfault(frame)) 83128cbb9b1SJustin Hibbits return (0); 83228cbb9b1SJustin Hibbits 83328cbb9b1SJustin Hibbits return (SIGSEGV); 83428cbb9b1SJustin Hibbits } 83528cbb9b1SJustin Hibbits 83628cbb9b1SJustin Hibbits /* 83728cbb9b1SJustin Hibbits * For now, this only deals with the particular unaligned access case 83828cbb9b1SJustin Hibbits * that gcc tends to generate. Eventually it should handle all of the 83928cbb9b1SJustin Hibbits * possibilities that can happen on a 32-bit PowerPC in big-endian mode. 84028cbb9b1SJustin Hibbits */ 84128cbb9b1SJustin Hibbits 84228cbb9b1SJustin Hibbits static int 84328cbb9b1SJustin Hibbits fix_unaligned(struct thread *td, struct trapframe *frame) 84428cbb9b1SJustin Hibbits { 84528cbb9b1SJustin Hibbits struct thread *fputhread; 846dc9b124dSJustin Hibbits #ifdef __SPE__ 847dc9b124dSJustin Hibbits uint32_t inst; 848dc9b124dSJustin Hibbits #endif 84928cbb9b1SJustin Hibbits int indicator, reg; 85028cbb9b1SJustin Hibbits double *fpr; 85128cbb9b1SJustin Hibbits 852dc9b124dSJustin Hibbits #ifdef __SPE__ 853dc9b124dSJustin Hibbits indicator = (frame->cpu.booke.esr & (ESR_ST|ESR_SPE)); 854dc9b124dSJustin Hibbits if (indicator & ESR_SPE) { 855dc9b124dSJustin Hibbits if (copyin((void *)frame->srr0, &inst, sizeof(inst)) != 0) 856dc9b124dSJustin Hibbits return (-1); 857dc9b124dSJustin Hibbits reg = EXC_ALI_SPE_REG(inst); 858dc9b124dSJustin Hibbits fpr = (double *)td->td_pcb->pcb_vec.vr[reg]; 859dc9b124dSJustin Hibbits fputhread = PCPU_GET(vecthread); 860dc9b124dSJustin Hibbits 86189965e70SJustin Hibbits /* Juggle the SPE to ensure that we've initialized 86289965e70SJustin Hibbits * the registers, and that their current state is in 863dc9b124dSJustin Hibbits * the PCB. 864dc9b124dSJustin Hibbits */ 865eaa5e396SJustin Hibbits if (fputhread != td) { 866eaa5e396SJustin Hibbits if (fputhread) 867eaa5e396SJustin Hibbits save_vec(fputhread); 868dc9b124dSJustin Hibbits enable_vec(td); 869dc9b124dSJustin Hibbits } 870dc9b124dSJustin Hibbits save_vec(td); 871dc9b124dSJustin Hibbits 872dc9b124dSJustin Hibbits if (!(indicator & ESR_ST)) { 873dc9b124dSJustin Hibbits if (copyin((void *)frame->dar, fpr, 874dc9b124dSJustin Hibbits sizeof(double)) != 0) 875dc9b124dSJustin Hibbits return (-1); 876dc9b124dSJustin Hibbits frame->fixreg[reg] = td->td_pcb->pcb_vec.vr[reg][1]; 877dc9b124dSJustin Hibbits enable_vec(td); 878dc9b124dSJustin Hibbits } else { 879dc9b124dSJustin Hibbits td->td_pcb->pcb_vec.vr[reg][1] = frame->fixreg[reg]; 880dc9b124dSJustin Hibbits if (copyout(fpr, (void *)frame->dar, 881dc9b124dSJustin Hibbits sizeof(double)) != 0) 882dc9b124dSJustin Hibbits return (-1); 883dc9b124dSJustin Hibbits } 884dc9b124dSJustin Hibbits return (0); 885dc9b124dSJustin Hibbits } 886dc9b124dSJustin Hibbits #else 88728cbb9b1SJustin Hibbits indicator = EXC_ALI_OPCODE_INDICATOR(frame->cpu.aim.dsisr); 88828cbb9b1SJustin Hibbits 88928cbb9b1SJustin Hibbits switch (indicator) { 89028cbb9b1SJustin Hibbits case EXC_ALI_LFD: 89128cbb9b1SJustin Hibbits case EXC_ALI_STFD: 89228cbb9b1SJustin Hibbits reg = EXC_ALI_RST(frame->cpu.aim.dsisr); 89328cbb9b1SJustin Hibbits fpr = &td->td_pcb->pcb_fpu.fpr[reg].fpr; 89428cbb9b1SJustin Hibbits fputhread = PCPU_GET(fputhread); 89528cbb9b1SJustin Hibbits 89628cbb9b1SJustin Hibbits /* Juggle the FPU to ensure that we've initialized 89728cbb9b1SJustin Hibbits * the FPRs, and that their current state is in 89828cbb9b1SJustin Hibbits * the PCB. 89928cbb9b1SJustin Hibbits */ 90028cbb9b1SJustin Hibbits if (fputhread != td) { 90128cbb9b1SJustin Hibbits if (fputhread) 90228cbb9b1SJustin Hibbits save_fpu(fputhread); 90328cbb9b1SJustin Hibbits enable_fpu(td); 90428cbb9b1SJustin Hibbits } 90528cbb9b1SJustin Hibbits save_fpu(td); 90628cbb9b1SJustin Hibbits 90728cbb9b1SJustin Hibbits if (indicator == EXC_ALI_LFD) { 90828cbb9b1SJustin Hibbits if (copyin((void *)frame->dar, fpr, 90928cbb9b1SJustin Hibbits sizeof(double)) != 0) 91028cbb9b1SJustin Hibbits return (-1); 91128cbb9b1SJustin Hibbits enable_fpu(td); 91228cbb9b1SJustin Hibbits } else { 91328cbb9b1SJustin Hibbits if (copyout(fpr, (void *)frame->dar, 91428cbb9b1SJustin Hibbits sizeof(double)) != 0) 91528cbb9b1SJustin Hibbits return (-1); 91628cbb9b1SJustin Hibbits } 91728cbb9b1SJustin Hibbits return (0); 91828cbb9b1SJustin Hibbits break; 91928cbb9b1SJustin Hibbits } 920dc9b124dSJustin Hibbits #endif 92128cbb9b1SJustin Hibbits 92228cbb9b1SJustin Hibbits return (-1); 92328cbb9b1SJustin Hibbits } 92428cbb9b1SJustin Hibbits 925be2bd024SLeandro Lupori #if defined(__powerpc64__) && defined(AIM) 926be2bd024SLeandro Lupori #define MSKNSHL(x, m, n) "(((" #x ") & " #m ") << " #n ")" 927be2bd024SLeandro Lupori #define MSKNSHR(x, m, n) "(((" #x ") & " #m ") >> " #n ")" 928be2bd024SLeandro Lupori 929be2bd024SLeandro Lupori /* xvcpsgndp instruction, built in opcode format. 930be2bd024SLeandro Lupori * This can be changed to use mnemonic after a toolchain update. 931be2bd024SLeandro Lupori */ 932be2bd024SLeandro Lupori #define XVCPSGNDP(xt, xa, xb) \ 933be2bd024SLeandro Lupori __asm __volatile(".long (" \ 934be2bd024SLeandro Lupori MSKNSHL(60, 0x3f, 26) " | " \ 935be2bd024SLeandro Lupori MSKNSHL(xt, 0x1f, 21) " | " \ 936be2bd024SLeandro Lupori MSKNSHL(xa, 0x1f, 16) " | " \ 937be2bd024SLeandro Lupori MSKNSHL(xb, 0x1f, 11) " | " \ 938be2bd024SLeandro Lupori MSKNSHL(240, 0xff, 3) " | " \ 939be2bd024SLeandro Lupori MSKNSHR(xa, 0x20, 3) " | " \ 940be2bd024SLeandro Lupori MSKNSHR(xa, 0x20, 4) " | " \ 941be2bd024SLeandro Lupori MSKNSHR(xa, 0x20, 5) ")") 942be2bd024SLeandro Lupori 943be2bd024SLeandro Lupori /* Macros to normalize 1 or 10 VSX registers */ 944be2bd024SLeandro Lupori #define NORM(x) XVCPSGNDP(x, x, x) 945be2bd024SLeandro Lupori #define NORM10(x) \ 946be2bd024SLeandro Lupori NORM(x ## 0); NORM(x ## 1); NORM(x ## 2); NORM(x ## 3); NORM(x ## 4); \ 947be2bd024SLeandro Lupori NORM(x ## 5); NORM(x ## 6); NORM(x ## 7); NORM(x ## 8); NORM(x ## 9) 948be2bd024SLeandro Lupori 949be2bd024SLeandro Lupori static void 950be2bd024SLeandro Lupori normalize_inputs(void) 951be2bd024SLeandro Lupori { 952be2bd024SLeandro Lupori unsigned long msr; 953be2bd024SLeandro Lupori 954be2bd024SLeandro Lupori /* enable VSX */ 955be2bd024SLeandro Lupori msr = mfmsr(); 956be2bd024SLeandro Lupori mtmsr(msr | PSL_VSX); 957be2bd024SLeandro Lupori 958be2bd024SLeandro Lupori NORM(0); NORM(1); NORM(2); NORM(3); NORM(4); 959be2bd024SLeandro Lupori NORM(5); NORM(6); NORM(7); NORM(8); NORM(9); 960be2bd024SLeandro Lupori NORM10(1); NORM10(2); NORM10(3); NORM10(4); NORM10(5); 961be2bd024SLeandro Lupori NORM(60); NORM(61); NORM(62); NORM(63); 962be2bd024SLeandro Lupori 963be2bd024SLeandro Lupori /* restore MSR */ 964be2bd024SLeandro Lupori mtmsr(msr); 965be2bd024SLeandro Lupori } 966be2bd024SLeandro Lupori #endif 967be2bd024SLeandro Lupori 96828cbb9b1SJustin Hibbits #ifdef KDB 96928cbb9b1SJustin Hibbits int 97028cbb9b1SJustin Hibbits db_trap_glue(struct trapframe *frame) 97128cbb9b1SJustin Hibbits { 97215fc4ab7SJustin Hibbits 97328cbb9b1SJustin Hibbits if (!(frame->srr1 & PSL_PR) 97428cbb9b1SJustin Hibbits && (frame->exc == EXC_TRC || frame->exc == EXC_RUNMODETRC 975a72b9513SJustin Hibbits || frame_is_trap_inst(frame) 97628cbb9b1SJustin Hibbits || frame->exc == EXC_BPT 9779ae2eed9SJustin Hibbits || frame->exc == EXC_DEBUG 97828cbb9b1SJustin Hibbits || frame->exc == EXC_DSI)) { 97928cbb9b1SJustin Hibbits int type = frame->exc; 98028cbb9b1SJustin Hibbits 98128cbb9b1SJustin Hibbits /* Ignore DTrace traps. */ 98228cbb9b1SJustin Hibbits if (*(uint32_t *)frame->srr0 == EXC_DTRACE) 98328cbb9b1SJustin Hibbits return (0); 984a72b9513SJustin Hibbits if (frame_is_trap_inst(frame)) { 98528cbb9b1SJustin Hibbits type = T_BREAKPOINT; 98628cbb9b1SJustin Hibbits } 98728cbb9b1SJustin Hibbits return (kdb_trap(type, 0, frame)); 98828cbb9b1SJustin Hibbits } 98928cbb9b1SJustin Hibbits 99028cbb9b1SJustin Hibbits return (0); 99128cbb9b1SJustin Hibbits } 99228cbb9b1SJustin Hibbits #endif 993