trap.c revision 134571
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 34113038Sobrien#include <sys/cdefs.h> 35113038Sobrien__FBSDID("$FreeBSD: head/sys/powerpc/aim/trap.c 134571 2004-08-31 07:34:54Z 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> 4677957Sbenno#include <sys/reboot.h> 4777957Sbenno#include <sys/syscall.h> 4896938Sbenno#include <sys/sysent.h> 4996255Sbenno#include <sys/systm.h> 5096906Sbenno#include <sys/uio.h> 5177957Sbenno#include <sys/user.h> 5286067Smp#ifdef KTRACE 5377957Sbenno#include <sys/ktrace.h> 5486067Smp#endif 5596938Sbenno#include <sys/vmmeter.h> 5677957Sbenno 5777957Sbenno#include <vm/vm.h> 5886067Smp#include <vm/pmap.h> 5986067Smp#include <vm/vm_extern.h> 6096255Sbenno#include <vm/vm_param.h> 6177957Sbenno#include <vm/vm_kern.h> 6286067Smp#include <vm/vm_map.h> 6396255Sbenno#include <vm/vm_page.h> 6477957Sbenno 6577957Sbenno#include <machine/cpu.h> 6696255Sbenno#include <machine/db_machdep.h> 6796255Sbenno#include <machine/fpu.h> 6877957Sbenno#include <machine/frame.h> 6977957Sbenno#include <machine/pcb.h> 7096255Sbenno#include <machine/pmap.h> 7177957Sbenno#include <machine/psl.h> 7277957Sbenno#include <machine/trap.h> 7396255Sbenno#include <machine/spr.h> 7496255Sbenno#include <machine/sr.h> 7577957Sbenno 7696938Sbennovoid trap(struct trapframe *); 7796255Sbenno 7896938Sbennostatic void trap_fatal(struct trapframe *frame); 7996938Sbennostatic void printtrap(u_int vector, struct trapframe *frame, int isfatal, 8096938Sbenno int user); 8196938Sbennostatic int trap_pfault(struct trapframe *frame, int user); 8296938Sbennostatic int fix_unaligned(struct thread *td, struct trapframe *frame); 8396938Sbennostatic int handle_onfault(struct trapframe *frame); 8496938Sbennostatic void syscall(struct trapframe *frame); 8596938Sbenno 8696906Sbennostatic __inline void setusr(u_int); 8777957Sbenno 8896906Sbennoint setfault(faultbuf); /* defined in locore.S */ 8996906Sbenno 9096255Sbenno/* Why are these not defined in a header? */ 9196906Sbennoint badaddr(void *, size_t); 9296906Sbennoint badaddr_read(void *, size_t, int *); 9386067Smp 9496499Sbennoextern char *syscallnames[]; 9596499Sbenno 96132074Sgrehanextern int debugger_on_panic; /* XXX */ 97132074Sgrehan 9896938Sbennostruct powerpc_exception { 9996938Sbenno u_int vector; 10096938Sbenno char *name; 10196938Sbenno}; 10296938Sbenno 10396938Sbennostatic struct powerpc_exception powerpc_exceptions[] = { 10496938Sbenno { 0x0100, "system reset" }, 10596938Sbenno { 0x0200, "machine check" }, 10696938Sbenno { 0x0300, "data storage interrupt" }, 10796938Sbenno { 0x0400, "instruction storage interrupt" }, 10896938Sbenno { 0x0500, "external interrupt" }, 10996938Sbenno { 0x0600, "alignment" }, 11096938Sbenno { 0x0700, "program" }, 11196938Sbenno { 0x0800, "floating-point unavailable" }, 11296938Sbenno { 0x0900, "decrementer" }, 11396938Sbenno { 0x0c00, "system call" }, 11496938Sbenno { 0x0d00, "trace" }, 11596938Sbenno { 0x0e00, "floating-point assist" }, 11696938Sbenno { 0x0f00, "performance monitoring" }, 11796938Sbenno { 0x0f20, "altivec unavailable" }, 11896938Sbenno { 0x1000, "instruction tlb miss" }, 11996938Sbenno { 0x1100, "data load tlb miss" }, 12096938Sbenno { 0x1200, "data store tlb miss" }, 12196938Sbenno { 0x1300, "instruction breakpoint" }, 122131698Sgrehan { 0x1400, "system management" }, 12396938Sbenno { 0x1600, "altivec assist" }, 12496938Sbenno { 0x1700, "thermal management" }, 12596938Sbenno { 0x2000, "run mode/trace" }, 12696938Sbenno { 0x3000, NULL } 12796938Sbenno}; 12896938Sbenno 12996938Sbennostatic const char * 13096938Sbennotrapname(u_int vector) 13196938Sbenno{ 13296938Sbenno struct powerpc_exception *pe; 13396938Sbenno 13496938Sbenno for (pe = powerpc_exceptions; pe->vector != 0x3000; pe++) { 13596938Sbenno if (pe->vector == vector) 13696938Sbenno return (pe->name); 13796938Sbenno } 13896938Sbenno 13996938Sbenno return ("unknown"); 14096938Sbenno} 14196938Sbenno 14296255Sbennovoid 14396906Sbennotrap(struct trapframe *frame) 14486067Smp{ 145112429Sgrehan struct thread *td; 14696906Sbenno struct proc *p; 14796938Sbenno int sig, type, user; 14896938Sbenno u_int sticks, ucode; 14986067Smp 15096938Sbenno atomic_add_int(&cnt.v_trap, 1); 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; 15896938Sbenno sticks = 0; 15986067Smp 16096938Sbenno CTR3(KTR_TRAP, "trap: %s type=%s (%s)", p->p_comm, 16196938Sbenno trapname(type), user ? "user" : "kernel"); 16286067Smp 16396938Sbenno if (user) { 164111024Sjeff sticks = td->td_sticks; 16596938Sbenno td->td_frame = frame; 16696938Sbenno if (td->td_ucred != p->p_ucred) 16796938Sbenno cred_update_thread(td); 16886067Smp 16996938Sbenno /* User Mode Traps */ 17096938Sbenno switch (type) { 17196938Sbenno case EXC_RUNMODETRC: 17296938Sbenno case EXC_TRC: 17396938Sbenno frame->srr1 &= ~PSL_SE; 17496938Sbenno sig = SIGTRAP; 17596938Sbenno break; 17677957Sbenno 17796938Sbenno case EXC_DSI: 17896938Sbenno case EXC_ISI: 17996938Sbenno sig = trap_pfault(frame, 1); 18096938Sbenno break; 18196938Sbenno 18296938Sbenno case EXC_SC: 18396938Sbenno syscall(frame); 18496938Sbenno break; 18596938Sbenno 18696938Sbenno case EXC_FPU: 187112429Sgrehan KASSERT((td->td_pcb->pcb_flags & PCB_FPU) != PCB_FPU, 188112429Sgrehan ("FPU already enabled for thread")); 18996938Sbenno enable_fpu(td); 19096938Sbenno break; 19196938Sbenno 19296938Sbenno#ifdef ALTIVEC 19396938Sbenno case EXC_VEC: 19496938Sbenno if ((vecthread = PCPU_GET(vecthread)) != NULL) { 19596938Sbenno KASSERT(vecthread != td, 19696938Sbenno ("altivec already enabled")); 19796938Sbenno save_vec(vecthread); 19896938Sbenno } 19996938Sbenno PCPU_SET(vecthread, td); 20096938Sbenno td->td_pcb->pcb_veccpu = PCPU_GET(cpuid); 20196938Sbenno enable_vec(td); 20296938Sbenno frame->srr1 |= PSL_VEC; 20396938Sbenno break; 20496938Sbenno#endif /* ALTIVEC */ 20596938Sbenno 20696938Sbenno case EXC_ALI: 20796938Sbenno if (fix_unaligned(td, frame) != 0) 20896938Sbenno sig = SIGBUS; 20977957Sbenno else 21096938Sbenno frame->srr0 += 4; 21196938Sbenno break; 21296938Sbenno 21396938Sbenno case EXC_PGM: 21496938Sbenno /* XXX temporarily */ 21596938Sbenno /* XXX: Magic Number? */ 21696938Sbenno if (frame->srr1 & 0x0002000) 21796938Sbenno sig = SIGTRAP; 21896938Sbenno else 21996938Sbenno sig = SIGILL; 22096938Sbenno break; 22196938Sbenno 22296938Sbenno default: 22396938Sbenno trap_fatal(frame); 22477957Sbenno } 22596938Sbenno } else { 22696938Sbenno /* Kernel Mode Traps */ 22796938Sbenno 22896938Sbenno KASSERT(cold || td->td_ucred != NULL, 22996938Sbenno ("kernel trap doesn't have ucred")); 23096938Sbenno switch (type) { 23196938Sbenno case EXC_DSI: 23296938Sbenno if (trap_pfault(frame, 0) == 0) 23396938Sbenno return; 23496938Sbenno break; 23596938Sbenno case EXC_MCHK: 23696938Sbenno if (handle_onfault(frame)) 23796938Sbenno return; 23896938Sbenno break; 23996938Sbenno default: 240132994Sgrehan break; 24196255Sbenno } 242132994Sgrehan trap_fatal(frame); 24386067Smp } 24496938Sbenno 24596938Sbenno#ifdef ALTIVEC 24696938Sbenno if (td != PCPU_GET(vecthread) || 24796938Sbenno td->td_pcb->pcb_veccpu != PCPU_GET(cpuid)) 24896938Sbenno frame->srr1 &= ~PSL_VEC; 24996938Sbenno#endif /* ALTIVEC */ 25096938Sbenno 25196938Sbenno if (sig != 0) { 25296938Sbenno if (p->p_sysent->sv_transtrap != NULL) 25396938Sbenno sig = (p->p_sysent->sv_transtrap)(sig, type); 254112883Sjeff trapsignal(td, sig, ucode); 25596938Sbenno } 25696938Sbenno 25796938Sbenno userret(td, frame, sticks); 25896938Sbenno mtx_assert(&Giant, MA_NOTOWNED); 25996938Sbenno} 26096938Sbenno 26196938Sbennostatic void 26296938Sbennotrap_fatal(struct trapframe *frame) 26396938Sbenno{ 26496938Sbenno 26596938Sbenno printtrap(frame->exc, frame, 1, (frame->srr1 & PSL_PR)); 266132074Sgrehan#ifdef KDB 267132074Sgrehan if ((debugger_on_panic || kdb_active) && 268132074Sgrehan kdb_trap(frame->exc, 0, frame)) 26996938Sbenno return; 27096938Sbenno#endif 27196938Sbenno panic("%s trap", trapname(frame->exc)); 27296938Sbenno} 27396938Sbenno 27496938Sbennostatic void 27596938Sbennoprinttrap(u_int vector, struct trapframe *frame, int isfatal, int user) 27696938Sbenno{ 27796938Sbenno 27896938Sbenno printf("\n"); 27996938Sbenno printf("%s %s trap:\n", isfatal ? "fatal" : "handled", 28096938Sbenno user ? "user" : "kernel"); 28196938Sbenno printf("\n"); 28296938Sbenno printf(" exception = 0x%x (%s)\n", vector >> 8, 28396938Sbenno trapname(vector)); 28496938Sbenno switch (vector) { 28596938Sbenno case EXC_DSI: 28696938Sbenno printf(" virtual address = 0x%x\n", frame->dar); 28796255Sbenno break; 28896255Sbenno case EXC_ISI: 28996938Sbenno printf(" virtual address = 0x%x\n", frame->srr0); 29096255Sbenno break; 29196938Sbenno } 29297347Sbenno printf(" srr0 = 0x%x\n", frame->srr0); 29397347Sbenno printf(" srr1 = 0x%x\n", frame->srr1); 29496938Sbenno printf(" curthread = %p\n", curthread); 29596938Sbenno if (curthread != NULL) 29696938Sbenno printf(" pid = %d, comm = %s\n", 29796938Sbenno curthread->td_proc->p_pid, curthread->td_proc->p_comm); 29896938Sbenno printf("\n"); 29996938Sbenno} 30086067Smp 30196938Sbenno/* 30296938Sbenno * Handles a fatal fault when we have onfault state to recover. Returns 30396938Sbenno * non-zero if there was onfault recovery state available. 30496938Sbenno */ 30596938Sbennostatic int 30696938Sbennohandle_onfault(struct trapframe *frame) 30796938Sbenno{ 30896938Sbenno struct thread *td; 30996938Sbenno faultbuf *fb; 31086067Smp 31196938Sbenno td = curthread; 31296938Sbenno fb = td->td_pcb->pcb_onfault; 31396938Sbenno if (fb != NULL) { 31496938Sbenno frame->srr0 = (*fb)[0]; 31596938Sbenno frame->fixreg[1] = (*fb)[1]; 31696938Sbenno frame->fixreg[2] = (*fb)[2]; 317131867Sgrehan frame->fixreg[3] = 1; 31896938Sbenno frame->cr = (*fb)[3]; 31996938Sbenno bcopy(&(*fb)[4], &frame->fixreg[13], 32096938Sbenno 19 * sizeof(register_t)); 32196938Sbenno return (1); 32296938Sbenno } 32396938Sbenno return (0); 32496938Sbenno} 32586067Smp 32696938Sbennovoid 32796938Sbennosyscall(struct trapframe *frame) 32896938Sbenno{ 32996938Sbenno caddr_t params; 33096938Sbenno struct sysent *callp; 33196938Sbenno struct thread *td; 33296938Sbenno struct proc *p; 33396938Sbenno int error, n; 33496938Sbenno size_t narg; 33596938Sbenno register_t args[10]; 33696938Sbenno u_int code; 33786067Smp 33896938Sbenno td = PCPU_GET(curthread); 33996938Sbenno p = td->td_proc; 34086067Smp 34196938Sbenno atomic_add_int(&cnt.v_syscall, 1); 342131698Sgrehan 343131698Sgrehan if (p->p_flag & P_SA) 344134571Sjulian thread_user_enter(td); 345131698Sgrehan 34696938Sbenno code = frame->fixreg[0]; 34796938Sbenno params = (caddr_t)(frame->fixreg + FIRSTARG); 34896938Sbenno n = NARGREG; 349131698Sgrehan 35096938Sbenno if (p->p_sysent->sv_prepsyscall) { 35196938Sbenno /* 35296938Sbenno * The prep code is MP aware. 35396938Sbenno */ 35496938Sbenno (*p->p_sysent->sv_prepsyscall)(frame, args, &code, ¶ms); 35596938Sbenno } else if (code == SYS_syscall) { 35696938Sbenno /* 35796938Sbenno * code is first argument, 35896938Sbenno * followed by actual args. 35996938Sbenno */ 360103607Sgrehan code = *(u_int *) params; 361103607Sgrehan params += sizeof(register_t); 36296938Sbenno n -= 1; 36396938Sbenno } else if (code == SYS___syscall) { 36496938Sbenno /* 36596938Sbenno * Like syscall, but code is a quad, 36696938Sbenno * so as to maintain quad alignment 36796938Sbenno * for the rest of the args. 36896938Sbenno */ 369103607Sgrehan params += sizeof(register_t); 370103607Sgrehan code = *(u_int *) params; 371103607Sgrehan params += sizeof(register_t); 37296938Sbenno n -= 2; 37396938Sbenno } 37496452Sbenno 37596938Sbenno if (p->p_sysent->sv_mask) 37696938Sbenno code &= p->p_sysent->sv_mask; 37786067Smp 37896938Sbenno if (code >= p->p_sysent->sv_size) 37996938Sbenno callp = &p->p_sysent->sv_table[0]; 38096938Sbenno else 38196938Sbenno callp = &p->p_sysent->sv_table[code]; 38286067Smp 38396938Sbenno narg = callp->sy_narg & SYF_ARGMASK; 38496255Sbenno 385103607Sgrehan if (narg > n) { 38696938Sbenno bcopy(params, args, n * sizeof(register_t)); 38796938Sbenno error = copyin(MOREARGS(frame->fixreg[1]), args + n, 388103607Sgrehan (narg - n) * sizeof(register_t)); 38998001Sjhb params = (caddr_t)args; 39098001Sjhb } else 39198001Sjhb error = 0; 39298001Sjhb 393131867Sgrehan CTR5(KTR_SYSC, "syscall: p=%s %s(%x %x %x)", p->p_comm, 394131867Sgrehan syscallnames[code], 395131867Sgrehan frame->fixreg[FIRSTARG], 396131867Sgrehan frame->fixreg[FIRSTARG+1], 397131867Sgrehan frame->fixreg[FIRSTARG+2]); 398131867Sgrehan 39977957Sbenno#ifdef KTRACE 40098001Sjhb if (KTRPOINT(td, KTR_SYSCALL)) 401103607Sgrehan ktrsyscall(code, narg, (register_t *)params); 40277957Sbenno#endif 40396938Sbenno /* 40496938Sbenno * Try to run the syscall without Giant if the syscall is MP safe. 40596938Sbenno */ 40696938Sbenno if ((callp->sy_narg & SYF_MPSAFE) == 0) 40796938Sbenno mtx_lock(&Giant); 40877957Sbenno 40998001Sjhb if (error == 0) { 41098001Sjhb td->td_retval[0] = 0; 41198001Sjhb td->td_retval[1] = frame->fixreg[FIRSTARG + 1]; 41296255Sbenno 41398001Sjhb STOPEVENT(p, S_SCE, narg); 41477957Sbenno 41598001Sjhb error = (*callp->sy_call)(td, params); 416131867Sgrehan 417131867Sgrehan CTR3(KTR_SYSC, "syscall: p=%s %s ret=%x", p->p_comm, 418131867Sgrehan syscallnames[code], td->td_retval[0]); 41998001Sjhb } 42096938Sbenno switch (error) { 42196938Sbenno case 0: 422131698Sgrehan if ((frame->fixreg[0] == SYS___syscall) && 423103607Sgrehan (code != SYS_lseek)) { 424103607Sgrehan /* 425103607Sgrehan * 64-bit return, 32-bit syscall. Fixup byte order 426103607Sgrehan */ 427103607Sgrehan frame->fixreg[FIRSTARG] = 0; 428103607Sgrehan frame->fixreg[FIRSTARG + 1] = td->td_retval[0]; 429103607Sgrehan } else { 430103607Sgrehan frame->fixreg[FIRSTARG] = td->td_retval[0]; 431103607Sgrehan frame->fixreg[FIRSTARG + 1] = td->td_retval[1]; 432103607Sgrehan } 43396938Sbenno /* XXX: Magic number */ 43496938Sbenno frame->cr &= ~0x10000000; 43596255Sbenno break; 43696938Sbenno case ERESTART: 43796938Sbenno /* 43896938Sbenno * Set user's pc back to redo the system call. 43996938Sbenno */ 44096938Sbenno frame->srr0 -= 4; 44196255Sbenno break; 44296938Sbenno case EJUSTRETURN: 44396938Sbenno /* nothing to do */ 44496938Sbenno break; 44596938Sbenno default: 44696938Sbenno if (p->p_sysent->sv_errsize) { 44796938Sbenno if (error >= p->p_sysent->sv_errsize) 44896938Sbenno error = -1; /* XXX */ 44996938Sbenno else 45096938Sbenno error = p->p_sysent->sv_errtbl[error]; 45196255Sbenno } 45296938Sbenno frame->fixreg[FIRSTARG] = error; 45396938Sbenno /* XXX: Magic number: Carry Flag Equivalent? */ 45496938Sbenno frame->cr |= 0x10000000; 45596938Sbenno break; 45677957Sbenno } 45777957Sbenno 458131698Sgrehan 45998001Sjhb if ((callp->sy_narg & SYF_MPSAFE) == 0) 46098001Sjhb mtx_unlock(&Giant); 46198001Sjhb 46296938Sbenno#ifdef KTRACE 46398001Sjhb if (KTRPOINT(td, KTR_SYSRET)) 46498001Sjhb ktrsysret(code, error, td->td_retval[0]); 46596255Sbenno#endif 46686067Smp 46796255Sbenno /* 46896938Sbenno * Does the comment in the i386 code about errno apply here? 46996255Sbenno */ 47096938Sbenno STOPEVENT(p, S_SCX, code); 47186067Smp 472111883Sjhb WITNESS_WARN(WARN_PANIC, NULL, "System call %s returning", 473114305Sjhb (code >= 0 && code < SYS_MAXSYSCALL) ? syscallnames[code] : "???"); 47496938Sbenno mtx_assert(&sched_lock, MA_NOTOWNED); 475131698Sgrehan mtx_assert(&Giant, MA_NOTOWNED); 47677957Sbenno} 47777957Sbenno 47896938Sbennostatic int 47996938Sbennotrap_pfault(struct trapframe *frame, int user) 48077957Sbenno{ 48196938Sbenno vm_offset_t eva, va; 48296938Sbenno struct thread *td; 48396938Sbenno struct proc *p; 48496938Sbenno vm_map_t map; 48596938Sbenno vm_prot_t ftype; 48696938Sbenno int rv; 48796938Sbenno u_int user_sr; 48877957Sbenno 48996938Sbenno td = curthread; 49096906Sbenno p = td->td_proc; 49196938Sbenno if (frame->exc == EXC_ISI) { 49296938Sbenno eva = frame->srr0; 49396938Sbenno ftype = VM_PROT_READ | VM_PROT_EXECUTE; 49496938Sbenno } else { 49596938Sbenno eva = frame->dar; 49696938Sbenno if (frame->dsisr & DSISR_STORE) 497103607Sgrehan ftype = VM_PROT_WRITE; 49896938Sbenno else 49996938Sbenno ftype = VM_PROT_READ; 50096938Sbenno } 50196906Sbenno 50296938Sbenno if (user) { 50396938Sbenno map = &p->p_vmspace->vm_map; 50496938Sbenno } else { 50596938Sbenno if ((eva >> ADDR_SR_SHFT) == USER_SR) { 50696938Sbenno if (p->p_vmspace == NULL) 50796938Sbenno return (SIGSEGV); 508131698Sgrehan 50996938Sbenno __asm ("mfsr %0, %1" 51096938Sbenno : "=r"(user_sr) 51196938Sbenno : "K"(USER_SR)); 51296938Sbenno eva &= ADDR_PIDX | ADDR_POFF; 51396938Sbenno eva |= user_sr << ADDR_SR_SHFT; 51496938Sbenno map = &p->p_vmspace->vm_map; 51596938Sbenno } else { 51696938Sbenno map = kernel_map; 51796938Sbenno } 51896938Sbenno } 51996938Sbenno va = trunc_page(eva); 52077957Sbenno 52196938Sbenno if (map != kernel_map) { 52296938Sbenno /* 52396938Sbenno * Keep swapout from messing with us during this 52496938Sbenno * critical time. 52596938Sbenno */ 52696255Sbenno PROC_LOCK(p); 52796938Sbenno ++p->p_lock; 52896255Sbenno PROC_UNLOCK(p); 52996938Sbenno 53096938Sbenno /* Fault in the user page: */ 53196938Sbenno rv = vm_fault(map, va, ftype, 53296938Sbenno (ftype & VM_PROT_WRITE) ? VM_FAULT_DIRTY 53396938Sbenno : VM_FAULT_NORMAL); 53496938Sbenno 53596938Sbenno PROC_LOCK(p); 53696938Sbenno --p->p_lock; 53796938Sbenno PROC_UNLOCK(p); 53896938Sbenno } else { 53996938Sbenno /* 54096938Sbenno * Don't have to worry about process locking or stacks in the 54196938Sbenno * kernel. 54296938Sbenno */ 54396938Sbenno rv = vm_fault(map, va, ftype, VM_FAULT_NORMAL); 54496255Sbenno } 54596938Sbenno 54696938Sbenno if (rv == KERN_SUCCESS) 54796938Sbenno return (0); 54896938Sbenno 54996938Sbenno if (!user && handle_onfault(frame)) 55096938Sbenno return (0); 55196938Sbenno 55296938Sbenno return (SIGSEGV); 55377957Sbenno} 55477957Sbenno 55596255Sbennostatic __inline void 55696906Sbennosetusr(u_int content) 55796255Sbenno{ 55896255Sbenno __asm __volatile ("isync; mtsr %0,%1; isync" 55996255Sbenno :: "n"(USER_SR), "r"(content)); 56096255Sbenno} 56196255Sbenno 56277957Sbennoint 56396906Sbennobadaddr(void *addr, size_t size) 56477957Sbenno{ 56596906Sbenno return (badaddr_read(addr, size, NULL)); 56677957Sbenno} 56777957Sbenno 56877957Sbennoint 56996906Sbennobadaddr_read(void *addr, size_t size, int *rptr) 57077957Sbenno{ 57196906Sbenno struct thread *td; 57296906Sbenno faultbuf env; 57396906Sbenno int x; 57477957Sbenno 57577957Sbenno /* Get rid of any stale machine checks that have been waiting. */ 57677957Sbenno __asm __volatile ("sync; isync"); 57777957Sbenno 57896255Sbenno td = PCPU_GET(curthread); 57996255Sbenno 58077957Sbenno if (setfault(env)) { 58196255Sbenno td->td_pcb->pcb_onfault = 0; 58277957Sbenno __asm __volatile ("sync"); 58377957Sbenno return 1; 58477957Sbenno } 58577957Sbenno 58677957Sbenno __asm __volatile ("sync"); 58777957Sbenno 58877957Sbenno switch (size) { 58977957Sbenno case 1: 59077957Sbenno x = *(volatile int8_t *)addr; 59177957Sbenno break; 59277957Sbenno case 2: 59377957Sbenno x = *(volatile int16_t *)addr; 59477957Sbenno break; 59577957Sbenno case 4: 59677957Sbenno x = *(volatile int32_t *)addr; 59777957Sbenno break; 59877957Sbenno default: 59977957Sbenno panic("badaddr: invalid size (%d)", size); 60077957Sbenno } 60177957Sbenno 60277957Sbenno /* Make sure we took the machine check, if we caused one. */ 60377957Sbenno __asm __volatile ("sync; isync"); 60477957Sbenno 60596255Sbenno td->td_pcb->pcb_onfault = 0; 60677957Sbenno __asm __volatile ("sync"); /* To be sure. */ 60777957Sbenno 60877957Sbenno /* Use the value to avoid reorder. */ 60977957Sbenno if (rptr) 61077957Sbenno *rptr = x; 61177957Sbenno 61296906Sbenno return (0); 61377957Sbenno} 61477957Sbenno 61577957Sbenno/* 61677957Sbenno * For now, this only deals with the particular unaligned access case 61777957Sbenno * that gcc tends to generate. Eventually it should handle all of the 61877957Sbenno * possibilities that can happen on a 32-bit PowerPC in big-endian mode. 61977957Sbenno */ 62077957Sbenno 62177957Sbennostatic int 62296906Sbennofix_unaligned(struct thread *td, struct trapframe *frame) 62377957Sbenno{ 62496906Sbenno struct thread *fputhread; 62596906Sbenno int indicator, reg; 62696906Sbenno double *fpr; 62777957Sbenno 62896906Sbenno indicator = EXC_ALI_OPCODE_INDICATOR(frame->dsisr); 62996906Sbenno 63077957Sbenno switch (indicator) { 63177957Sbenno case EXC_ALI_LFD: 63277957Sbenno case EXC_ALI_STFD: 63396906Sbenno reg = EXC_ALI_RST(frame->dsisr); 63496906Sbenno fpr = &td->td_pcb->pcb_fpu.fpr[reg]; 63596906Sbenno fputhread = PCPU_GET(fputhread); 63677957Sbenno 63796906Sbenno /* Juggle the FPU to ensure that we've initialized 63896906Sbenno * the FPRs, and that their current state is in 63996906Sbenno * the PCB. 64096906Sbenno */ 64196906Sbenno if (fputhread != td) { 64296906Sbenno if (fputhread) 64396906Sbenno save_fpu(fputhread); 64496906Sbenno enable_fpu(td); 64596906Sbenno } 64696906Sbenno save_fpu(td); 64777957Sbenno 64896906Sbenno if (indicator == EXC_ALI_LFD) { 64996906Sbenno if (copyin((void *)frame->dar, fpr, 65096906Sbenno sizeof(double)) != 0) 65196906Sbenno return -1; 65296906Sbenno enable_fpu(td); 65396906Sbenno } else { 65496906Sbenno if (copyout(fpr, (void *)frame->dar, 65596906Sbenno sizeof(double)) != 0) 65696906Sbenno return -1; 65777957Sbenno } 65896906Sbenno return 0; 65977957Sbenno break; 66077957Sbenno } 66177957Sbenno 66277957Sbenno return -1; 66377957Sbenno} 664