Revamp how user MSR/SRR1 are dealt with.
Add a PSL_USEROK_P(psl) macro which valids the bits (replaces the use of PSL_USERSTATIC). Add a PSL_USERSRR1 mask which is used to mask out status bits in the upper half of SRR1. Make sure PSL_VEC is set appropriately in userret(). PSL_VEC is in the same region as SSR1 status bits so it's not preserved on exceptions. Thus we need to make to set it. When returning a MSR/SRR1 to userland, always clear the status bits. Add emulation of the mfpvr, mtmsr, and mfmsr instructions.
This commit is contained in:
parent
e30c25106f
commit
ee00feaab9
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: psl.h,v 1.9 2004/04/04 16:49:12 matt Exp $ */
|
||||
/* $NetBSD: psl.h,v 1.10 2004/04/15 21:07:06 matt Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (C) 1995, 1996 Wolfgang Solfrank.
|
||||
@ -82,7 +82,12 @@
|
||||
|
||||
/*
|
||||
* A user is not allowed to change any MSR bits except the following:
|
||||
* We restrict the test to the low 16 bits of the MSR since those are the
|
||||
* only ones preserved in the trap. Note that this means PSL_VEC needs to
|
||||
* restored the SRR1 in userret.
|
||||
*/
|
||||
#define PSL_USERSTATIC (~(PSL_VEC|PSL_FP|PSL_FE0|PSL_FE1|PSL_LE|PSL_SE|PSL_BE))
|
||||
#define PSL_USERSRR1 ((PSL_USERSET|PSL_USERMOD) & 0xFFFF)
|
||||
#define PSL_USERMOD (PSL_VEC|PSL_FP|PSL_FE0|PSL_FE1|PSL_LE|PSL_SE|PSL_BE)
|
||||
#define PSL_USEROK_P(psl) (((psl) & ~PSL_USERMOD) == PSL_USERSET)
|
||||
|
||||
#endif /* _POWERPC_PSL_H_ */
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: userret.h,v 1.8 2004/04/06 02:25:22 matt Exp $ */
|
||||
/* $NetBSD: userret.h,v 1.9 2004/04/15 21:07:07 matt Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (C) 1995, 1996 Wolfgang Solfrank.
|
||||
@ -44,13 +44,13 @@
|
||||
static __inline void
|
||||
userret(struct lwp *l, struct trapframe *frame)
|
||||
{
|
||||
struct cpu_info *ci = curcpu();
|
||||
struct pcb *pcb;
|
||||
struct cpu_info * const ci = curcpu();
|
||||
struct pcb * const pcb = &l->l_addr->u_pcb;
|
||||
|
||||
/* Invoke MI userret code */
|
||||
mi_userret(l);
|
||||
|
||||
pcb = &l->l_addr->u_pcb;
|
||||
frame->srr1 &= PSL_USERSRR1; /* clear SRR1 status bits */
|
||||
|
||||
/*
|
||||
* If someone stole the fp or vector unit while we were away,
|
||||
@ -64,9 +64,16 @@ userret(struct lwp *l, struct trapframe *frame)
|
||||
}
|
||||
#endif
|
||||
#ifdef ALTIVEC
|
||||
if ((frame->srr1 & PSL_VEC) &&
|
||||
(l != ci->ci_veclwp || pcb->pcb_veccpu != ci)) {
|
||||
frame->srr1 &= ~PSL_VEC;
|
||||
/*
|
||||
* We need to manually restore PSL_VEC each time we return
|
||||
* to user mode since PSL_VEC is not preserved in SRR1.
|
||||
*/
|
||||
if (frame->srr1 & PSL_VEC) {
|
||||
if (l != ci->ci_veclwp)
|
||||
frame->srr1 &= ~PSL_VEC;
|
||||
} else {
|
||||
if (l == ci->ci_veclwp)
|
||||
frame->srr1 |= PSL_VEC;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: altivec.c,v 1.5 2003/07/15 02:54:45 lukem Exp $ */
|
||||
/* $NetBSD: altivec.c,v 1.6 2004/04/15 21:07:07 matt Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (C) 1996 Wolfgang Solfrank.
|
||||
@ -32,7 +32,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: altivec.c,v 1.5 2003/07/15 02:54:45 lukem Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: altivec.c,v 1.6 2004/04/15 21:07:07 matt Exp $");
|
||||
|
||||
#include "opt_multiprocessor.h"
|
||||
|
||||
@ -109,7 +109,6 @@ enable_vec()
|
||||
* Enable AltiVec when we return to user-mode.
|
||||
* Record the new ownership of the AltiVec unit.
|
||||
*/
|
||||
tf->srr1 |= PSL_VEC;
|
||||
curcpu()->ci_veclwp = l;
|
||||
pcb->pcb_veccpu = curcpu();
|
||||
__asm __volatile ("sync");
|
||||
@ -176,7 +175,6 @@ save_vec_cpu(void)
|
||||
* Note that we aren't using any CPU resources and stop any
|
||||
* data streams.
|
||||
*/
|
||||
tf->srr1 &= ~PSL_VEC;
|
||||
pcb->pcb_veccpu = NULL;
|
||||
ci->ci_veclwp = NULL;
|
||||
__asm __volatile ("dssall; sync");
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: compat_13_machdep.c,v 1.8 2003/09/27 04:44:42 matt Exp $ */
|
||||
/* $NetBSD: compat_13_machdep.c,v 1.9 2004/04/15 21:07:07 matt Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (C) 1995, 1996 Wolfgang Solfrank.
|
||||
@ -32,7 +32,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: compat_13_machdep.c,v 1.8 2003/09/27 04:44:42 matt Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: compat_13_machdep.c,v 1.9 2004/04/15 21:07:07 matt Exp $");
|
||||
|
||||
#include "opt_ppcarch.h"
|
||||
|
||||
@ -68,7 +68,7 @@ compat_13_sys_sigreturn(struct lwp *l, void *v, register_t *retval)
|
||||
|
||||
/* Restore the register context. */
|
||||
tf = trapframe(l);
|
||||
if ((sc.sc_frame.srr1 & PSL_USERSTATIC) != (tf->srr1 & PSL_USERSTATIC))
|
||||
if (!PSL_USEROK_P(sc.sc_frame.srr1))
|
||||
return (EINVAL);
|
||||
|
||||
/* Restore register context. */
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: compat_16_machdep.c,v 1.3 2004/04/04 17:10:32 matt Exp $ */
|
||||
/* $NetBSD: compat_16_machdep.c,v 1.4 2004/04/15 21:07:07 matt Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (C) 1995, 1996 Wolfgang Solfrank.
|
||||
@ -32,9 +32,10 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: compat_16_machdep.c,v 1.3 2004/04/04 17:10:32 matt Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: compat_16_machdep.c,v 1.4 2004/04/15 21:07:07 matt Exp $");
|
||||
|
||||
#include "opt_compat_netbsd.h"
|
||||
#include "opt_altivec.h"
|
||||
#include "opt_ppcarch.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
@ -86,10 +87,13 @@ sendsig_sigcontext(int sig, const sigset_t *mask, u_long code)
|
||||
utf->xer = tf->xer;
|
||||
utf->ctr = tf->ctr;
|
||||
utf->srr0 = tf->srr0;
|
||||
utf->srr1 = tf->srr1;
|
||||
utf->srr1 = tf->srr1 & PSL_USERSRR1;
|
||||
#ifdef PPC_HAVE_FPU
|
||||
utf->srr1 |= l->l_addr->u_pcb.pcb_flags & (PCB_FE0|PCB_FE1);
|
||||
#endif
|
||||
#ifdef ALTIVEC
|
||||
utf->srr1 |= l->l_addr->u_pcb.pcb_flags & PCB_ALTIVEC ? PSL_VEC : 0;
|
||||
#endif
|
||||
#ifdef PPC_OEA
|
||||
utf->vrsave = tf->tf_xtra[TF_VRSAVE];
|
||||
utf->mq = tf->tf_xtra[TF_MQ];
|
||||
@ -180,7 +184,11 @@ compat_16_sys___sigreturn14(struct lwp *l, void *v, register_t *retval)
|
||||
|
||||
/* Restore the register context. */
|
||||
tf = trapframe(l);
|
||||
if ((sc.sc_frame.srr1 & PSL_USERSTATIC) != (tf->srr1 & PSL_USERSTATIC))
|
||||
|
||||
/*
|
||||
* Make sure SRR1 hasn't been maliciously tampered with.
|
||||
*/
|
||||
if (!PSL_USEROK_P(sc.sc_frame.srr1))
|
||||
return (EINVAL);
|
||||
|
||||
/* Restore register context. */
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: darwin_machdep.c,v 1.12 2003/12/16 13:38:26 manu Exp $ */
|
||||
/* $NetBSD: darwin_machdep.c,v 1.13 2004/04/15 21:07:07 matt Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2002 The NetBSD Foundation, Inc.
|
||||
@ -37,7 +37,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: darwin_machdep.c,v 1.12 2003/12/16 13:38:26 manu Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: darwin_machdep.c,v 1.13 2004/04/15 21:07:07 matt Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
@ -109,7 +109,7 @@ darwin_sendsig(ksi, mask)
|
||||
sf.dmc.es.exception = tf->exc;
|
||||
|
||||
sf.dmc.ss.srr0 = tf->srr0;
|
||||
sf.dmc.ss.srr1 = tf->srr1;
|
||||
sf.dmc.ss.srr1 = tf->srr1 & PSL_USERSRR1;
|
||||
memcpy(&sf.dmc.ss.gpreg[0], &tf->fixreg[0], sizeof(sf.dmc.ss.gpreg));
|
||||
sf.dmc.ss.cr = tf->cr;
|
||||
sf.dmc.ss.xer = tf->xer;
|
||||
@ -215,9 +215,7 @@ darwin_sys_sigreturn(struct lwp *l, void *v, register_t *retval)
|
||||
|
||||
/* Check for security abuse */
|
||||
tf = trapframe(l);
|
||||
mctx.ss.srr1 &= ~(PSL_POW | PSL_ILE | PSL_IP | PSL_LE | PSL_RI);
|
||||
mctx.ss.srr1 |= (PSL_PR | PSL_ME | PSL_IR | PSL_DR | PSL_EE);
|
||||
if ((mctx.ss.srr1 & PSL_USERSTATIC) != (tf->srr1 & PSL_USERSTATIC)) {
|
||||
if (!PSL_USEROK_P(mctx.ss.srr1))
|
||||
DPRINTF(("uctx.ss.srr1 = 0x%08x, rf->srr1 = 0x%08lx\n",
|
||||
mctx.ss.srr1, tf->srr1));
|
||||
return (EINVAL);
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: mach_machdep.c,v 1.18 2003/11/29 23:56:09 manu Exp $ */
|
||||
/* $NetBSD: mach_machdep.c,v 1.19 2004/04/15 21:07:07 matt Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2002 The NetBSD Foundation, Inc.
|
||||
@ -37,7 +37,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: mach_machdep.c,v 1.18 2003/11/29 23:56:09 manu Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: mach_machdep.c,v 1.19 2004/04/15 21:07:07 matt Exp $");
|
||||
|
||||
#include "opt_ppcarch.h"
|
||||
#include <sys/param.h>
|
||||
@ -109,7 +109,7 @@ mach_create_thread_child(void *arg)
|
||||
regs = (struct exec_macho_powerpc_thread_state *)mctc->mctc_state;
|
||||
|
||||
/* Security warning */
|
||||
if ((regs->srr1 & PSL_USERSTATIC) != (tf->srr1 & PSL_USERSTATIC))
|
||||
if (!PSL_USEROK_P(regs->srr1))
|
||||
uprintf("mach_create_thread_child: PSL_USERSTATIC change\n");
|
||||
/*
|
||||
* Call upcallret before setting the register context as it
|
||||
@ -119,8 +119,7 @@ mach_create_thread_child(void *arg)
|
||||
|
||||
/* Set requested register context */
|
||||
tf->srr0 = regs->srr0;
|
||||
tf->srr1 = ((regs->srr1 & ~PSL_USERSTATIC) |
|
||||
(tf->srr1 & PSL_USERSTATIC));
|
||||
tf->srr1 = regs->srr1;
|
||||
memcpy(tf->fixreg, ®s->r0, 32 * sizeof(register_t));
|
||||
tf->cr = regs->cr;
|
||||
tf->xer = regs->xer;
|
||||
@ -158,7 +157,7 @@ mach_thread_get_state_machdep(l, flavor, state, size)
|
||||
|
||||
mpts = (struct mach_ppc_thread_state *)state;
|
||||
mpts->srr0 = tf->srr0;
|
||||
mpts->srr1 = tf->srr1;
|
||||
mpts->srr1 = tf->srr1 & PSL_USERSRR1;
|
||||
memcpy(mpts->gpreg, tf->fixreg, 32 * sizeof(register_t));
|
||||
mpts->cr = tf->cr;
|
||||
mpts->xer = tf->xer;
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: sig_machdep.c,v 1.21 2004/04/04 17:26:10 matt Exp $ */
|
||||
/* $NetBSD: sig_machdep.c,v 1.22 2004/04/15 21:07:07 matt Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (C) 1995, 1996 Wolfgang Solfrank.
|
||||
@ -32,10 +32,11 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: sig_machdep.c,v 1.21 2004/04/04 17:26:10 matt Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: sig_machdep.c,v 1.22 2004/04/15 21:07:07 matt Exp $");
|
||||
|
||||
#include "opt_compat_netbsd.h"
|
||||
#include "opt_ppcarch.h"
|
||||
#include "opt_altivec.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/mount.h>
|
||||
@ -47,7 +48,8 @@ __KERNEL_RCSID(0, "$NetBSD: sig_machdep.c,v 1.21 2004/04/04 17:26:10 matt Exp $"
|
||||
#include <sys/ucontext.h>
|
||||
#include <sys/user.h>
|
||||
|
||||
#include <machine/fpu.h>
|
||||
#include <powerpc/fpu.h>
|
||||
#include <powerpc/altivec.h>
|
||||
|
||||
/*
|
||||
* Send a signal to process.
|
||||
@ -150,7 +152,7 @@ cpu_getmcontext(struct lwp *l, mcontext_t *mcp, unsigned int *flagp)
|
||||
{
|
||||
const struct trapframe *tf = trapframe(l);
|
||||
__greg_t *gr = mcp->__gregs;
|
||||
#ifdef PPC_HAVE_FPU
|
||||
#if defined(PPC_HAVE_FPU) || defined(ALTIVEC)
|
||||
struct pcb *pcb = &l->l_addr->u_pcb;
|
||||
#endif
|
||||
|
||||
@ -159,9 +161,12 @@ cpu_getmcontext(struct lwp *l, mcontext_t *mcp, unsigned int *flagp)
|
||||
gr[_REG_CR] = tf->cr;
|
||||
gr[_REG_LR] = tf->lr;
|
||||
gr[_REG_PC] = tf->srr0;
|
||||
gr[_REG_MSR] = tf->srr1;
|
||||
gr[_REG_MSR] = tf->srr1 & PSL_USERSRR1;
|
||||
#ifdef PPC_HAVE_FPU
|
||||
gr[_REG_MSR] |= pcb->pcb_flags & (PCB_FE0|PCB_FE1);
|
||||
#endif
|
||||
#ifdef ALTIVEC
|
||||
gr[_REG_MSR] |= pcb->pcb_flags & PCB_ALTIVEC ? PSL_VEC : 0;
|
||||
#endif
|
||||
gr[_REG_CTR] = tf->ctr;
|
||||
gr[_REG_XER] = tf->xer;
|
||||
@ -188,8 +193,23 @@ cpu_getmcontext(struct lwp *l, mcontext_t *mcp, unsigned int *flagp)
|
||||
#endif
|
||||
memset(&mcp->__fpregs, 0, sizeof(mcp->__fpregs));
|
||||
|
||||
/* No AltiVec support, for now. */
|
||||
memset(&mcp->__vrf, 0, sizeof (mcp->__vrf));
|
||||
#ifdef ALTIVEC
|
||||
/* Save AltiVec context, if any. */
|
||||
if ((pcb->pcb_flags & PCB_ALTIVEC) != 0) {
|
||||
/*
|
||||
* If we're the AltiVec owner, dump its context
|
||||
* to the PCB first.
|
||||
*/
|
||||
if (pcb->pcb_veccpu)
|
||||
save_vec_lwp(l);
|
||||
(void)memcpy(mcp->__vrf.__vrs, pcb->pcb_vr.vreg,
|
||||
sizeof (mcp->__vrf.__vrs));
|
||||
mcp->__vrf.__vscr = pcb->pcb_vr.vscr;
|
||||
mcp->__vrf.__vrsave = pcb->pcb_vr.vrsave;
|
||||
*flagp |= _UC_POWERPC_VEC;
|
||||
} else
|
||||
#endif
|
||||
memset(&mcp->__vrf, 0, sizeof (mcp->__vrf));
|
||||
}
|
||||
|
||||
int
|
||||
@ -203,8 +223,7 @@ cpu_setmcontext(struct lwp *l, const mcontext_t *mcp, unsigned int flags)
|
||||
|
||||
/* Restore GPR context, if any. */
|
||||
if (flags & _UC_CPU) {
|
||||
if ((gr[_REG_MSR] & PSL_USERSTATIC) !=
|
||||
(tf->srr1 & PSL_USERSTATIC))
|
||||
if (!PSL_USEROK_P(gr[_REG_MSR]))
|
||||
return (EINVAL);
|
||||
|
||||
#ifdef PPC_HAVE_FPU
|
||||
@ -227,8 +246,7 @@ cpu_setmcontext(struct lwp *l, const mcontext_t *mcp, unsigned int flags)
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef PPC_HAVE_FPU
|
||||
/* Restore FPR context, if any. */
|
||||
#ifdef PPC_HAVE_FPU /* Restore FPR context, if any. */
|
||||
if ((flags & _UC_FPU) && mcp->__fpregs.__fpu_valid != 0) {
|
||||
/* XXX we don't need to save the state, just to drop it */
|
||||
save_fpu_lwp(l);
|
||||
@ -239,5 +257,17 @@ cpu_setmcontext(struct lwp *l, const mcontext_t *mcp, unsigned int flags)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ALTIVEC
|
||||
/* Restore AltiVec context, if any. */
|
||||
if (flags & _UC_POWERPC_VEC) {
|
||||
/* XXX we don't need to save the state, just to drop it */
|
||||
save_vec_lwp(l);
|
||||
(void)memcpy(pcb->pcb_vr.vreg, &mcp->__vrf.__vrs,
|
||||
sizeof (pcb->pcb_vr.vreg));
|
||||
pcb->pcb_vr.vscr = mcp->__vrf.__vscr;
|
||||
pcb->pcb_vr.vrsave = mcp->__vrf.__vrsave;
|
||||
}
|
||||
#endif
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: trap.c,v 1.100 2004/04/04 19:21:36 matt Exp $ */
|
||||
/* $NetBSD: trap.c,v 1.101 2004/04/15 21:07:07 matt Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (C) 1995, 1996 Wolfgang Solfrank.
|
||||
@ -32,7 +32,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.100 2004/04/04 19:21:36 matt Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.101 2004/04/15 21:07:07 matt Exp $");
|
||||
|
||||
#include "opt_altivec.h"
|
||||
#include "opt_ddb.h"
|
||||
@ -64,7 +64,8 @@ __KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.100 2004/04/04 19:21:36 matt Exp $");
|
||||
#include <powerpc/spr.h>
|
||||
#include <powerpc/userret.h>
|
||||
|
||||
static int fix_unaligned(struct lwp *l, struct trapframe *frame);
|
||||
static int emulated_opcode(struct lwp *, struct trapframe *);
|
||||
static int fix_unaligned(struct lwp *, struct trapframe *);
|
||||
static __inline vaddr_t setusr(vaddr_t, size_t *);
|
||||
static __inline void unsetusr(void);
|
||||
|
||||
@ -418,7 +419,6 @@ trap(struct trapframe *frame)
|
||||
#endif
|
||||
case EXC_MCHK|EXC_USER:
|
||||
ci->ci_ev_umchk.ev_count++;
|
||||
KERNEL_PROC_LOCK(l);
|
||||
if (cpu_printfataltraps) {
|
||||
printf("trap: pid %d (%s): user MCHK trap @ %#lx "
|
||||
"(SRR1=%#lx)\n",
|
||||
@ -429,13 +429,14 @@ trap(struct trapframe *frame)
|
||||
ksi.ksi_trap = EXC_MCHK;
|
||||
ksi.ksi_addr = (void *)frame->srr0;
|
||||
ksi.ksi_code = BUS_OBJERR;
|
||||
KERNEL_PROC_LOCK(l);
|
||||
(*p->p_emul->e_trapsignal)(l, &ksi);
|
||||
KERNEL_PROC_UNLOCK(l);
|
||||
|
||||
case EXC_PGM|EXC_USER:
|
||||
ci->ci_ev_pgm.ev_count++;
|
||||
KERNEL_PROC_LOCK(l);
|
||||
if (frame->srr1 & 0x00020000) { /* Bit 14 is set if trap */
|
||||
KERNEL_PROC_LOCK(l);
|
||||
if (LIST_EMPTY(&p->p_raslist) ||
|
||||
ras_lookup(p, (caddr_t)frame->srr0) == (caddr_t) -1) {
|
||||
KSI_INIT_TRAP(&ksi);
|
||||
@ -448,11 +449,8 @@ trap(struct trapframe *frame)
|
||||
/* skip the trap instruction */
|
||||
frame->srr0 += 4;
|
||||
}
|
||||
KERNEL_PROC_UNLOCK(l);
|
||||
} else {
|
||||
if (cpu_printfataltraps)
|
||||
printf("trap: pid %d.%d (%s): user PGM trap @"
|
||||
" %#lx (SRR1=%#lx)\n", p->p_pid, l->l_lid,
|
||||
p->p_comm, frame->srr0, frame->srr1);
|
||||
KSI_INIT_TRAP(&ksi);
|
||||
ksi.ksi_signo = SIGILL;
|
||||
ksi.ksi_trap = EXC_PGM;
|
||||
@ -461,12 +459,21 @@ trap(struct trapframe *frame)
|
||||
ksi.ksi_signo = SIGFPE;
|
||||
ksi.ksi_code = get_fpu_fault_code();
|
||||
} else if (frame->srr1 & 0x40000) {
|
||||
if (emulated_opcode(l, frame)) {
|
||||
frame->srr0 += 4;
|
||||
break;
|
||||
}
|
||||
ksi.ksi_code = ILL_PRVOPC;
|
||||
} else
|
||||
ksi.ksi_code = ILL_ILLOPC;
|
||||
if (cpu_printfataltraps)
|
||||
printf("trap: pid %d.%d (%s): user PGM trap @"
|
||||
" %#lx (SRR1=%#lx)\n", p->p_pid, l->l_lid,
|
||||
p->p_comm, frame->srr0, frame->srr1);
|
||||
KERNEL_PROC_LOCK(l);
|
||||
(*p->p_emul->e_trapsignal)(l, &ksi);
|
||||
KERNEL_PROC_UNLOCK(l);
|
||||
}
|
||||
KERNEL_PROC_UNLOCK(l);
|
||||
break;
|
||||
|
||||
case EXC_MCHK: {
|
||||
@ -749,6 +756,81 @@ fix_unaligned(struct lwp *l, struct trapframe *frame)
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
emulated_opcode(struct lwp *l, struct trapframe *tf)
|
||||
{
|
||||
uint32_t opcode;
|
||||
if (copyin((caddr_t)tf->srr0, &opcode, sizeof(opcode)) != 0)
|
||||
return 0;
|
||||
|
||||
#define OPC_MFSPR_CODE 0x7c0002a6
|
||||
#define OPC_MFSPR_MASK (0xfc0007ff|0x001ff800)
|
||||
#define OPC_MFSPR(spr) (OPC_MFSPR_CODE |\
|
||||
(((spr) & 0x1f) << 16) |\
|
||||
(((spr) & 0x3e0) << 6))
|
||||
#define OPC_MFSPR_REG(o) (((o) >> 21) & 0x1f)
|
||||
#define OPC_MFSPR_P(o, spr) (((o) & OPC_MFSPR_MASK) == OPC_MFSPR(spr))
|
||||
|
||||
if (OPC_MFSPR_P(opcode, SPR_PVR)) {
|
||||
__asm ("mfpvr %0" : "=r"(tf->fixreg[OPC_MFSPR_REG(opcode)]));
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define OPC_MFMSR_CODE 0x7c0000a8
|
||||
#define OPC_MFMSR_MASK 0xfc1fffff
|
||||
#define OPC_MFMSR OPC_MFMSR_CODE
|
||||
#define OPC_MFMSR_REG(o) (((o) >> 21) & 0x1f)
|
||||
#define OPC_MFMSR_P(o) (((o) & OPC_MFMSR_MASK) == OPC_MFMSR_CODE)
|
||||
|
||||
if (OPC_MFMSR_P(opcode)) {
|
||||
struct pcb * const pcb = &l->l_addr->u_pcb;
|
||||
register_t msr = tf->srr1 & PSL_USERSRR1;
|
||||
|
||||
if (pcb->pcb_flags & PCB_FPU)
|
||||
msr |= PSL_FP;
|
||||
msr |= (pcb->pcb_flags & (PCB_FE0|PCB_FE1));
|
||||
#ifdef ALTIVEC
|
||||
if (pcb->pcb_flags & PCB_ALTIVEC)
|
||||
msr |= PSL_VEC;
|
||||
#endif
|
||||
tf->fixreg[OPC_MFMSR_REG(opcode)] = msr;
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define OPC_MTMSR_CODE 0x7c0000a8
|
||||
#define OPC_MTMSR_MASK 0xfc1fffff
|
||||
#define OPC_MTMSR OPC_MTMSR_CODE
|
||||
#define OPC_MTMSR_REG(o) (((o) >> 21) & 0x1f)
|
||||
#define OPC_MTMSR_P(o) (((o) & OPC_MTMSR_MASK) == OPC_MTMSR_CODE)
|
||||
|
||||
if (OPC_MTMSR_P(opcode)) {
|
||||
struct pcb * const pcb = &l->l_addr->u_pcb;
|
||||
register_t msr = tf->fixreg[OPC_MTMSR_REG(opcode)];
|
||||
|
||||
/*
|
||||
* Don't let the user muck with bits he's not allowed to.
|
||||
*/
|
||||
if (!PSL_USEROK_P(msr))
|
||||
return 0;
|
||||
/*
|
||||
* For now, only update the FP exception mode.
|
||||
*/
|
||||
pcb->pcb_flags &= ~(PSL_FE0|PSL_FE1);
|
||||
pcb->pcb_flags |= msr & (PSL_FE0|PSL_FE1);
|
||||
/*
|
||||
* If we think we have the FPU, update SRR1 too. If we're
|
||||
* wrong userret() will take care of it.
|
||||
*/
|
||||
if (tf->srr1 & PSL_FP) {
|
||||
tf->srr1 &= ~(PSL_FE0|PSL_FE1);
|
||||
tf->srr1 |= msr & (PSL_FE0|PSL_FE1);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
copyinstr(const void *udaddr, void *kaddr, size_t len, size_t *done)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user