trap.c revision 167352
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 167352 2007-03-09 04:02:38Z mohans $"); 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 7996938Sbennovoid trap(struct trapframe *); 8096255Sbenno 8196938Sbennostatic void trap_fatal(struct trapframe *frame); 8296938Sbennostatic void printtrap(u_int vector, struct trapframe *frame, int isfatal, 8396938Sbenno int user); 8496938Sbennostatic int trap_pfault(struct trapframe *frame, int user); 8596938Sbennostatic int fix_unaligned(struct thread *td, struct trapframe *frame); 8696938Sbennostatic int handle_onfault(struct trapframe *frame); 8796938Sbennostatic void syscall(struct trapframe *frame); 8896938Sbenno 8996906Sbennostatic __inline void setusr(u_int); 9077957Sbenno 9196906Sbennoint setfault(faultbuf); /* defined in locore.S */ 9296906Sbenno 9396255Sbenno/* Why are these not defined in a header? */ 9496906Sbennoint badaddr(void *, size_t); 9596906Sbennoint badaddr_read(void *, size_t, int *); 9686067Smp 9796499Sbennoextern char *syscallnames[]; 9896499Sbenno 9996938Sbennostruct powerpc_exception { 10096938Sbenno u_int vector; 10196938Sbenno char *name; 10296938Sbenno}; 10396938Sbenno 10496938Sbennostatic struct powerpc_exception powerpc_exceptions[] = { 10596938Sbenno { 0x0100, "system reset" }, 10696938Sbenno { 0x0200, "machine check" }, 10796938Sbenno { 0x0300, "data storage interrupt" }, 10896938Sbenno { 0x0400, "instruction storage interrupt" }, 10996938Sbenno { 0x0500, "external interrupt" }, 11096938Sbenno { 0x0600, "alignment" }, 11196938Sbenno { 0x0700, "program" }, 11296938Sbenno { 0x0800, "floating-point unavailable" }, 11396938Sbenno { 0x0900, "decrementer" }, 11496938Sbenno { 0x0c00, "system call" }, 11596938Sbenno { 0x0d00, "trace" }, 11696938Sbenno { 0x0e00, "floating-point assist" }, 11796938Sbenno { 0x0f00, "performance monitoring" }, 11896938Sbenno { 0x0f20, "altivec unavailable" }, 11996938Sbenno { 0x1000, "instruction tlb miss" }, 12096938Sbenno { 0x1100, "data load tlb miss" }, 12196938Sbenno { 0x1200, "data store tlb miss" }, 12296938Sbenno { 0x1300, "instruction breakpoint" }, 123131698Sgrehan { 0x1400, "system management" }, 12496938Sbenno { 0x1600, "altivec assist" }, 12596938Sbenno { 0x1700, "thermal management" }, 12696938Sbenno { 0x2000, "run mode/trace" }, 12796938Sbenno { 0x3000, NULL } 12896938Sbenno}; 12996938Sbenno 13096938Sbennostatic const char * 13196938Sbennotrapname(u_int vector) 13296938Sbenno{ 13396938Sbenno struct powerpc_exception *pe; 13496938Sbenno 13596938Sbenno for (pe = powerpc_exceptions; pe->vector != 0x3000; pe++) { 13696938Sbenno if (pe->vector == vector) 13796938Sbenno return (pe->name); 13896938Sbenno } 13996938Sbenno 14096938Sbenno return ("unknown"); 14196938Sbenno} 14296938Sbenno 14396255Sbennovoid 14496906Sbennotrap(struct trapframe *frame) 14586067Smp{ 146112429Sgrehan struct thread *td; 14796906Sbenno struct proc *p; 14896938Sbenno int sig, type, user; 149155455Sphk u_int ucode; 150151316Sdavidxu ksiginfo_t ksi; 15186067Smp 152144971Sjhb PCPU_LAZY_INC(cnt.v_trap); 15396938Sbenno 15496906Sbenno td = PCPU_GET(curthread); 15596906Sbenno p = td->td_proc; 15686067Smp 15796938Sbenno type = ucode = frame->exc; 15896938Sbenno sig = 0; 15996938Sbenno user = frame->srr1 & PSL_PR; 16086067Smp 16196938Sbenno CTR3(KTR_TRAP, "trap: %s type=%s (%s)", p->p_comm, 16296938Sbenno trapname(type), user ? "user" : "kernel"); 16386067Smp 16496938Sbenno if (user) { 165155455Sphk td->td_pticks = 0; 16696938Sbenno td->td_frame = frame; 16796938Sbenno if (td->td_ucred != p->p_ucred) 16896938Sbenno cred_update_thread(td); 16986067Smp 17096938Sbenno /* User Mode Traps */ 17196938Sbenno switch (type) { 17296938Sbenno case EXC_RUNMODETRC: 17396938Sbenno case EXC_TRC: 17496938Sbenno frame->srr1 &= ~PSL_SE; 17596938Sbenno sig = SIGTRAP; 17696938Sbenno break; 17777957Sbenno 17896938Sbenno case EXC_DSI: 17996938Sbenno case EXC_ISI: 18096938Sbenno sig = trap_pfault(frame, 1); 18196938Sbenno break; 18296938Sbenno 18396938Sbenno case EXC_SC: 18496938Sbenno syscall(frame); 18596938Sbenno break; 18696938Sbenno 18796938Sbenno case EXC_FPU: 188112429Sgrehan KASSERT((td->td_pcb->pcb_flags & PCB_FPU) != PCB_FPU, 189112429Sgrehan ("FPU already enabled for thread")); 19096938Sbenno enable_fpu(td); 19196938Sbenno break; 19296938Sbenno 19396938Sbenno#ifdef ALTIVEC 19496938Sbenno case EXC_VEC: 19596938Sbenno if ((vecthread = PCPU_GET(vecthread)) != NULL) { 19696938Sbenno KASSERT(vecthread != td, 19796938Sbenno ("altivec already enabled")); 19896938Sbenno save_vec(vecthread); 19996938Sbenno } 20096938Sbenno PCPU_SET(vecthread, td); 20196938Sbenno td->td_pcb->pcb_veccpu = PCPU_GET(cpuid); 20296938Sbenno enable_vec(td); 20396938Sbenno frame->srr1 |= PSL_VEC; 20496938Sbenno break; 205148568Sgrehan#else 206148568Sgrehan case EXC_VEC: 207148568Sgrehan case EXC_VECAST: 208148568Sgrehan sig = SIGILL; 209148568Sgrehan break; 21096938Sbenno#endif /* ALTIVEC */ 21196938Sbenno 21296938Sbenno case EXC_ALI: 21396938Sbenno if (fix_unaligned(td, frame) != 0) 21496938Sbenno sig = SIGBUS; 21577957Sbenno else 21696938Sbenno frame->srr0 += 4; 21796938Sbenno break; 21896938Sbenno 21996938Sbenno case EXC_PGM: 22096938Sbenno /* XXX temporarily */ 22196938Sbenno /* XXX: Magic Number? */ 22296938Sbenno if (frame->srr1 & 0x0002000) 22396938Sbenno sig = SIGTRAP; 22496938Sbenno else 22596938Sbenno sig = SIGILL; 22696938Sbenno break; 22796938Sbenno 22896938Sbenno default: 22996938Sbenno trap_fatal(frame); 23077957Sbenno } 23196938Sbenno } else { 23296938Sbenno /* Kernel Mode Traps */ 23396938Sbenno 23496938Sbenno KASSERT(cold || td->td_ucred != NULL, 23596938Sbenno ("kernel trap doesn't have ucred")); 23696938Sbenno switch (type) { 23796938Sbenno case EXC_DSI: 23896938Sbenno if (trap_pfault(frame, 0) == 0) 23996938Sbenno return; 24096938Sbenno break; 24196938Sbenno case EXC_MCHK: 24296938Sbenno if (handle_onfault(frame)) 24396938Sbenno return; 24496938Sbenno break; 24596938Sbenno default: 246132994Sgrehan break; 24796255Sbenno } 248132994Sgrehan trap_fatal(frame); 24986067Smp } 25096938Sbenno 25196938Sbenno#ifdef ALTIVEC 25296938Sbenno if (td != PCPU_GET(vecthread) || 25396938Sbenno td->td_pcb->pcb_veccpu != PCPU_GET(cpuid)) 25496938Sbenno frame->srr1 &= ~PSL_VEC; 25596938Sbenno#endif /* ALTIVEC */ 25696938Sbenno 25796938Sbenno if (sig != 0) { 25896938Sbenno if (p->p_sysent->sv_transtrap != NULL) 25996938Sbenno sig = (p->p_sysent->sv_transtrap)(sig, type); 260151316Sdavidxu ksiginfo_init_trap(&ksi); 261151316Sdavidxu ksi.ksi_signo = sig; 262151316Sdavidxu ksi.ksi_code = (int) ucode; /* XXX, not POSIX */ 263151316Sdavidxu /* ksi.ksi_addr = ? */ 264151316Sdavidxu ksi.ksi_trapno = type; 265151316Sdavidxu trapsignal(td, &ksi); 26696938Sbenno } 26796938Sbenno 268155455Sphk userret(td, frame); 26996938Sbenno mtx_assert(&Giant, MA_NOTOWNED); 27096938Sbenno} 27196938Sbenno 27296938Sbennostatic void 27396938Sbennotrap_fatal(struct trapframe *frame) 27496938Sbenno{ 27596938Sbenno 27696938Sbenno printtrap(frame->exc, frame, 1, (frame->srr1 & PSL_PR)); 277132074Sgrehan#ifdef KDB 278132074Sgrehan if ((debugger_on_panic || kdb_active) && 279132074Sgrehan kdb_trap(frame->exc, 0, frame)) 28096938Sbenno return; 28196938Sbenno#endif 28296938Sbenno panic("%s trap", trapname(frame->exc)); 28396938Sbenno} 28496938Sbenno 28596938Sbennostatic void 28696938Sbennoprinttrap(u_int vector, struct trapframe *frame, int isfatal, int user) 28796938Sbenno{ 28896938Sbenno 28996938Sbenno printf("\n"); 29096938Sbenno printf("%s %s trap:\n", isfatal ? "fatal" : "handled", 29196938Sbenno user ? "user" : "kernel"); 29296938Sbenno printf("\n"); 29396938Sbenno printf(" exception = 0x%x (%s)\n", vector >> 8, 29496938Sbenno trapname(vector)); 29596938Sbenno switch (vector) { 29696938Sbenno case EXC_DSI: 29796938Sbenno printf(" virtual address = 0x%x\n", frame->dar); 29896255Sbenno break; 29996255Sbenno case EXC_ISI: 30096938Sbenno printf(" virtual address = 0x%x\n", frame->srr0); 30196255Sbenno break; 30296938Sbenno } 30397347Sbenno printf(" srr0 = 0x%x\n", frame->srr0); 30497347Sbenno printf(" srr1 = 0x%x\n", frame->srr1); 30596938Sbenno printf(" curthread = %p\n", curthread); 30696938Sbenno if (curthread != NULL) 30796938Sbenno printf(" pid = %d, comm = %s\n", 30896938Sbenno curthread->td_proc->p_pid, curthread->td_proc->p_comm); 30996938Sbenno printf("\n"); 31096938Sbenno} 31186067Smp 31296938Sbenno/* 31396938Sbenno * Handles a fatal fault when we have onfault state to recover. Returns 31496938Sbenno * non-zero if there was onfault recovery state available. 31596938Sbenno */ 31696938Sbennostatic int 31796938Sbennohandle_onfault(struct trapframe *frame) 31896938Sbenno{ 31996938Sbenno struct thread *td; 32096938Sbenno faultbuf *fb; 32186067Smp 32296938Sbenno td = curthread; 32396938Sbenno fb = td->td_pcb->pcb_onfault; 32496938Sbenno if (fb != NULL) { 32596938Sbenno frame->srr0 = (*fb)[0]; 32696938Sbenno frame->fixreg[1] = (*fb)[1]; 32796938Sbenno frame->fixreg[2] = (*fb)[2]; 328131867Sgrehan frame->fixreg[3] = 1; 32996938Sbenno frame->cr = (*fb)[3]; 33096938Sbenno bcopy(&(*fb)[4], &frame->fixreg[13], 33196938Sbenno 19 * sizeof(register_t)); 33296938Sbenno return (1); 33396938Sbenno } 33496938Sbenno return (0); 33596938Sbenno} 33686067Smp 33796938Sbennovoid 33896938Sbennosyscall(struct trapframe *frame) 33996938Sbenno{ 34096938Sbenno caddr_t params; 34196938Sbenno struct sysent *callp; 34296938Sbenno struct thread *td; 34396938Sbenno struct proc *p; 34496938Sbenno int error, n; 34596938Sbenno size_t narg; 34696938Sbenno register_t args[10]; 34796938Sbenno u_int code; 34886067Smp 34996938Sbenno td = PCPU_GET(curthread); 35096938Sbenno p = td->td_proc; 35186067Smp 352144971Sjhb PCPU_LAZY_INC(cnt.v_syscall); 353131698Sgrehan 354163709Sjb#ifdef KSE 355131698Sgrehan if (p->p_flag & P_SA) 356134571Sjulian thread_user_enter(td); 357163709Sjb#endif 358131698Sgrehan 35996938Sbenno code = frame->fixreg[0]; 36096938Sbenno params = (caddr_t)(frame->fixreg + FIRSTARG); 36196938Sbenno n = NARGREG; 362131698Sgrehan 36396938Sbenno if (p->p_sysent->sv_prepsyscall) { 36496938Sbenno /* 36596938Sbenno * The prep code is MP aware. 36696938Sbenno */ 36796938Sbenno (*p->p_sysent->sv_prepsyscall)(frame, args, &code, ¶ms); 36896938Sbenno } else if (code == SYS_syscall) { 36996938Sbenno /* 37096938Sbenno * code is first argument, 37196938Sbenno * followed by actual args. 37296938Sbenno */ 373103607Sgrehan code = *(u_int *) params; 374103607Sgrehan params += sizeof(register_t); 37596938Sbenno n -= 1; 37696938Sbenno } else if (code == SYS___syscall) { 37796938Sbenno /* 37896938Sbenno * Like syscall, but code is a quad, 37996938Sbenno * so as to maintain quad alignment 38096938Sbenno * for the rest of the args. 38196938Sbenno */ 382103607Sgrehan params += sizeof(register_t); 383103607Sgrehan code = *(u_int *) params; 384103607Sgrehan params += sizeof(register_t); 38596938Sbenno n -= 2; 38696938Sbenno } 38796452Sbenno 38896938Sbenno if (p->p_sysent->sv_mask) 38996938Sbenno code &= p->p_sysent->sv_mask; 39086067Smp 39196938Sbenno if (code >= p->p_sysent->sv_size) 39296938Sbenno callp = &p->p_sysent->sv_table[0]; 39396938Sbenno else 39496938Sbenno callp = &p->p_sysent->sv_table[code]; 39586067Smp 396160801Sjhb narg = callp->sy_narg; 39796255Sbenno 398103607Sgrehan if (narg > n) { 39996938Sbenno bcopy(params, args, n * sizeof(register_t)); 40096938Sbenno error = copyin(MOREARGS(frame->fixreg[1]), args + n, 401103607Sgrehan (narg - n) * sizeof(register_t)); 40298001Sjhb params = (caddr_t)args; 40398001Sjhb } else 40498001Sjhb error = 0; 40598001Sjhb 406131867Sgrehan CTR5(KTR_SYSC, "syscall: p=%s %s(%x %x %x)", p->p_comm, 407131867Sgrehan syscallnames[code], 408131867Sgrehan frame->fixreg[FIRSTARG], 409131867Sgrehan frame->fixreg[FIRSTARG+1], 410131867Sgrehan frame->fixreg[FIRSTARG+2]); 411131867Sgrehan 41277957Sbenno#ifdef KTRACE 41398001Sjhb if (KTRPOINT(td, KTR_SYSCALL)) 414103607Sgrehan ktrsyscall(code, narg, (register_t *)params); 41577957Sbenno#endif 41677957Sbenno 417167352Smohans td->td_syscalls++; 418167352Smohans 41998001Sjhb if (error == 0) { 42098001Sjhb td->td_retval[0] = 0; 42198001Sjhb td->td_retval[1] = frame->fixreg[FIRSTARG + 1]; 42296255Sbenno 42398001Sjhb STOPEVENT(p, S_SCE, narg); 42477957Sbenno 425160764Sjhb PTRACESTOP_SC(p, td, S_PT_SCE); 426160764Sjhb 427162361Srwatson AUDIT_SYSCALL_ENTER(code, td); 42898001Sjhb error = (*callp->sy_call)(td, params); 429162361Srwatson AUDIT_SYSCALL_EXIT(error, td); 430131867Sgrehan 431131867Sgrehan CTR3(KTR_SYSC, "syscall: p=%s %s ret=%x", p->p_comm, 432131867Sgrehan syscallnames[code], td->td_retval[0]); 43398001Sjhb } 43496938Sbenno switch (error) { 43596938Sbenno case 0: 436131698Sgrehan if ((frame->fixreg[0] == SYS___syscall) && 437103607Sgrehan (code != SYS_lseek)) { 438103607Sgrehan /* 439103607Sgrehan * 64-bit return, 32-bit syscall. Fixup byte order 440103607Sgrehan */ 441103607Sgrehan frame->fixreg[FIRSTARG] = 0; 442103607Sgrehan frame->fixreg[FIRSTARG + 1] = td->td_retval[0]; 443103607Sgrehan } else { 444103607Sgrehan frame->fixreg[FIRSTARG] = td->td_retval[0]; 445103607Sgrehan frame->fixreg[FIRSTARG + 1] = td->td_retval[1]; 446103607Sgrehan } 44796938Sbenno /* XXX: Magic number */ 44896938Sbenno frame->cr &= ~0x10000000; 44996255Sbenno break; 45096938Sbenno case ERESTART: 45196938Sbenno /* 45296938Sbenno * Set user's pc back to redo the system call. 45396938Sbenno */ 45496938Sbenno frame->srr0 -= 4; 45596255Sbenno break; 45696938Sbenno case EJUSTRETURN: 45796938Sbenno /* nothing to do */ 45896938Sbenno break; 45996938Sbenno default: 46096938Sbenno if (p->p_sysent->sv_errsize) { 46196938Sbenno if (error >= p->p_sysent->sv_errsize) 46296938Sbenno error = -1; /* XXX */ 46396938Sbenno else 46496938Sbenno error = p->p_sysent->sv_errtbl[error]; 46596255Sbenno } 46696938Sbenno frame->fixreg[FIRSTARG] = error; 46796938Sbenno /* XXX: Magic number: Carry Flag Equivalent? */ 46896938Sbenno frame->cr |= 0x10000000; 46996938Sbenno break; 47077957Sbenno } 47177957Sbenno 472160773Sjhb /* 473160773Sjhb * Check for misbehavior. 474160773Sjhb */ 475160773Sjhb WITNESS_WARN(WARN_PANIC, NULL, "System call %s returning", 476160773Sjhb (code >= 0 && code < SYS_MAXSYSCALL) ? syscallnames[code] : "???"); 477160773Sjhb KASSERT(td->td_critnest == 0, 478160773Sjhb ("System call %s returning in a critical section", 479160773Sjhb (code >= 0 && code < SYS_MAXSYSCALL) ? syscallnames[code] : "???")); 480160773Sjhb KASSERT(td->td_locks == 0, 481160773Sjhb ("System call %s returning with %d locks held", 482160773Sjhb (code >= 0 && code < SYS_MAXSYSCALL) ? syscallnames[code] : "???", 483160773Sjhb td->td_locks)); 484160773Sjhb 48596938Sbenno#ifdef KTRACE 48698001Sjhb if (KTRPOINT(td, KTR_SYSRET)) 48798001Sjhb ktrsysret(code, error, td->td_retval[0]); 48896255Sbenno#endif 48986067Smp 49096255Sbenno /* 49196938Sbenno * Does the comment in the i386 code about errno apply here? 49296255Sbenno */ 49396938Sbenno STOPEVENT(p, S_SCX, code); 494160764Sjhb 495160764Sjhb PTRACESTOP_SC(p, td, S_PT_SCX); 49677957Sbenno} 49777957Sbenno 49896938Sbennostatic int 49996938Sbennotrap_pfault(struct trapframe *frame, int user) 50077957Sbenno{ 50196938Sbenno vm_offset_t eva, va; 50296938Sbenno struct thread *td; 50396938Sbenno struct proc *p; 50496938Sbenno vm_map_t map; 50596938Sbenno vm_prot_t ftype; 50696938Sbenno int rv; 50796938Sbenno u_int user_sr; 50877957Sbenno 50996938Sbenno td = curthread; 51096906Sbenno p = td->td_proc; 51196938Sbenno if (frame->exc == EXC_ISI) { 51296938Sbenno eva = frame->srr0; 51396938Sbenno ftype = VM_PROT_READ | VM_PROT_EXECUTE; 51496938Sbenno } else { 51596938Sbenno eva = frame->dar; 51696938Sbenno if (frame->dsisr & DSISR_STORE) 517103607Sgrehan ftype = VM_PROT_WRITE; 51896938Sbenno else 51996938Sbenno ftype = VM_PROT_READ; 52096938Sbenno } 52196906Sbenno 52296938Sbenno if (user) { 52396938Sbenno map = &p->p_vmspace->vm_map; 52496938Sbenno } else { 52596938Sbenno if ((eva >> ADDR_SR_SHFT) == USER_SR) { 52696938Sbenno if (p->p_vmspace == NULL) 52796938Sbenno return (SIGSEGV); 528131698Sgrehan 52996938Sbenno __asm ("mfsr %0, %1" 53096938Sbenno : "=r"(user_sr) 53196938Sbenno : "K"(USER_SR)); 53296938Sbenno eva &= ADDR_PIDX | ADDR_POFF; 53396938Sbenno eva |= user_sr << ADDR_SR_SHFT; 53496938Sbenno map = &p->p_vmspace->vm_map; 53596938Sbenno } else { 53696938Sbenno map = kernel_map; 53796938Sbenno } 53896938Sbenno } 53996938Sbenno va = trunc_page(eva); 54077957Sbenno 54196938Sbenno if (map != kernel_map) { 54296938Sbenno /* 54396938Sbenno * Keep swapout from messing with us during this 54496938Sbenno * critical time. 54596938Sbenno */ 54696255Sbenno PROC_LOCK(p); 54796938Sbenno ++p->p_lock; 54896255Sbenno PROC_UNLOCK(p); 54996938Sbenno 55096938Sbenno /* Fault in the user page: */ 55196938Sbenno rv = vm_fault(map, va, ftype, 55296938Sbenno (ftype & VM_PROT_WRITE) ? VM_FAULT_DIRTY 55396938Sbenno : VM_FAULT_NORMAL); 55496938Sbenno 55596938Sbenno PROC_LOCK(p); 55696938Sbenno --p->p_lock; 55796938Sbenno PROC_UNLOCK(p); 55896938Sbenno } else { 55996938Sbenno /* 56096938Sbenno * Don't have to worry about process locking or stacks in the 56196938Sbenno * kernel. 56296938Sbenno */ 56396938Sbenno rv = vm_fault(map, va, ftype, VM_FAULT_NORMAL); 56496255Sbenno } 56596938Sbenno 56696938Sbenno if (rv == KERN_SUCCESS) 56796938Sbenno return (0); 56896938Sbenno 56996938Sbenno if (!user && handle_onfault(frame)) 57096938Sbenno return (0); 57196938Sbenno 57296938Sbenno return (SIGSEGV); 57377957Sbenno} 57477957Sbenno 57596255Sbennostatic __inline void 57696906Sbennosetusr(u_int content) 57796255Sbenno{ 57896255Sbenno __asm __volatile ("isync; mtsr %0,%1; isync" 57996255Sbenno :: "n"(USER_SR), "r"(content)); 58096255Sbenno} 58196255Sbenno 58277957Sbennoint 58396906Sbennobadaddr(void *addr, size_t size) 58477957Sbenno{ 58596906Sbenno return (badaddr_read(addr, size, NULL)); 58677957Sbenno} 58777957Sbenno 58877957Sbennoint 58996906Sbennobadaddr_read(void *addr, size_t size, int *rptr) 59077957Sbenno{ 59196906Sbenno struct thread *td; 59296906Sbenno faultbuf env; 59396906Sbenno int x; 59477957Sbenno 59577957Sbenno /* Get rid of any stale machine checks that have been waiting. */ 59677957Sbenno __asm __volatile ("sync; isync"); 59777957Sbenno 59896255Sbenno td = PCPU_GET(curthread); 59996255Sbenno 60077957Sbenno if (setfault(env)) { 60196255Sbenno td->td_pcb->pcb_onfault = 0; 60277957Sbenno __asm __volatile ("sync"); 60377957Sbenno return 1; 60477957Sbenno } 60577957Sbenno 60677957Sbenno __asm __volatile ("sync"); 60777957Sbenno 60877957Sbenno switch (size) { 60977957Sbenno case 1: 61077957Sbenno x = *(volatile int8_t *)addr; 61177957Sbenno break; 61277957Sbenno case 2: 61377957Sbenno x = *(volatile int16_t *)addr; 61477957Sbenno break; 61577957Sbenno case 4: 61677957Sbenno x = *(volatile int32_t *)addr; 61777957Sbenno break; 61877957Sbenno default: 61977957Sbenno panic("badaddr: invalid size (%d)", size); 62077957Sbenno } 62177957Sbenno 62277957Sbenno /* Make sure we took the machine check, if we caused one. */ 62377957Sbenno __asm __volatile ("sync; isync"); 62477957Sbenno 62596255Sbenno td->td_pcb->pcb_onfault = 0; 62677957Sbenno __asm __volatile ("sync"); /* To be sure. */ 62777957Sbenno 62877957Sbenno /* Use the value to avoid reorder. */ 62977957Sbenno if (rptr) 63077957Sbenno *rptr = x; 63177957Sbenno 63296906Sbenno return (0); 63377957Sbenno} 63477957Sbenno 63577957Sbenno/* 63677957Sbenno * For now, this only deals with the particular unaligned access case 63777957Sbenno * that gcc tends to generate. Eventually it should handle all of the 63877957Sbenno * possibilities that can happen on a 32-bit PowerPC in big-endian mode. 63977957Sbenno */ 64077957Sbenno 64177957Sbennostatic int 64296906Sbennofix_unaligned(struct thread *td, struct trapframe *frame) 64377957Sbenno{ 64496906Sbenno struct thread *fputhread; 64596906Sbenno int indicator, reg; 64696906Sbenno double *fpr; 64777957Sbenno 64896906Sbenno indicator = EXC_ALI_OPCODE_INDICATOR(frame->dsisr); 64996906Sbenno 65077957Sbenno switch (indicator) { 65177957Sbenno case EXC_ALI_LFD: 65277957Sbenno case EXC_ALI_STFD: 65396906Sbenno reg = EXC_ALI_RST(frame->dsisr); 65496906Sbenno fpr = &td->td_pcb->pcb_fpu.fpr[reg]; 65596906Sbenno fputhread = PCPU_GET(fputhread); 65677957Sbenno 65796906Sbenno /* Juggle the FPU to ensure that we've initialized 65896906Sbenno * the FPRs, and that their current state is in 65996906Sbenno * the PCB. 66096906Sbenno */ 66196906Sbenno if (fputhread != td) { 66296906Sbenno if (fputhread) 66396906Sbenno save_fpu(fputhread); 66496906Sbenno enable_fpu(td); 66596906Sbenno } 66696906Sbenno save_fpu(td); 66777957Sbenno 66896906Sbenno if (indicator == EXC_ALI_LFD) { 66996906Sbenno if (copyin((void *)frame->dar, fpr, 67096906Sbenno sizeof(double)) != 0) 67196906Sbenno return -1; 67296906Sbenno enable_fpu(td); 67396906Sbenno } else { 67496906Sbenno if (copyout(fpr, (void *)frame->dar, 67596906Sbenno sizeof(double)) != 0) 67696906Sbenno return -1; 67777957Sbenno } 67896906Sbenno return 0; 67977957Sbenno break; 68077957Sbenno } 68177957Sbenno 68277957Sbenno return -1; 68377957Sbenno} 684