Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 1 addition & 9 deletions sys/powerpc/include/pcb.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,16 +66,8 @@ struct pcb {
#define PCB_VECREGS 0x200 /* Process had Altivec registers initialized */
struct fpu {
union {
#if _BYTE_ORDER == _BIG_ENDIAN
double fpr;
uint32_t vsr[4];
#else
uint32_t vsr[4];
struct {
double padding;
double fpr;
};
#endif
double fpr;
} fpr[32];
double fpscr; /* FPSCR stored as double for easier access */
} pcb_fpu; /* Floating point processor */
Expand Down
2 changes: 2 additions & 0 deletions sys/powerpc/include/ucontext.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ typedef struct __mcontext {
int mc_flags;
#define _MC_FP_VALID 0x01
#define _MC_AV_VALID 0x02
#define _MC_VS_VALID 0x04
int mc_onstack; /* saved onstack flag */
int mc_len; /* sizeof(__mcontext) */
__uint64_t mc_avec[32*2]; /* vector register file */
Expand All @@ -56,6 +57,7 @@ typedef struct __mcontext32 {
int mc_flags;
#define _MC_FP_VALID 0x01
#define _MC_AV_VALID 0x02
#define _MC_VS_VALID 0x04
int mc_onstack; /* saved onstack flag */
int mc_len; /* sizeof(__mcontext) */
uint64_t mc_avec[32*2]; /* vector register file */
Expand Down
39 changes: 27 additions & 12 deletions sys/powerpc/powerpc/exec_machdep.c
Original file line number Diff line number Diff line change
Expand Up @@ -214,10 +214,10 @@ sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
sfpsize = sizeof(sf);
#ifdef __powerpc64__
/*
* 64-bit PPC defines a 288 byte scratch region
* below the stack.
* 64-bit PPC defines a 512 byte red zone below
* the existing stack (ELF ABI v2 §2.2.2.4)
*/
rndfsize = 288 + roundup(sizeof(sf), 48);
rndfsize = 512 + roundup(sizeof(sf), 48);
#else
rndfsize = roundup(sizeof(sf), 16);
#endif
Expand Down Expand Up @@ -349,13 +349,6 @@ sys_sigreturn(struct thread *td, struct sigreturn_args *uap)
if (error != 0)
return (error);

/*
* Save FPU state if needed. User may have changed it on
* signal handler
*/
if (uc.uc_mcontext.mc_srr1 & PSL_FP)
save_fpu(td);

kern_sigprocmask(td, SIG_SETMASK, &uc.uc_sigmask, NULL, 0);

CTR3(KTR_SIG, "sigreturn: return td=%p pc=%#x sp=%#x",
Expand Down Expand Up @@ -432,6 +425,7 @@ grab_mcontext(struct thread *td, mcontext_t *mcp, int flags)
}

if (pcb->pcb_flags & PCB_VSX) {
mcp->mc_flags |= _MC_VS_VALID;
for (i = 0; i < 32; i++)
memcpy(&mcp->mc_vsxfpreg[i],
&pcb->pcb_fpu.fpr[i].vsr[2], sizeof(double));
Expand Down Expand Up @@ -481,6 +475,7 @@ set_mcontext(struct thread *td, mcontext_t *mcp)
struct pcb *pcb;
struct trapframe *tf;
register_t tls;
register_t msr;
int i;

pcb = td->td_pcb;
Expand Down Expand Up @@ -531,6 +526,22 @@ set_mcontext(struct thread *td, mcontext_t *mcp)
tf->srr1 &= ~(PSL_FP | PSL_VSX | PSL_VEC);
pcb->pcb_flags &= ~(PCB_FPU | PCB_VSX | PCB_VEC);

/*
* Ensure the FPU is also disabled in hardware.
*
* Without this, it's possible for the register reload to fail if we
* don't switch to a FPU disabled context before resuming the original
* thread. Specifically, if the FPU/VSX unavailable exception is never
* hit, then whatever data is still in the FP/VSX registers when
* sigresume is callled will used by the resumed thread, instead of the
* previously saved data from the mcontext.
*/
critical_enter();
msr = mfmsr() & ~(PSL_FP | PSL_VSX | PSL_VEC);
isync();
mtmsr(msr);
critical_exit();

if (mcp->mc_flags & _MC_FP_VALID) {
/* enable_fpu() will happen lazily on a fault */
pcb->pcb_flags |= PCB_FPREGS;
Expand All @@ -539,8 +550,12 @@ set_mcontext(struct thread *td, mcontext_t *mcp)
for (i = 0; i < 32; i++) {
memcpy(&pcb->pcb_fpu.fpr[i].fpr, &mcp->mc_fpreg[i],
sizeof(double));
memcpy(&pcb->pcb_fpu.fpr[i].vsr[2],
&mcp->mc_vsxfpreg[i], sizeof(double));
}
if (mcp->mc_flags & _MC_VS_VALID) {
for (i = 0; i < 32; i++) {
memcpy(&pcb->pcb_fpu.fpr[i].vsr[2],
&mcp->mc_vsxfpreg[i], sizeof(double));
}
}
}

Expand Down
30 changes: 26 additions & 4 deletions sys/powerpc/powerpc/fpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,19 @@ save_fpu_int(struct thread *td)
* Save the floating-point registers and FPSCR to the PCB
*/
if (pcb->pcb_flags & PCB_VSX) {
#define SFP(n) __asm ("stxvw4x " #n ", 0,%0" \
#if _BYTE_ORDER == _BIG_ENDIAN
#define SFP(n) __asm("stxvw4x " #n ", 0,%0" \
:: "b"(&pcb->pcb_fpu.fpr[n]));
#else
/*
* stxvw2x will swap words within the FP double word on LE systems,
* leading to corruption if VSX is used to store state and FP is
* subsequently used to restore state.
* Use stxvd2x instead.
*/
#define SFP(n) __asm("stxvd2x " #n ", 0,%0" \
:: "b"(&pcb->pcb_fpu.fpr[n]));
#endif
SFP(0); SFP(1); SFP(2); SFP(3);
SFP(4); SFP(5); SFP(6); SFP(7);
SFP(8); SFP(9); SFP(10); SFP(11);
Expand All @@ -76,7 +87,7 @@ save_fpu_int(struct thread *td)
SFP(28); SFP(29); SFP(30); SFP(31);
#undef SFP
} else {
#define SFP(n) __asm ("stfd " #n ", 0(%0)" \
#define SFP(n) __asm("stfd " #n ", 0(%0)" \
:: "b"(&pcb->pcb_fpu.fpr[n].fpr));
SFP(0); SFP(1); SFP(2); SFP(3);
SFP(4); SFP(5); SFP(6); SFP(7);
Expand Down Expand Up @@ -149,8 +160,19 @@ enable_fpu(struct thread *td)
:: "b"(&pcb->pcb_fpu.fpscr));

if (pcb->pcb_flags & PCB_VSX) {
#define LFP(n) __asm ("lxvw4x " #n ", 0,%0" \
#if _BYTE_ORDER == _BIG_ENDIAN
#define LFP(n) __asm("lxvw4x " #n ", 0,%0" \
:: "b"(&pcb->pcb_fpu.fpr[n]));
#else
/*
* lxvw4x will swap words within the FP double word on LE systems,
* leading to corruption if FP is used to store state and VSX is
* subsequently used to restore state.
* Use lxvd2x instead.
*/
#define LFP(n) __asm("lxvd2x " #n ", 0,%0" \
:: "b"(&pcb->pcb_fpu.fpr[n]));
#endif
LFP(0); LFP(1); LFP(2); LFP(3);
LFP(4); LFP(5); LFP(6); LFP(7);
LFP(8); LFP(9); LFP(10); LFP(11);
Expand All @@ -161,7 +183,7 @@ enable_fpu(struct thread *td)
LFP(28); LFP(29); LFP(30); LFP(31);
#undef LFP
} else {
#define LFP(n) __asm ("lfd " #n ", 0(%0)" \
#define LFP(n) __asm("lfd " #n ", 0(%0)" \
:: "b"(&pcb->pcb_fpu.fpr[n].fpr));
LFP(0); LFP(1); LFP(2); LFP(3);
LFP(4); LFP(5); LFP(6); LFP(7);
Expand Down