diff options
author | Justin Hibbits <jhibbits@FreeBSD.org> | 2019-04-03 04:01:08 +0000 |
---|---|---|
committer | Justin Hibbits <jhibbits@FreeBSD.org> | 2019-04-03 04:01:08 +0000 |
commit | 62c7ea1f1d3693ec35e78ce16f0c0c260100b1ce (patch) | |
tree | 50f32fca027f243e1a6d0eb0d0bd18f6d747ef6f | |
parent | b0fefb25c558179e9f9c7f0d375c6a03fb567eb9 (diff) |
powerpc: Allow emulating optional FPU instructions on CPUs with an FPU
The e5500 has an FPU, but lacks the optional fsqrt instruction. This
instruction gets emulated in the kernel, but the emulation uses stale data,
from the last switch out, and does not return the result of the operation
immediately. Fix both of these conditions by saving and restoring the FPRs
around the emulation point.
MFC after: 1 week
MFC with: r345829
Notes
Notes:
svn path=/head/; revision=345831
-rw-r--r-- | sys/powerpc/include/trap.h | 4 | ||||
-rw-r--r-- | sys/powerpc/powerpc/exec_machdep.c | 9 | ||||
-rw-r--r-- | sys/powerpc/powerpc/trap.c | 2 |
3 files changed, 10 insertions, 5 deletions
diff --git a/sys/powerpc/include/trap.h b/sys/powerpc/include/trap.h index fc927419db68..5017a7535d29 100644 --- a/sys/powerpc/include/trap.h +++ b/sys/powerpc/include/trap.h @@ -152,10 +152,10 @@ #ifndef LOCORE struct trapframe; -struct pcb; +struct thread; extern int (*hmi_handler)(struct trapframe *); void trap(struct trapframe *); -int ppc_instr_emulate(struct trapframe *, struct pcb *); +int ppc_instr_emulate(struct trapframe *, struct thread *); #endif #endif /* _POWERPC_TRAP_H_ */ diff --git a/sys/powerpc/powerpc/exec_machdep.c b/sys/powerpc/powerpc/exec_machdep.c index 3ae1640b2642..0ce6f0e26869 100644 --- a/sys/powerpc/powerpc/exec_machdep.c +++ b/sys/powerpc/powerpc/exec_machdep.c @@ -1081,8 +1081,9 @@ emulate_mtspr(int spr, int reg, struct trapframe *frame){ #define XFX 0xFC0007FF int -ppc_instr_emulate(struct trapframe *frame, struct pcb *pcb) +ppc_instr_emulate(struct trapframe *frame, struct thread *td) { + struct pcb *pcb; uint32_t instr; int reg, sig; int rs, spr; @@ -1109,12 +1110,16 @@ ppc_instr_emulate(struct trapframe *frame, struct pcb *pcb) return (0); } + pcb = td->td_pcb; #ifdef FPU_EMU if (!(pcb->pcb_flags & PCB_FPREGS)) { bzero(&pcb->pcb_fpu, sizeof(pcb->pcb_fpu)); pcb->pcb_flags |= PCB_FPREGS; - } + } else if (pcb->pcb_flags & PCB_FPU) + save_fpu(td); sig = fpu_emulate(frame, &pcb->pcb_fpu); + if ((sig == 0 || sig == SIGFPE) && pcb->pcb_flags & PCB_FPU) + enable_fpu(td); #endif if (sig == SIGILL) { if (pcb->pcb_lastill != frame->srr0) { diff --git a/sys/powerpc/powerpc/trap.c b/sys/powerpc/powerpc/trap.c index 111e69a7b32e..2a63f47b71a1 100644 --- a/sys/powerpc/powerpc/trap.c +++ b/sys/powerpc/powerpc/trap.c @@ -363,7 +363,7 @@ trap(struct trapframe *frame) sig = SIGTRAP; ucode = TRAP_BRKPT; } else { - sig = ppc_instr_emulate(frame, td->td_pcb); + sig = ppc_instr_emulate(frame, td); if (sig == SIGILL) { if (frame->srr1 & EXC_PGM_PRIV) ucode = ILL_PRVOPC; |