trap.c revision 97347
177957Sbenno/* 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 3477957Sbenno#ifndef lint 3577957Sbennostatic const char rcsid[] = 3677957Sbenno "$FreeBSD: head/sys/powerpc/aim/trap.c 97347 2002-05-27 11:20:19Z benno $"; 3777957Sbenno#endif /* not lint */ 3877957Sbenno 3977957Sbenno#include "opt_ddb.h" 4077957Sbenno#include "opt_ktrace.h" 4177957Sbenno 4277957Sbenno#include <sys/param.h> 4396938Sbenno#include <sys/proc.h> 4496938Sbenno#include <sys/ktr.h> 4586067Smp#include <sys/lock.h> 4686067Smp#include <sys/mutex.h> 4796938Sbenno#include <sys/pioctl.h> 4877957Sbenno#include <sys/reboot.h> 4977957Sbenno#include <sys/syscall.h> 5096938Sbenno#include <sys/sysent.h> 5196255Sbenno#include <sys/systm.h> 5296906Sbenno#include <sys/uio.h> 5377957Sbenno#include <sys/user.h> 5486067Smp#ifdef KTRACE 5577957Sbenno#include <sys/ktrace.h> 5686067Smp#endif 5796938Sbenno#include <sys/vmmeter.h> 5877957Sbenno 5977957Sbenno#include <vm/vm.h> 6086067Smp#include <vm/pmap.h> 6186067Smp#include <vm/vm_extern.h> 6296255Sbenno#include <vm/vm_param.h> 6377957Sbenno#include <vm/vm_kern.h> 6486067Smp#include <vm/vm_map.h> 6596255Sbenno#include <vm/vm_page.h> 6677957Sbenno 6777957Sbenno#include <machine/cpu.h> 6896255Sbenno#include <machine/db_machdep.h> 6996255Sbenno#include <machine/fpu.h> 7077957Sbenno#include <machine/frame.h> 7177957Sbenno#include <machine/pcb.h> 7296255Sbenno#include <machine/pmap.h> 7377957Sbenno#include <machine/psl.h> 7477957Sbenno#include <machine/trap.h> 7596255Sbenno#include <machine/spr.h> 7696255Sbenno#include <machine/sr.h> 7777957Sbenno 7896255Sbenno/* These definitions should probably be somewhere else XXX */ 7977957Sbenno#define FIRSTARG 3 /* first argument is in reg 3 */ 8077957Sbenno#define NARGREG 8 /* 8 args are in registers */ 8177957Sbenno#define MOREARGS(sp) ((caddr_t)((int)(sp) + 8)) /* more args go here */ 8277957Sbenno 8396255Sbenno#ifndef MULTIPROCESSOR 8496255Sbennoextern int intr_depth; 8586067Smp#endif 8677957Sbenno 8796938Sbennovoid trap(struct trapframe *); 8896255Sbenno 8996938Sbennostatic void trap_fatal(struct trapframe *frame); 9096938Sbennostatic void printtrap(u_int vector, struct trapframe *frame, int isfatal, 9196938Sbenno int user); 9296938Sbennostatic int trap_pfault(struct trapframe *frame, int user); 9396938Sbennostatic int fix_unaligned(struct thread *td, struct trapframe *frame); 9496938Sbennostatic int handle_onfault(struct trapframe *frame); 9596938Sbennostatic void syscall(struct trapframe *frame); 9696938Sbenno 9796906Sbennostatic __inline void setusr(u_int); 9877957Sbenno 9996906Sbennoint setfault(faultbuf); /* defined in locore.S */ 10096906Sbenno 10196255Sbenno/* Why are these not defined in a header? */ 10296906Sbennoint badaddr(void *, size_t); 10396906Sbennoint badaddr_read(void *, size_t, int *); 10496906Sbennoint kcopy(const void *, void *, size_t); 10586067Smp 10696906Sbenno#ifdef WITNESS 10796499Sbennoextern char *syscallnames[]; 10896906Sbenno#endif 10996499Sbenno 11096938Sbennostruct powerpc_exception { 11196938Sbenno u_int vector; 11296938Sbenno char *name; 11396938Sbenno}; 11496938Sbenno 11596938Sbennostatic struct powerpc_exception powerpc_exceptions[] = { 11696938Sbenno { 0x0100, "system reset" }, 11796938Sbenno { 0x0200, "machine check" }, 11896938Sbenno { 0x0300, "data storage interrupt" }, 11996938Sbenno { 0x0400, "instruction storage interrupt" }, 12096938Sbenno { 0x0500, "external interrupt" }, 12196938Sbenno { 0x0600, "alignment" }, 12296938Sbenno { 0x0700, "program" }, 12396938Sbenno { 0x0800, "floating-point unavailable" }, 12496938Sbenno { 0x0900, "decrementer" }, 12596938Sbenno { 0x0c00, "system call" }, 12696938Sbenno { 0x0d00, "trace" }, 12796938Sbenno { 0x0e00, "floating-point assist" }, 12896938Sbenno { 0x0f00, "performance monitoring" }, 12996938Sbenno { 0x0f20, "altivec unavailable" }, 13096938Sbenno { 0x1000, "instruction tlb miss" }, 13196938Sbenno { 0x1100, "data load tlb miss" }, 13296938Sbenno { 0x1200, "data store tlb miss" }, 13396938Sbenno { 0x1300, "instruction breakpoint" }, 13496938Sbenno { 0x1400, "system management" }, 13596938Sbenno { 0x1600, "altivec assist" }, 13696938Sbenno { 0x1700, "thermal management" }, 13796938Sbenno { 0x2000, "run mode/trace" }, 13896938Sbenno { 0x3000, NULL } 13996938Sbenno}; 14096938Sbenno 14196938Sbennostatic const char * 14296938Sbennotrapname(u_int vector) 14396938Sbenno{ 14496938Sbenno struct powerpc_exception *pe; 14596938Sbenno 14696938Sbenno for (pe = powerpc_exceptions; pe->vector != 0x3000; pe++) { 14796938Sbenno if (pe->vector == vector) 14896938Sbenno return (pe->name); 14996938Sbenno } 15096938Sbenno 15196938Sbenno return ("unknown"); 15296938Sbenno} 15396938Sbenno 15496255Sbennovoid 15596906Sbennotrap(struct trapframe *frame) 15686067Smp{ 15796906Sbenno struct thread *td, *fputhread; 15896906Sbenno struct proc *p; 15996938Sbenno int sig, type, user; 16096938Sbenno u_int sticks, ucode; 16186067Smp 16296938Sbenno atomic_add_int(&cnt.v_trap, 1); 16396938Sbenno 16496906Sbenno td = PCPU_GET(curthread); 16596906Sbenno p = td->td_proc; 16686067Smp 16796938Sbenno type = ucode = frame->exc; 16896938Sbenno sig = 0; 16996938Sbenno user = frame->srr1 & PSL_PR; 17096938Sbenno sticks = 0; 17186067Smp 17296938Sbenno CTR3(KTR_TRAP, "trap: %s type=%s (%s)", p->p_comm, 17396938Sbenno trapname(type), user ? "user" : "kernel"); 17486067Smp 17596938Sbenno if (user) { 17696938Sbenno sticks = td->td_kse->ke_sticks; 17796938Sbenno td->td_frame = frame; 17896938Sbenno if (td->td_ucred != p->p_ucred) 17996938Sbenno cred_update_thread(td); 18086067Smp 18196938Sbenno /* User Mode Traps */ 18296938Sbenno switch (type) { 18396938Sbenno case EXC_RUNMODETRC: 18496938Sbenno case EXC_TRC: 18596938Sbenno frame->srr1 &= ~PSL_SE; 18696938Sbenno sig = SIGTRAP; 18796938Sbenno break; 18877957Sbenno 18996938Sbenno case EXC_DSI: 19096938Sbenno case EXC_ISI: 19196938Sbenno sig = trap_pfault(frame, 1); 19296938Sbenno break; 19396938Sbenno 19496938Sbenno case EXC_SC: 19596938Sbenno syscall(frame); 19696938Sbenno break; 19796938Sbenno 19896938Sbenno case EXC_FPU: 19996938Sbenno if ((fputhread = PCPU_GET(fputhread)) != NULL) { 20096938Sbenno KASSERT(fputhread != td, 20196938Sbenno ("floating-point already enabled")); 20296938Sbenno save_fpu(fputhread); 20396255Sbenno } 20496938Sbenno PCPU_SET(fputhread, td); 20596938Sbenno td->td_pcb->pcb_fpcpu = PCPU_GET(cpuid); 20696938Sbenno enable_fpu(td); 20796938Sbenno frame->srr1 |= PSL_FP; 20896938Sbenno break; 20996938Sbenno 21096938Sbenno#ifdef ALTIVEC 21196938Sbenno case EXC_VEC: 21296938Sbenno if ((vecthread = PCPU_GET(vecthread)) != NULL) { 21396938Sbenno KASSERT(vecthread != td, 21496938Sbenno ("altivec already enabled")); 21596938Sbenno save_vec(vecthread); 21696938Sbenno } 21796938Sbenno PCPU_SET(vecthread, td); 21896938Sbenno td->td_pcb->pcb_veccpu = PCPU_GET(cpuid); 21996938Sbenno enable_vec(td); 22096938Sbenno frame->srr1 |= PSL_VEC; 22196938Sbenno break; 22296938Sbenno#endif /* ALTIVEC */ 22396938Sbenno 22496938Sbenno case EXC_ALI: 22596938Sbenno if (fix_unaligned(td, frame) != 0) 22696938Sbenno sig = SIGBUS; 22777957Sbenno else 22896938Sbenno frame->srr0 += 4; 22996938Sbenno break; 23096938Sbenno 23196938Sbenno case EXC_PGM: 23296938Sbenno /* XXX temporarily */ 23396938Sbenno /* XXX: Magic Number? */ 23496938Sbenno if (frame->srr1 & 0x0002000) 23596938Sbenno sig = SIGTRAP; 23696938Sbenno else 23796938Sbenno sig = SIGILL; 23896938Sbenno break; 23996938Sbenno 24096938Sbenno default: 24196938Sbenno trap_fatal(frame); 24277957Sbenno } 24396938Sbenno } else { 24496938Sbenno /* Kernel Mode Traps */ 24596938Sbenno 24696938Sbenno KASSERT(cold || td->td_ucred != NULL, 24796938Sbenno ("kernel trap doesn't have ucred")); 24896938Sbenno switch (type) { 24996938Sbenno case EXC_DSI: 25096938Sbenno if (trap_pfault(frame, 0) == 0) 25196938Sbenno return; 25296938Sbenno break; 25396938Sbenno case EXC_MCHK: 25496938Sbenno if (handle_onfault(frame)) 25596938Sbenno return; 25696938Sbenno break; 25796938Sbenno default: 25896938Sbenno trap_fatal(frame); 25996255Sbenno } 26086067Smp } 26196938Sbenno 26296938Sbenno if (td != PCPU_GET(fputhread) || 26396938Sbenno td->td_pcb->pcb_fpcpu != PCPU_GET(cpuid)) 26496938Sbenno frame->srr1 &= ~PSL_FP; 26596938Sbenno 26696938Sbenno#ifdef ALTIVEC 26796938Sbenno if (td != PCPU_GET(vecthread) || 26896938Sbenno td->td_pcb->pcb_veccpu != PCPU_GET(cpuid)) 26996938Sbenno frame->srr1 &= ~PSL_VEC; 27096938Sbenno#endif /* ALTIVEC */ 27196938Sbenno 27296938Sbenno if (sig != 0) { 27396938Sbenno if (p->p_sysent->sv_transtrap != NULL) 27496938Sbenno sig = (p->p_sysent->sv_transtrap)(sig, type); 27596938Sbenno trapsignal(p, sig, ucode); 27696938Sbenno } 27796938Sbenno 27896938Sbenno userret(td, frame, sticks); 27996938Sbenno mtx_assert(&Giant, MA_NOTOWNED); 28096938Sbenno#ifdef DIAGNOSTIC 28196938Sbenno cred_free_thread(td); 28296938Sbenno#endif /* DIAGNOSTIC */ 28396938Sbenno} 28496938Sbenno 28596938Sbennostatic void 28696938Sbennotrap_fatal(struct trapframe *frame) 28796938Sbenno{ 28896938Sbenno 28996938Sbenno printtrap(frame->exc, frame, 1, (frame->srr1 & PSL_PR)); 29096938Sbenno#ifdef DDB 29196938Sbenno if ((debugger_on_panic || db_active) && kdb_trap(frame->exc, 0, frame)) 29296938Sbenno return; 29396938Sbenno#endif 29496938Sbenno panic("%s trap", trapname(frame->exc)); 29596938Sbenno} 29696938Sbenno 29796938Sbennostatic void 29896938Sbennoprinttrap(u_int vector, struct trapframe *frame, int isfatal, int user) 29996938Sbenno{ 30096938Sbenno 30196938Sbenno printf("\n"); 30296938Sbenno printf("%s %s trap:\n", isfatal ? "fatal" : "handled", 30396938Sbenno user ? "user" : "kernel"); 30496938Sbenno printf("\n"); 30596938Sbenno printf(" exception = 0x%x (%s)\n", vector >> 8, 30696938Sbenno trapname(vector)); 30796938Sbenno switch (vector) { 30896938Sbenno case EXC_DSI: 30996938Sbenno printf(" virtual address = 0x%x\n", frame->dar); 31096255Sbenno break; 31196255Sbenno case EXC_ISI: 31296938Sbenno printf(" virtual address = 0x%x\n", frame->srr0); 31396255Sbenno break; 31496938Sbenno } 31597347Sbenno printf(" srr0 = 0x%x\n", frame->srr0); 31697347Sbenno printf(" srr1 = 0x%x\n", frame->srr1); 31796938Sbenno printf(" curthread = %p\n", curthread); 31896938Sbenno if (curthread != NULL) 31996938Sbenno printf(" pid = %d, comm = %s\n", 32096938Sbenno curthread->td_proc->p_pid, curthread->td_proc->p_comm); 32196938Sbenno printf("\n"); 32296938Sbenno} 32386067Smp 32496938Sbenno/* 32596938Sbenno * Handles a fatal fault when we have onfault state to recover. Returns 32696938Sbenno * non-zero if there was onfault recovery state available. 32796938Sbenno */ 32896938Sbennostatic int 32996938Sbennohandle_onfault(struct trapframe *frame) 33096938Sbenno{ 33196938Sbenno struct thread *td; 33296938Sbenno faultbuf *fb; 33386067Smp 33496938Sbenno td = curthread; 33596938Sbenno fb = td->td_pcb->pcb_onfault; 33696938Sbenno if (fb != NULL) { 33796938Sbenno frame->srr0 = (*fb)[0]; 33896938Sbenno frame->fixreg[1] = (*fb)[1]; 33996938Sbenno frame->fixreg[2] = (*fb)[2]; 34096938Sbenno frame->cr = (*fb)[3]; 34196938Sbenno bcopy(&(*fb)[4], &frame->fixreg[13], 34296938Sbenno 19 * sizeof(register_t)); 34396938Sbenno return (1); 34496938Sbenno } 34596938Sbenno return (0); 34696938Sbenno} 34786067Smp 34896938Sbennovoid 34996938Sbennosyscall(struct trapframe *frame) 35096938Sbenno{ 35196938Sbenno caddr_t params; 35296938Sbenno struct sysent *callp; 35396938Sbenno struct thread *td; 35496938Sbenno struct proc *p; 35596938Sbenno int error, n; 35696938Sbenno size_t narg; 35796938Sbenno register_t args[10]; 35896938Sbenno u_int code; 35986067Smp 36096938Sbenno td = PCPU_GET(curthread); 36196938Sbenno p = td->td_proc; 36286067Smp 36396938Sbenno atomic_add_int(&cnt.v_syscall, 1); 36496938Sbenno 36596938Sbenno code = frame->fixreg[0]; 36696938Sbenno params = (caddr_t)(frame->fixreg + FIRSTARG); 36796938Sbenno n = NARGREG; 36896938Sbenno 36996938Sbenno if (p->p_sysent->sv_prepsyscall) { 37096938Sbenno /* 37196938Sbenno * The prep code is MP aware. 37296938Sbenno */ 37396938Sbenno (*p->p_sysent->sv_prepsyscall)(frame, args, &code, ¶ms); 37496938Sbenno } else if (code == SYS_syscall) { 37596938Sbenno /* 37696938Sbenno * code is first argument, 37796938Sbenno * followed by actual args. 37896938Sbenno */ 37996938Sbenno code = *params++; 38096938Sbenno n -= 1; 38196938Sbenno } else if (code == SYS___syscall) { 38296938Sbenno /* 38396938Sbenno * Like syscall, but code is a quad, 38496938Sbenno * so as to maintain quad alignment 38596938Sbenno * for the rest of the args. 38696938Sbenno */ 38796938Sbenno params++; 38896938Sbenno code = *params++; 38996938Sbenno n -= 2; 39096938Sbenno } 39196452Sbenno 39296938Sbenno if (p->p_sysent->sv_mask) 39396938Sbenno code &= p->p_sysent->sv_mask; 39486067Smp 39596938Sbenno if (code >= p->p_sysent->sv_size) 39696938Sbenno callp = &p->p_sysent->sv_table[0]; 39796938Sbenno else 39896938Sbenno callp = &p->p_sysent->sv_table[code]; 39986067Smp 40096938Sbenno narg = callp->sy_narg & SYF_ARGMASK; 40196255Sbenno 40296938Sbenno if (narg > n * sizeof(register_t)) { 40396938Sbenno bcopy(params, args, n * sizeof(register_t)); 40496938Sbenno error = copyin(MOREARGS(frame->fixreg[1]), args + n, 40596938Sbenno narg - n * sizeof(register_t)); 40696938Sbenno if (error) { 40777957Sbenno#ifdef KTRACE 40896938Sbenno /* Can't get all the arguments! */ 40996938Sbenno if (KTRPOINT(p, KTR_SYSCALL)) 41096938Sbenno ktrsyscall(p->p_tracep, code, narg, args); 41177957Sbenno#endif 41296938Sbenno goto bad; 41396255Sbenno } 41496938Sbenno params = (caddr_t)args; 41596938Sbenno } 41677957Sbenno 41796938Sbenno /* 41896938Sbenno * Try to run the syscall without Giant if the syscall is MP safe. 41996938Sbenno */ 42096938Sbenno if ((callp->sy_narg & SYF_MPSAFE) == 0) 42196938Sbenno mtx_lock(&Giant); 42277957Sbenno 42396938Sbenno#ifdef KTRACE 42496938Sbenno if (KTRPOINT(p, KTR_SYSCALL)) 42596938Sbenno ktrsyscall(p->p_tracep, code, narg, params); 42696255Sbenno#endif 42796938Sbenno td->td_retval[0] = 0; 42896938Sbenno td->td_retval[1] = frame->fixreg[FIRSTARG + 1]; 42996255Sbenno 43096938Sbenno STOPEVENT(p, S_SCE, narg); 43177957Sbenno 43296938Sbenno error = (*callp->sy_call)(td, params); 43396938Sbenno switch (error) { 43496938Sbenno case 0: 43596938Sbenno frame->fixreg[FIRSTARG] = td->td_retval[0]; 43696938Sbenno frame->fixreg[FIRSTARG + 1] = td->td_retval[1]; 43796938Sbenno /* XXX: Magic number */ 43896938Sbenno frame->cr &= ~0x10000000; 43996255Sbenno break; 44096938Sbenno case ERESTART: 44196938Sbenno /* 44296938Sbenno * Set user's pc back to redo the system call. 44396938Sbenno */ 44496938Sbenno frame->srr0 -= 4; 44596255Sbenno break; 44696938Sbenno case EJUSTRETURN: 44796938Sbenno /* nothing to do */ 44896938Sbenno break; 44996938Sbenno default: 45096938Sbennobad: 45196938Sbenno if (p->p_sysent->sv_errsize) { 45296938Sbenno if (error >= p->p_sysent->sv_errsize) 45396938Sbenno error = -1; /* XXX */ 45496938Sbenno else 45596938Sbenno error = p->p_sysent->sv_errtbl[error]; 45696255Sbenno } 45796938Sbenno frame->fixreg[FIRSTARG] = error; 45896938Sbenno /* XXX: Magic number: Carry Flag Equivalent? */ 45996938Sbenno frame->cr |= 0x10000000; 46096938Sbenno break; 46177957Sbenno } 46277957Sbenno 46396938Sbenno 46496938Sbenno#ifdef KTRACE 46596938Sbenno if (KTRPOINT(p, KTR_SYSRET)) 46696938Sbenno ktrsysret(p->p_tracep, code, error, td->td_retval[0]); 46796255Sbenno#endif 46886067Smp 46996938Sbenno if ((callp->sy_narg & SYF_MPSAFE) == 0) 47096938Sbenno mtx_unlock(&Giant); 47186067Smp 47296255Sbenno /* 47396938Sbenno * Does the comment in the i386 code about errno apply here? 47496255Sbenno */ 47596938Sbenno STOPEVENT(p, S_SCX, code); 47686067Smp 47796938Sbenno#ifdef WITNESS 47896938Sbenno if (witness_list(td)) { 47996938Sbenno panic("system call %s returning with mutex(s) held\n", 48096938Sbenno syscallnames[code]); 48196938Sbenno } 48296255Sbenno#endif 48396938Sbenno mtx_assert(&sched_lock, MA_NOTOWNED); 48496938Sbenno mtx_assert(&Giant, MA_NOTOWNED); 48577957Sbenno} 48677957Sbenno 48796938Sbennostatic int 48896938Sbennotrap_pfault(struct trapframe *frame, int user) 48977957Sbenno{ 49096938Sbenno vm_offset_t eva, va; 49196938Sbenno struct thread *td; 49296938Sbenno struct proc *p; 49396938Sbenno vm_map_t map; 49496938Sbenno vm_prot_t ftype; 49596938Sbenno int rv; 49696938Sbenno u_int user_sr; 49777957Sbenno 49896938Sbenno td = curthread; 49996906Sbenno p = td->td_proc; 50096938Sbenno if (frame->exc == EXC_ISI) { 50196938Sbenno eva = frame->srr0; 50296938Sbenno ftype = VM_PROT_READ | VM_PROT_EXECUTE; 50396938Sbenno } else { 50496938Sbenno eva = frame->dar; 50596938Sbenno if (frame->dsisr & DSISR_STORE) 50696938Sbenno ftype = VM_PROT_READ | VM_PROT_WRITE; 50796938Sbenno else 50896938Sbenno ftype = VM_PROT_READ; 50996938Sbenno } 51096906Sbenno 51196938Sbenno if (user) { 51296938Sbenno map = &p->p_vmspace->vm_map; 51396938Sbenno } else { 51496938Sbenno if ((eva >> ADDR_SR_SHFT) == USER_SR) { 51596938Sbenno if (p->p_vmspace == NULL) 51696938Sbenno return (SIGSEGV); 51796938Sbenno 51896938Sbenno __asm ("mfsr %0, %1" 51996938Sbenno : "=r"(user_sr) 52096938Sbenno : "K"(USER_SR)); 52196938Sbenno eva &= ADDR_PIDX | ADDR_POFF; 52296938Sbenno eva |= user_sr << ADDR_SR_SHFT; 52396938Sbenno map = &p->p_vmspace->vm_map; 52496938Sbenno } else { 52596938Sbenno map = kernel_map; 52696938Sbenno } 52796938Sbenno } 52896938Sbenno va = trunc_page(eva); 52977957Sbenno 53096938Sbenno mtx_lock(&Giant); 53196938Sbenno if (map != kernel_map) { 53296938Sbenno /* 53396938Sbenno * Keep swapout from messing with us during this 53496938Sbenno * critical time. 53596938Sbenno */ 53696255Sbenno PROC_LOCK(p); 53796938Sbenno ++p->p_lock; 53896255Sbenno PROC_UNLOCK(p); 53996938Sbenno 54096938Sbenno /* Fault in the user page: */ 54196938Sbenno rv = vm_fault(map, va, ftype, 54296938Sbenno (ftype & VM_PROT_WRITE) ? VM_FAULT_DIRTY 54396938Sbenno : VM_FAULT_NORMAL); 54496938Sbenno 54596938Sbenno PROC_LOCK(p); 54696938Sbenno --p->p_lock; 54796938Sbenno PROC_UNLOCK(p); 54896938Sbenno } else { 54996938Sbenno /* 55096938Sbenno * Don't have to worry about process locking or stacks in the 55196938Sbenno * kernel. 55296938Sbenno */ 55396938Sbenno rv = vm_fault(map, va, ftype, VM_FAULT_NORMAL); 55496255Sbenno } 55596938Sbenno mtx_unlock(&Giant); 55696938Sbenno 55796938Sbenno if (rv == KERN_SUCCESS) 55896938Sbenno return (0); 55996938Sbenno 56096938Sbenno if (!user && handle_onfault(frame)) 56196938Sbenno return (0); 56296938Sbenno 56396938Sbenno return (SIGSEGV); 56477957Sbenno} 56577957Sbenno 56696255Sbennostatic __inline void 56796906Sbennosetusr(u_int content) 56896255Sbenno{ 56996255Sbenno __asm __volatile ("isync; mtsr %0,%1; isync" 57096255Sbenno :: "n"(USER_SR), "r"(content)); 57196255Sbenno} 57296255Sbenno 57377957Sbenno/* 57477957Sbenno * kcopy(const void *src, void *dst, size_t len); 57577957Sbenno * 57677957Sbenno * Copy len bytes from src to dst, aborting if we encounter a fatal 57777957Sbenno * page fault. 57877957Sbenno * 57977957Sbenno * kcopy() _must_ save and restore the old fault handler since it is 58077957Sbenno * called by uiomove(), which may be in the path of servicing a non-fatal 58177957Sbenno * page fault. 58277957Sbenno */ 58377957Sbennoint 58477957Sbennokcopy(const void *src, void *dst, size_t len) 58577957Sbenno{ 58696906Sbenno struct thread *td; 58796906Sbenno faultbuf env, *oldfault; 58896906Sbenno int rv; 58977957Sbenno 59096255Sbenno td = PCPU_GET(curthread); 59196255Sbenno oldfault = td->td_pcb->pcb_onfault; 59296255Sbenno if ((rv = setfault(env)) != 0) { 59396255Sbenno td->td_pcb->pcb_onfault = oldfault; 59496255Sbenno return rv; 59577957Sbenno } 59677957Sbenno 59796255Sbenno memcpy(dst, src, len); 59877957Sbenno 59996255Sbenno td->td_pcb->pcb_onfault = oldfault; 60096906Sbenno return (0); 60177957Sbenno} 60277957Sbenno 60377957Sbennoint 60496906Sbennobadaddr(void *addr, size_t size) 60577957Sbenno{ 60696906Sbenno return (badaddr_read(addr, size, NULL)); 60777957Sbenno} 60877957Sbenno 60977957Sbennoint 61096906Sbennobadaddr_read(void *addr, size_t size, int *rptr) 61177957Sbenno{ 61296906Sbenno struct thread *td; 61396906Sbenno faultbuf env; 61496906Sbenno int x; 61577957Sbenno 61677957Sbenno /* Get rid of any stale machine checks that have been waiting. */ 61777957Sbenno __asm __volatile ("sync; isync"); 61877957Sbenno 61996255Sbenno td = PCPU_GET(curthread); 62096255Sbenno 62177957Sbenno if (setfault(env)) { 62296255Sbenno td->td_pcb->pcb_onfault = 0; 62377957Sbenno __asm __volatile ("sync"); 62477957Sbenno return 1; 62577957Sbenno } 62677957Sbenno 62777957Sbenno __asm __volatile ("sync"); 62877957Sbenno 62977957Sbenno switch (size) { 63077957Sbenno case 1: 63177957Sbenno x = *(volatile int8_t *)addr; 63277957Sbenno break; 63377957Sbenno case 2: 63477957Sbenno x = *(volatile int16_t *)addr; 63577957Sbenno break; 63677957Sbenno case 4: 63777957Sbenno x = *(volatile int32_t *)addr; 63877957Sbenno break; 63977957Sbenno default: 64077957Sbenno panic("badaddr: invalid size (%d)", size); 64177957Sbenno } 64277957Sbenno 64377957Sbenno /* Make sure we took the machine check, if we caused one. */ 64477957Sbenno __asm __volatile ("sync; isync"); 64577957Sbenno 64696255Sbenno td->td_pcb->pcb_onfault = 0; 64777957Sbenno __asm __volatile ("sync"); /* To be sure. */ 64877957Sbenno 64977957Sbenno /* Use the value to avoid reorder. */ 65077957Sbenno if (rptr) 65177957Sbenno *rptr = x; 65277957Sbenno 65396906Sbenno return (0); 65477957Sbenno} 65577957Sbenno 65677957Sbenno/* 65777957Sbenno * For now, this only deals with the particular unaligned access case 65877957Sbenno * that gcc tends to generate. Eventually it should handle all of the 65977957Sbenno * possibilities that can happen on a 32-bit PowerPC in big-endian mode. 66077957Sbenno */ 66177957Sbenno 66277957Sbennostatic int 66396906Sbennofix_unaligned(struct thread *td, struct trapframe *frame) 66477957Sbenno{ 66596906Sbenno struct thread *fputhread; 66696906Sbenno int indicator, reg; 66796906Sbenno double *fpr; 66877957Sbenno 66996906Sbenno indicator = EXC_ALI_OPCODE_INDICATOR(frame->dsisr); 67096906Sbenno 67177957Sbenno switch (indicator) { 67277957Sbenno case EXC_ALI_LFD: 67377957Sbenno case EXC_ALI_STFD: 67496906Sbenno reg = EXC_ALI_RST(frame->dsisr); 67596906Sbenno fpr = &td->td_pcb->pcb_fpu.fpr[reg]; 67696906Sbenno fputhread = PCPU_GET(fputhread); 67777957Sbenno 67896906Sbenno /* Juggle the FPU to ensure that we've initialized 67996906Sbenno * the FPRs, and that their current state is in 68096906Sbenno * the PCB. 68196906Sbenno */ 68296906Sbenno if (fputhread != td) { 68396906Sbenno if (fputhread) 68496906Sbenno save_fpu(fputhread); 68596906Sbenno enable_fpu(td); 68696906Sbenno } 68796906Sbenno save_fpu(td); 68877957Sbenno 68996906Sbenno if (indicator == EXC_ALI_LFD) { 69096906Sbenno if (copyin((void *)frame->dar, fpr, 69196906Sbenno sizeof(double)) != 0) 69296906Sbenno return -1; 69396906Sbenno enable_fpu(td); 69496906Sbenno } else { 69596906Sbenno if (copyout(fpr, (void *)frame->dar, 69696906Sbenno sizeof(double)) != 0) 69796906Sbenno return -1; 69877957Sbenno } 69996906Sbenno return 0; 70077957Sbenno break; 70177957Sbenno } 70277957Sbenno 70377957Sbenno return -1; 70477957Sbenno} 705