summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authornwhitehorn <nwhitehorn@FreeBSD.org>2013-11-17 15:12:03 +0000
committernwhitehorn <nwhitehorn@FreeBSD.org>2013-11-17 15:12:03 +0000
commitf754a8eebe1b02160a6c87a32d19015174ff2eca (patch)
treefbfd6f79ff61342c3b3e402c171476bbcdc018a3
parent6f96364448a360b6b6d7cc9c732a441a15144bcc (diff)
downloadFreeBSD-src-f754a8eebe1b02160a6c87a32d19015174ff2eca.zip
FreeBSD-src-f754a8eebe1b02160a6c87a32d19015174ff2eca.tar.gz
Unify handling of illegal instruction faults between AIM and Book-E. This
allows FPU emulation on AIM as well as providing support for the mfpvr and lwsync instructions from userland on e500 cores. lwsync, in particular, is required for many C++ programs to work correctly. MFC after: 1 week
-rw-r--r--sys/powerpc/aim/trap.c25
-rw-r--r--sys/powerpc/booke/trap.c17
-rw-r--r--sys/powerpc/include/trap.h2
-rw-r--r--sys/powerpc/powerpc/exec_machdep.c38
4 files changed, 44 insertions, 38 deletions
diff --git a/sys/powerpc/aim/trap.c b/sys/powerpc/aim/trap.c
index 922412f..a59bd74 100644
--- a/sys/powerpc/aim/trap.c
+++ b/sys/powerpc/aim/trap.c
@@ -80,7 +80,6 @@ static void printtrap(u_int vector, struct trapframe *frame, int isfatal,
int user);
static int trap_pfault(struct trapframe *frame, int user);
static int fix_unaligned(struct thread *td, struct trapframe *frame);
-static int ppc_instr_emulate(struct trapframe *frame);
static int handle_onfault(struct trapframe *frame);
static void syscall(struct trapframe *frame);
@@ -292,10 +291,9 @@ trap(struct trapframe *frame)
}
#endif
sig = SIGTRAP;
- } else if (ppc_instr_emulate(frame) == 0)
- frame->srr0 += 4;
- else
- sig = SIGILL;
+ } else {
+ sig = ppc_instr_emulate(frame, td->td_pcb);
+ }
break;
default:
@@ -800,20 +798,3 @@ fix_unaligned(struct thread *td, struct trapframe *frame)
return -1;
}
-static int
-ppc_instr_emulate(struct trapframe *frame)
-{
- uint32_t instr;
- int reg;
-
- instr = fuword32((void *)frame->srr0);
-
- if ((instr & 0xfc1fffff) == 0x7c1f42a6) { /* mfpvr */
- reg = (instr & ~0xfc1fffff) >> 21;
- frame->fixreg[reg] = mfpvr();
- return (0);
- }
-
- return (-1);
-}
-
diff --git a/sys/powerpc/booke/trap.c b/sys/powerpc/booke/trap.c
index 72c4f47..dc84ede 100644
--- a/sys/powerpc/booke/trap.c
+++ b/sys/powerpc/booke/trap.c
@@ -71,10 +71,6 @@ __FBSDID("$FreeBSD$");
#include <machine/trap.h>
#include <machine/spr.h>
-#ifdef FPU_EMU
-#include <powerpc/fpu/fpu_extern.h>
-#endif
-
#define FAULTBUF_LR 0
#define FAULTBUF_R1 1
#define FAULTBUF_R2 2
@@ -193,18 +189,7 @@ trap(struct trapframe *frame)
break;
case EXC_PGM: /* Program exception */
-#ifdef FPU_EMU
- if (!(td->td_pcb->pcb_flags & PCB_FPREGS)) {
- bzero(&td->td_pcb->pcb_fpu,
- sizeof(td->td_pcb->pcb_fpu));
- td->td_pcb->pcb_flags |= PCB_FPREGS;
- }
- sig = fpu_emulate(frame,
- (struct fpreg *)&td->td_pcb->pcb_fpu);
-#else
- /* XXX SIGILL for non-trap instructions. */
- sig = SIGTRAP;
-#endif
+ sig = ppc_instr_emulate(frame, td->td_pcb);
break;
default:
diff --git a/sys/powerpc/include/trap.h b/sys/powerpc/include/trap.h
index d8462cf..89f5966 100644
--- a/sys/powerpc/include/trap.h
+++ b/sys/powerpc/include/trap.h
@@ -122,7 +122,9 @@
#ifndef LOCORE
struct trapframe;
+struct pcb;
void trap(struct trapframe *);
+int ppc_instr_emulate(struct trapframe *, struct pcb *);
#endif
#endif /* _POWERPC_TRAP_H_ */
diff --git a/sys/powerpc/powerpc/exec_machdep.c b/sys/powerpc/powerpc/exec_machdep.c
index 4b4be6c..acacb3d 100644
--- a/sys/powerpc/powerpc/exec_machdep.c
+++ b/sys/powerpc/powerpc/exec_machdep.c
@@ -58,6 +58,7 @@
__FBSDID("$FreeBSD$");
#include "opt_compat.h"
+#include "opt_fpu_emu.h"
#include <sys/param.h>
#include <sys/proc.h>
@@ -92,6 +93,10 @@ __FBSDID("$FreeBSD$");
#include <machine/trap.h>
#include <machine/vmparam.h>
+#ifdef FPU_EMU
+#include <powerpc/fpu/fpu_extern.h>
+#endif
+
#ifdef COMPAT_FREEBSD32
#include <compat/freebsd32/freebsd32_signal.h>
#include <compat/freebsd32/freebsd32_util.h>
@@ -1038,3 +1043,36 @@ cpu_set_upcall_kse(struct thread *td, void (*entry)(void *), void *arg,
td->td_retval[1] = 0;
}
+int
+ppc_instr_emulate(struct trapframe *frame, struct pcb *pcb)
+{
+ uint32_t instr;
+ int reg, sig;
+
+ instr = fuword32((void *)frame->srr0);
+ sig = SIGILL;
+
+ if ((instr & 0xfc1fffff) == 0x7c1f42a6) { /* mfpvr */
+ reg = (instr & ~0xfc1fffff) >> 21;
+ frame->fixreg[reg] = mfpvr();
+ frame->srr0 += 4;
+ return (0);
+ }
+
+ if ((instr & 0xfc000ffe) == 0x7c0004ac) { /* various sync */
+ powerpc_sync(); /* Do a heavy-weight sync */
+ frame->srr0 += 4;
+ return (0);
+ }
+
+#ifdef FPU_EMU
+ if (!(pcb->pcb_flags & PCB_FPREGS)) {
+ bzero(&pcb->pcb_fpu, sizeof(pcb->pcb_fpu));
+ pcb->pcb_flags |= PCB_FPREGS;
+ }
+ sig = fpu_emulate(frame, (struct fpreg *)&pcb->pcb_fpu);
+#endif
+
+ return (sig);
+}
+
OpenPOWER on IntegriCloud