trap.c revision 173600
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: head/sys/powerpc/aim/trap.c 173600 2007-11-14 06:21:24Z julian $"); 3677957Sbenno 3777957Sbenno#include "opt_ktrace.h" 3877957Sbenno 3977957Sbenno#include <sys/param.h> 40132074Sgrehan#include <sys/kdb.h> 4196938Sbenno#include <sys/proc.h> 4296938Sbenno#include <sys/ktr.h> 4386067Smp#include <sys/lock.h> 4486067Smp#include <sys/mutex.h> 4596938Sbenno#include <sys/pioctl.h> 46160764Sjhb#include <sys/ptrace.h> 4777957Sbenno#include <sys/reboot.h> 4877957Sbenno#include <sys/syscall.h> 4996938Sbenno#include <sys/sysent.h> 5096255Sbenno#include <sys/systm.h> 5196906Sbenno#include <sys/uio.h> 52143633Sgrehan#include <sys/signalvar.h> 5386067Smp#ifdef KTRACE 5477957Sbenno#include <sys/ktrace.h> 5586067Smp#endif 5696938Sbenno#include <sys/vmmeter.h> 5777957Sbenno 58162361Srwatson#include <security/audit/audit.h> 59162361Srwatson 6077957Sbenno#include <vm/vm.h> 6186067Smp#include <vm/pmap.h> 6286067Smp#include <vm/vm_extern.h> 6396255Sbenno#include <vm/vm_param.h> 6477957Sbenno#include <vm/vm_kern.h> 6586067Smp#include <vm/vm_map.h> 6696255Sbenno#include <vm/vm_page.h> 6777957Sbenno 6877957Sbenno#include <machine/cpu.h> 6996255Sbenno#include <machine/db_machdep.h> 7096255Sbenno#include <machine/fpu.h> 7177957Sbenno#include <machine/frame.h> 7277957Sbenno#include <machine/pcb.h> 7396255Sbenno#include <machine/pmap.h> 7477957Sbenno#include <machine/psl.h> 7577957Sbenno#include <machine/trap.h> 7696255Sbenno#include <machine/spr.h> 7796255Sbenno#include <machine/sr.h> 7877957Sbenno 7996938Sbennostatic void trap_fatal(struct trapframe *frame); 8096938Sbennostatic void printtrap(u_int vector, struct trapframe *frame, int isfatal, 8196938Sbenno int user); 8296938Sbennostatic int trap_pfault(struct trapframe *frame, int user); 8396938Sbennostatic int fix_unaligned(struct thread *td, struct trapframe *frame); 8496938Sbennostatic int handle_onfault(struct trapframe *frame); 8596938Sbennostatic void syscall(struct trapframe *frame); 8696938Sbenno 8796906Sbennostatic __inline void setusr(u_int); 8877957Sbenno 8996906Sbennoint setfault(faultbuf); /* defined in locore.S */ 9096906Sbenno 9196255Sbenno/* Why are these not defined in a header? */ 9296906Sbennoint badaddr(void *, size_t); 9396906Sbennoint badaddr_read(void *, size_t, int *); 9486067Smp 9596499Sbennoextern char *syscallnames[]; 9696499Sbenno 9796938Sbennostruct powerpc_exception { 9896938Sbenno u_int vector; 9996938Sbenno char *name; 10096938Sbenno}; 10196938Sbenno 10296938Sbennostatic struct powerpc_exception powerpc_exceptions[] = { 10396938Sbenno { 0x0100, "system reset" }, 10496938Sbenno { 0x0200, "machine check" }, 10596938Sbenno { 0x0300, "data storage interrupt" }, 10696938Sbenno { 0x0400, "instruction storage interrupt" }, 10796938Sbenno { 0x0500, "external interrupt" }, 10896938Sbenno { 0x0600, "alignment" }, 10996938Sbenno { 0x0700, "program" }, 11096938Sbenno { 0x0800, "floating-point unavailable" }, 11196938Sbenno { 0x0900, "decrementer" }, 11296938Sbenno { 0x0c00, "system call" }, 11396938Sbenno { 0x0d00, "trace" }, 11496938Sbenno { 0x0e00, "floating-point assist" }, 11596938Sbenno { 0x0f00, "performance monitoring" }, 11696938Sbenno { 0x0f20, "altivec unavailable" }, 11796938Sbenno { 0x1000, "instruction tlb miss" }, 11896938Sbenno { 0x1100, "data load tlb miss" }, 11996938Sbenno { 0x1200, "data store tlb miss" }, 12096938Sbenno { 0x1300, "instruction breakpoint" }, 121131698Sgrehan { 0x1400, "system management" }, 12296938Sbenno { 0x1600, "altivec assist" }, 12396938Sbenno { 0x1700, "thermal management" }, 12496938Sbenno { 0x2000, "run mode/trace" }, 12596938Sbenno { 0x3000, NULL } 12696938Sbenno}; 12796938Sbenno 12896938Sbennostatic const char * 12996938Sbennotrapname(u_int vector) 13096938Sbenno{ 13196938Sbenno struct powerpc_exception *pe; 13296938Sbenno 13396938Sbenno for (pe = powerpc_exceptions; pe->vector != 0x3000; pe++) { 13496938Sbenno if (pe->vector == vector) 13596938Sbenno return (pe->name); 13696938Sbenno } 13796938Sbenno 13896938Sbenno return ("unknown"); 13996938Sbenno} 14096938Sbenno 14196255Sbennovoid 14296906Sbennotrap(struct trapframe *frame) 14386067Smp{ 144112429Sgrehan struct thread *td; 14596906Sbenno struct proc *p; 14696938Sbenno int sig, type, user; 147155455Sphk u_int ucode; 148151316Sdavidxu ksiginfo_t ksi; 14986067Smp 150170291Sattilio PCPU_INC(cnt.v_trap); 15196938Sbenno 15296906Sbenno td = PCPU_GET(curthread); 15396906Sbenno p = td->td_proc; 15486067Smp 15596938Sbenno type = ucode = frame->exc; 15696938Sbenno sig = 0; 15796938Sbenno user = frame->srr1 & PSL_PR; 15886067Smp 15996938Sbenno CTR3(KTR_TRAP, "trap: %s type=%s (%s)", p->p_comm, 16096938Sbenno trapname(type), user ? "user" : "kernel"); 16186067Smp 16296938Sbenno if (user) { 163155455Sphk td->td_pticks = 0; 16496938Sbenno td->td_frame = frame; 16596938Sbenno if (td->td_ucred != p->p_ucred) 16696938Sbenno cred_update_thread(td); 16786067Smp 16896938Sbenno /* User Mode Traps */ 16996938Sbenno switch (type) { 17096938Sbenno case EXC_RUNMODETRC: 17196938Sbenno case EXC_TRC: 17296938Sbenno frame->srr1 &= ~PSL_SE; 17396938Sbenno sig = SIGTRAP; 17496938Sbenno break; 17577957Sbenno 17696938Sbenno case EXC_DSI: 17796938Sbenno case EXC_ISI: 17896938Sbenno sig = trap_pfault(frame, 1); 17996938Sbenno break; 18096938Sbenno 18196938Sbenno case EXC_SC: 18296938Sbenno syscall(frame); 18396938Sbenno break; 18496938Sbenno 18596938Sbenno case EXC_FPU: 186112429Sgrehan KASSERT((td->td_pcb->pcb_flags & PCB_FPU) != PCB_FPU, 187112429Sgrehan ("FPU already enabled for thread")); 18896938Sbenno enable_fpu(td); 18996938Sbenno break; 19096938Sbenno 19196938Sbenno#ifdef ALTIVEC 19296938Sbenno case EXC_VEC: 19396938Sbenno if ((vecthread = PCPU_GET(vecthread)) != NULL) { 19496938Sbenno KASSERT(vecthread != td, 19596938Sbenno ("altivec already enabled")); 19696938Sbenno save_vec(vecthread); 19796938Sbenno } 19896938Sbenno PCPU_SET(vecthread, td); 19996938Sbenno td->td_pcb->pcb_veccpu = PCPU_GET(cpuid); 20096938Sbenno enable_vec(td); 20196938Sbenno frame->srr1 |= PSL_VEC; 20296938Sbenno break; 203148568Sgrehan#else 204148568Sgrehan case EXC_VEC: 205148568Sgrehan case EXC_VECAST: 206148568Sgrehan sig = SIGILL; 207148568Sgrehan break; 20896938Sbenno#endif /* ALTIVEC */ 20996938Sbenno 21096938Sbenno case EXC_ALI: 21196938Sbenno if (fix_unaligned(td, frame) != 0) 21296938Sbenno sig = SIGBUS; 21377957Sbenno else 21496938Sbenno frame->srr0 += 4; 21596938Sbenno break; 21696938Sbenno 21796938Sbenno case EXC_PGM: 21896938Sbenno /* XXX temporarily */ 21996938Sbenno /* XXX: Magic Number? */ 22096938Sbenno if (frame->srr1 & 0x0002000) 22196938Sbenno sig = SIGTRAP; 22296938Sbenno else 22396938Sbenno sig = SIGILL; 22496938Sbenno break; 22596938Sbenno 22696938Sbenno default: 22796938Sbenno trap_fatal(frame); 22877957Sbenno } 22996938Sbenno } else { 23096938Sbenno /* Kernel Mode Traps */ 23196938Sbenno 23296938Sbenno KASSERT(cold || td->td_ucred != NULL, 23396938Sbenno ("kernel trap doesn't have ucred")); 23496938Sbenno switch (type) { 23596938Sbenno case EXC_DSI: 23696938Sbenno if (trap_pfault(frame, 0) == 0) 23796938Sbenno return; 23896938Sbenno break; 23996938Sbenno case EXC_MCHK: 24096938Sbenno if (handle_onfault(frame)) 24196938Sbenno return; 24296938Sbenno break; 24396938Sbenno default: 244132994Sgrehan break; 24596255Sbenno } 246132994Sgrehan trap_fatal(frame); 24786067Smp } 24896938Sbenno 24996938Sbenno#ifdef ALTIVEC 25096938Sbenno if (td != PCPU_GET(vecthread) || 25196938Sbenno td->td_pcb->pcb_veccpu != PCPU_GET(cpuid)) 25296938Sbenno frame->srr1 &= ~PSL_VEC; 25396938Sbenno#endif /* ALTIVEC */ 25496938Sbenno 25596938Sbenno if (sig != 0) { 25696938Sbenno if (p->p_sysent->sv_transtrap != NULL) 25796938Sbenno sig = (p->p_sysent->sv_transtrap)(sig, type); 258151316Sdavidxu ksiginfo_init_trap(&ksi); 259151316Sdavidxu ksi.ksi_signo = sig; 260151316Sdavidxu ksi.ksi_code = (int) ucode; /* XXX, not POSIX */ 261151316Sdavidxu /* ksi.ksi_addr = ? */ 262151316Sdavidxu ksi.ksi_trapno = type; 263151316Sdavidxu trapsignal(td, &ksi); 26496938Sbenno } 26596938Sbenno 266155455Sphk userret(td, frame); 26796938Sbenno mtx_assert(&Giant, MA_NOTOWNED); 26896938Sbenno} 26996938Sbenno 27096938Sbennostatic void 27196938Sbennotrap_fatal(struct trapframe *frame) 27296938Sbenno{ 27396938Sbenno 27496938Sbenno printtrap(frame->exc, frame, 1, (frame->srr1 & PSL_PR)); 275132074Sgrehan#ifdef KDB 276132074Sgrehan if ((debugger_on_panic || kdb_active) && 277132074Sgrehan kdb_trap(frame->exc, 0, frame)) 27896938Sbenno return; 27996938Sbenno#endif 28096938Sbenno panic("%s trap", trapname(frame->exc)); 28196938Sbenno} 28296938Sbenno 28396938Sbennostatic void 28496938Sbennoprinttrap(u_int vector, struct trapframe *frame, int isfatal, int user) 28596938Sbenno{ 28696938Sbenno 28796938Sbenno printf("\n"); 28896938Sbenno printf("%s %s trap:\n", isfatal ? "fatal" : "handled", 28996938Sbenno user ? "user" : "kernel"); 29096938Sbenno printf("\n"); 29196938Sbenno printf(" exception = 0x%x (%s)\n", vector >> 8, 29296938Sbenno trapname(vector)); 29396938Sbenno switch (vector) { 29496938Sbenno case EXC_DSI: 29596938Sbenno printf(" virtual address = 0x%x\n", frame->dar); 29696255Sbenno break; 29796255Sbenno case EXC_ISI: 29896938Sbenno printf(" virtual address = 0x%x\n", frame->srr0); 29996255Sbenno break; 30096938Sbenno } 30197347Sbenno printf(" srr0 = 0x%x\n", frame->srr0); 30297347Sbenno printf(" srr1 = 0x%x\n", frame->srr1); 30396938Sbenno printf(" curthread = %p\n", curthread); 30496938Sbenno if (curthread != NULL) 30596938Sbenno printf(" pid = %d, comm = %s\n", 306173600Sjulian curthread->td_proc->p_pid, curthread->td_name); 30796938Sbenno printf("\n"); 30896938Sbenno} 30986067Smp 31096938Sbenno/* 31196938Sbenno * Handles a fatal fault when we have onfault state to recover. Returns 31296938Sbenno * non-zero if there was onfault recovery state available. 31396938Sbenno */ 31496938Sbennostatic int 31596938Sbennohandle_onfault(struct trapframe *frame) 31696938Sbenno{ 31796938Sbenno struct thread *td; 31896938Sbenno faultbuf *fb; 31986067Smp 32096938Sbenno td = curthread; 32196938Sbenno fb = td->td_pcb->pcb_onfault; 32296938Sbenno if (fb != NULL) { 32396938Sbenno frame->srr0 = (*fb)[0]; 32496938Sbenno frame->fixreg[1] = (*fb)[1]; 32596938Sbenno frame->fixreg[2] = (*fb)[2]; 326131867Sgrehan frame->fixreg[3] = 1; 32796938Sbenno frame->cr = (*fb)[3]; 32896938Sbenno bcopy(&(*fb)[4], &frame->fixreg[13], 32996938Sbenno 19 * sizeof(register_t)); 33096938Sbenno return (1); 33196938Sbenno } 33296938Sbenno return (0); 33396938Sbenno} 33486067Smp 33596938Sbennovoid 33696938Sbennosyscall(struct trapframe *frame) 33796938Sbenno{ 33896938Sbenno caddr_t params; 33996938Sbenno struct sysent *callp; 34096938Sbenno struct thread *td; 34196938Sbenno struct proc *p; 34296938Sbenno int error, n; 34396938Sbenno size_t narg; 34496938Sbenno register_t args[10]; 34596938Sbenno u_int code; 34686067Smp 34796938Sbenno td = PCPU_GET(curthread); 34896938Sbenno p = td->td_proc; 34986067Smp 350170291Sattilio PCPU_INC(cnt.v_syscall); 351131698Sgrehan 352163709Sjb#ifdef KSE 353131698Sgrehan if (p->p_flag & P_SA) 354134571Sjulian thread_user_enter(td); 355163709Sjb#endif 356131698Sgrehan 35796938Sbenno code = frame->fixreg[0]; 35896938Sbenno params = (caddr_t)(frame->fixreg + FIRSTARG); 35996938Sbenno n = NARGREG; 360131698Sgrehan 36196938Sbenno if (p->p_sysent->sv_prepsyscall) { 36296938Sbenno /* 36396938Sbenno * The prep code is MP aware. 36496938Sbenno */ 36596938Sbenno (*p->p_sysent->sv_prepsyscall)(frame, args, &code, ¶ms); 36696938Sbenno } else if (code == SYS_syscall) { 36796938Sbenno /* 36896938Sbenno * code is first argument, 36996938Sbenno * followed by actual args. 37096938Sbenno */ 371103607Sgrehan code = *(u_int *) params; 372103607Sgrehan params += sizeof(register_t); 37396938Sbenno n -= 1; 37496938Sbenno } else if (code == SYS___syscall) { 37596938Sbenno /* 37696938Sbenno * Like syscall, but code is a quad, 37796938Sbenno * so as to maintain quad alignment 37896938Sbenno * for the rest of the args. 37996938Sbenno */ 380103607Sgrehan params += sizeof(register_t); 381103607Sgrehan code = *(u_int *) params; 382103607Sgrehan params += sizeof(register_t); 38396938Sbenno n -= 2; 38496938Sbenno } 38596452Sbenno 38696938Sbenno if (p->p_sysent->sv_mask) 38796938Sbenno code &= p->p_sysent->sv_mask; 38886067Smp 38996938Sbenno if (code >= p->p_sysent->sv_size) 39096938Sbenno callp = &p->p_sysent->sv_table[0]; 39196938Sbenno else 39296938Sbenno callp = &p->p_sysent->sv_table[code]; 39386067Smp 394160801Sjhb narg = callp->sy_narg; 39596255Sbenno 396103607Sgrehan if (narg > n) { 39796938Sbenno bcopy(params, args, n * sizeof(register_t)); 39896938Sbenno error = copyin(MOREARGS(frame->fixreg[1]), args + n, 399103607Sgrehan (narg - n) * sizeof(register_t)); 40098001Sjhb params = (caddr_t)args; 40198001Sjhb } else 40298001Sjhb error = 0; 40398001Sjhb 404131867Sgrehan CTR5(KTR_SYSC, "syscall: p=%s %s(%x %x %x)", p->p_comm, 405131867Sgrehan syscallnames[code], 406131867Sgrehan frame->fixreg[FIRSTARG], 407131867Sgrehan frame->fixreg[FIRSTARG+1], 408131867Sgrehan frame->fixreg[FIRSTARG+2]); 409131867Sgrehan 41077957Sbenno#ifdef KTRACE 41198001Sjhb if (KTRPOINT(td, KTR_SYSCALL)) 412103607Sgrehan ktrsyscall(code, narg, (register_t *)params); 41377957Sbenno#endif 41477957Sbenno 415167352Smohans td->td_syscalls++; 416167352Smohans 41798001Sjhb if (error == 0) { 41898001Sjhb td->td_retval[0] = 0; 41998001Sjhb td->td_retval[1] = frame->fixreg[FIRSTARG + 1]; 42096255Sbenno 42198001Sjhb STOPEVENT(p, S_SCE, narg); 42277957Sbenno 423160764Sjhb PTRACESTOP_SC(p, td, S_PT_SCE); 424160764Sjhb 425162361Srwatson AUDIT_SYSCALL_ENTER(code, td); 42698001Sjhb error = (*callp->sy_call)(td, params); 427162361Srwatson AUDIT_SYSCALL_EXIT(error, td); 428131867Sgrehan 429131867Sgrehan CTR3(KTR_SYSC, "syscall: p=%s %s ret=%x", p->p_comm, 430131867Sgrehan syscallnames[code], td->td_retval[0]); 43198001Sjhb } 43296938Sbenno switch (error) { 43396938Sbenno case 0: 434171670Smarcel if (frame->fixreg[0] == SYS___syscall && 435171670Smarcel code != SYS_freebsd6_lseek && code != SYS_lseek) { 436103607Sgrehan /* 437103607Sgrehan * 64-bit return, 32-bit syscall. Fixup byte order 438103607Sgrehan */ 439103607Sgrehan frame->fixreg[FIRSTARG] = 0; 440103607Sgrehan frame->fixreg[FIRSTARG + 1] = td->td_retval[0]; 441103607Sgrehan } else { 442103607Sgrehan frame->fixreg[FIRSTARG] = td->td_retval[0]; 443103607Sgrehan frame->fixreg[FIRSTARG + 1] = td->td_retval[1]; 444103607Sgrehan } 44596938Sbenno /* XXX: Magic number */ 44696938Sbenno frame->cr &= ~0x10000000; 44796255Sbenno break; 44896938Sbenno case ERESTART: 44996938Sbenno /* 45096938Sbenno * Set user's pc back to redo the system call. 45196938Sbenno */ 45296938Sbenno frame->srr0 -= 4; 45396255Sbenno break; 45496938Sbenno case EJUSTRETURN: 45596938Sbenno /* nothing to do */ 45696938Sbenno break; 45796938Sbenno default: 45896938Sbenno if (p->p_sysent->sv_errsize) { 45996938Sbenno if (error >= p->p_sysent->sv_errsize) 46096938Sbenno error = -1; /* XXX */ 46196938Sbenno else 46296938Sbenno error = p->p_sysent->sv_errtbl[error]; 46396255Sbenno } 46496938Sbenno frame->fixreg[FIRSTARG] = error; 46596938Sbenno /* XXX: Magic number: Carry Flag Equivalent? */ 46696938Sbenno frame->cr |= 0x10000000; 46796938Sbenno break; 46877957Sbenno } 46977957Sbenno 470160773Sjhb /* 471160773Sjhb * Check for misbehavior. 472160773Sjhb */ 473160773Sjhb WITNESS_WARN(WARN_PANIC, NULL, "System call %s returning", 474160773Sjhb (code >= 0 && code < SYS_MAXSYSCALL) ? syscallnames[code] : "???"); 475160773Sjhb KASSERT(td->td_critnest == 0, 476160773Sjhb ("System call %s returning in a critical section", 477160773Sjhb (code >= 0 && code < SYS_MAXSYSCALL) ? syscallnames[code] : "???")); 478160773Sjhb KASSERT(td->td_locks == 0, 479160773Sjhb ("System call %s returning with %d locks held", 480160773Sjhb (code >= 0 && code < SYS_MAXSYSCALL) ? syscallnames[code] : "???", 481160773Sjhb td->td_locks)); 482160773Sjhb 48396938Sbenno#ifdef KTRACE 48498001Sjhb if (KTRPOINT(td, KTR_SYSRET)) 48598001Sjhb ktrsysret(code, error, td->td_retval[0]); 48696255Sbenno#endif 48786067Smp 48896255Sbenno /* 48996938Sbenno * Does the comment in the i386 code about errno apply here? 49096255Sbenno */ 49196938Sbenno STOPEVENT(p, S_SCX, code); 492160764Sjhb 493160764Sjhb PTRACESTOP_SC(p, td, S_PT_SCX); 49477957Sbenno} 49577957Sbenno 49696938Sbennostatic int 49796938Sbennotrap_pfault(struct trapframe *frame, int user) 49877957Sbenno{ 49996938Sbenno vm_offset_t eva, va; 50096938Sbenno struct thread *td; 50196938Sbenno struct proc *p; 50296938Sbenno vm_map_t map; 50396938Sbenno vm_prot_t ftype; 50496938Sbenno int rv; 50596938Sbenno u_int user_sr; 50677957Sbenno 50796938Sbenno td = curthread; 50896906Sbenno p = td->td_proc; 50996938Sbenno if (frame->exc == EXC_ISI) { 51096938Sbenno eva = frame->srr0; 51196938Sbenno ftype = VM_PROT_READ | VM_PROT_EXECUTE; 51296938Sbenno } else { 51396938Sbenno eva = frame->dar; 51496938Sbenno if (frame->dsisr & DSISR_STORE) 515103607Sgrehan ftype = VM_PROT_WRITE; 51696938Sbenno else 51796938Sbenno ftype = VM_PROT_READ; 51896938Sbenno } 51996906Sbenno 52096938Sbenno if (user) { 52196938Sbenno map = &p->p_vmspace->vm_map; 52296938Sbenno } else { 52396938Sbenno if ((eva >> ADDR_SR_SHFT) == USER_SR) { 52496938Sbenno if (p->p_vmspace == NULL) 52596938Sbenno return (SIGSEGV); 526131698Sgrehan 52796938Sbenno __asm ("mfsr %0, %1" 52896938Sbenno : "=r"(user_sr) 52996938Sbenno : "K"(USER_SR)); 53096938Sbenno eva &= ADDR_PIDX | ADDR_POFF; 53196938Sbenno eva |= user_sr << ADDR_SR_SHFT; 53296938Sbenno map = &p->p_vmspace->vm_map; 53396938Sbenno } else { 53496938Sbenno map = kernel_map; 53596938Sbenno } 53696938Sbenno } 53796938Sbenno va = trunc_page(eva); 53877957Sbenno 53996938Sbenno if (map != kernel_map) { 54096938Sbenno /* 54196938Sbenno * Keep swapout from messing with us during this 54296938Sbenno * critical time. 54396938Sbenno */ 54496255Sbenno PROC_LOCK(p); 54596938Sbenno ++p->p_lock; 54696255Sbenno PROC_UNLOCK(p); 54796938Sbenno 54896938Sbenno /* Fault in the user page: */ 54996938Sbenno rv = vm_fault(map, va, ftype, 55096938Sbenno (ftype & VM_PROT_WRITE) ? VM_FAULT_DIRTY 55196938Sbenno : VM_FAULT_NORMAL); 55296938Sbenno 55396938Sbenno PROC_LOCK(p); 55496938Sbenno --p->p_lock; 55596938Sbenno PROC_UNLOCK(p); 55696938Sbenno } else { 55796938Sbenno /* 55896938Sbenno * Don't have to worry about process locking or stacks in the 55996938Sbenno * kernel. 56096938Sbenno */ 56196938Sbenno rv = vm_fault(map, va, ftype, VM_FAULT_NORMAL); 56296255Sbenno } 56396938Sbenno 56496938Sbenno if (rv == KERN_SUCCESS) 56596938Sbenno return (0); 56696938Sbenno 56796938Sbenno if (!user && handle_onfault(frame)) 56896938Sbenno return (0); 56996938Sbenno 57096938Sbenno return (SIGSEGV); 57177957Sbenno} 57277957Sbenno 57396255Sbennostatic __inline void 57496906Sbennosetusr(u_int content) 57596255Sbenno{ 57696255Sbenno __asm __volatile ("isync; mtsr %0,%1; isync" 57796255Sbenno :: "n"(USER_SR), "r"(content)); 57896255Sbenno} 57996255Sbenno 58077957Sbennoint 58196906Sbennobadaddr(void *addr, size_t size) 58277957Sbenno{ 58396906Sbenno return (badaddr_read(addr, size, NULL)); 58477957Sbenno} 58577957Sbenno 58677957Sbennoint 58796906Sbennobadaddr_read(void *addr, size_t size, int *rptr) 58877957Sbenno{ 58996906Sbenno struct thread *td; 59096906Sbenno faultbuf env; 59196906Sbenno int x; 59277957Sbenno 59377957Sbenno /* Get rid of any stale machine checks that have been waiting. */ 59477957Sbenno __asm __volatile ("sync; isync"); 59577957Sbenno 59696255Sbenno td = PCPU_GET(curthread); 59796255Sbenno 59877957Sbenno if (setfault(env)) { 59996255Sbenno td->td_pcb->pcb_onfault = 0; 60077957Sbenno __asm __volatile ("sync"); 60177957Sbenno return 1; 60277957Sbenno } 60377957Sbenno 60477957Sbenno __asm __volatile ("sync"); 60577957Sbenno 60677957Sbenno switch (size) { 60777957Sbenno case 1: 60877957Sbenno x = *(volatile int8_t *)addr; 60977957Sbenno break; 61077957Sbenno case 2: 61177957Sbenno x = *(volatile int16_t *)addr; 61277957Sbenno break; 61377957Sbenno case 4: 61477957Sbenno x = *(volatile int32_t *)addr; 61577957Sbenno break; 61677957Sbenno default: 61777957Sbenno panic("badaddr: invalid size (%d)", size); 61877957Sbenno } 61977957Sbenno 62077957Sbenno /* Make sure we took the machine check, if we caused one. */ 62177957Sbenno __asm __volatile ("sync; isync"); 62277957Sbenno 62396255Sbenno td->td_pcb->pcb_onfault = 0; 62477957Sbenno __asm __volatile ("sync"); /* To be sure. */ 62577957Sbenno 62677957Sbenno /* Use the value to avoid reorder. */ 62777957Sbenno if (rptr) 62877957Sbenno *rptr = x; 62977957Sbenno 63096906Sbenno return (0); 63177957Sbenno} 63277957Sbenno 63377957Sbenno/* 63477957Sbenno * For now, this only deals with the particular unaligned access case 63577957Sbenno * that gcc tends to generate. Eventually it should handle all of the 63677957Sbenno * possibilities that can happen on a 32-bit PowerPC in big-endian mode. 63777957Sbenno */ 63877957Sbenno 63977957Sbennostatic int 64096906Sbennofix_unaligned(struct thread *td, struct trapframe *frame) 64177957Sbenno{ 64296906Sbenno struct thread *fputhread; 64396906Sbenno int indicator, reg; 64496906Sbenno double *fpr; 64577957Sbenno 64696906Sbenno indicator = EXC_ALI_OPCODE_INDICATOR(frame->dsisr); 64796906Sbenno 64877957Sbenno switch (indicator) { 64977957Sbenno case EXC_ALI_LFD: 65077957Sbenno case EXC_ALI_STFD: 65196906Sbenno reg = EXC_ALI_RST(frame->dsisr); 65296906Sbenno fpr = &td->td_pcb->pcb_fpu.fpr[reg]; 65396906Sbenno fputhread = PCPU_GET(fputhread); 65477957Sbenno 65596906Sbenno /* Juggle the FPU to ensure that we've initialized 65696906Sbenno * the FPRs, and that their current state is in 65796906Sbenno * the PCB. 65896906Sbenno */ 65996906Sbenno if (fputhread != td) { 66096906Sbenno if (fputhread) 66196906Sbenno save_fpu(fputhread); 66296906Sbenno enable_fpu(td); 66396906Sbenno } 66496906Sbenno save_fpu(td); 66577957Sbenno 66696906Sbenno if (indicator == EXC_ALI_LFD) { 66796906Sbenno if (copyin((void *)frame->dar, fpr, 66896906Sbenno sizeof(double)) != 0) 66996906Sbenno return -1; 67096906Sbenno enable_fpu(td); 67196906Sbenno } else { 67296906Sbenno if (copyout(fpr, (void *)frame->dar, 67396906Sbenno sizeof(double)) != 0) 67496906Sbenno return -1; 67577957Sbenno } 67696906Sbenno return 0; 67777957Sbenno break; 67877957Sbenno } 67977957Sbenno 68077957Sbenno return -1; 68177957Sbenno} 682