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
This commit is contained in:
Nathan Whitehorn 2013-11-17 15:12:03 +00:00
parent a3985bdd12
commit e537388b84
4 changed files with 44 additions and 38 deletions

View File

@ -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);
}

View File

@ -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:

View File

@ -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_ */

View File

@ -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);
}