Commit af59e218 authored by Anton Blanchard's avatar Anton Blanchard

ppc64: Allow user to change MSR_FE0 and MSR_FE1 - from ppc32

parent 220d2581
......@@ -1421,7 +1421,7 @@ _STATIC(load_up_fpu)
addi r4,r4,THREAD /* want THREAD of last_task_used_math */
SAVE_32FPRS(0, r4)
mffs fr0
stfd fr0,THREAD_FPSCR-4(r4)
stfd fr0,THREAD_FPSCR(r4)
ld r5,PT_REGS(r4)
ld r4,_MSR-STACK_FRAME_OVERHEAD(r5)
li r20,MSR_FP|MSR_FE0|MSR_FE1
......@@ -1430,10 +1430,12 @@ _STATIC(load_up_fpu)
1:
#endif /* CONFIG_SMP */
/* enable use of FP after return */
ori r23,r23,MSR_FP|MSR_FE0|MSR_FE1
ld r4, PACACURRENT(r13)
ld r4,PACACURRENT(r13)
addi r5,r4,THREAD /* Get THREAD */
lfd fr0,THREAD_FPSCR-4(r5)
lwz r4,THREAD_FPEXC_MODE(r5)
ori r23,r23,MSR_FP
or r23,r23,r4
lfd fr0,THREAD_FPSCR(r5)
mtfsf 0xff,fr0
REST_32FPRS(0, r5)
#ifndef CONFIG_SMP
......@@ -1476,7 +1478,7 @@ _GLOBAL(giveup_fpu)
cmpi 0,r5,0
SAVE_32FPRS(0, r3)
mffs fr0
stfd fr0,THREAD_FPSCR-4(r3)
stfd fr0,THREAD_FPSCR(r3)
beq 1f
ld r4,_MSR-STACK_FRAME_OVERHEAD(r5)
li r3,MSR_FP|MSR_FE0|MSR_FE1
......
......@@ -460,21 +460,21 @@ _GLOBAL(_get_HID0)
blr
_GLOBAL(cvt_fd)
lfd 0,-4(r5) /* load up fpscr value */
lfd 0,0(r5) /* load up fpscr value */
mtfsf 0xff,0
lfs 0,0(r3)
stfd 0,0(r4)
mffs 0 /* save new fpscr value */
stfd 0,-4(r5)
stfd 0,0(r5)
blr
_GLOBAL(cvt_df)
lfd 0,-4(r5) /* load up fpscr value */
lfd 0,0(r5) /* load up fpscr value */
mtfsf 0xff,0
lfd 0,0(r3)
stfs 0,0(r4)
mffs 0 /* save new fpscr value */
stfd 0,-4(r5)
stfd 0,0(r5)
blr
/*
......
......@@ -51,6 +51,7 @@ main(void)
/* task_struct->thread */
DEFINE(THREAD, offsetof(struct task_struct, thread));
DEFINE(PT_REGS, offsetof(struct thread_struct, regs));
DEFINE(THREAD_FPEXC_MODE, offsetof(struct thread_struct, fpexc_mode));
DEFINE(THREAD_FPR0, offsetof(struct thread_struct, fpr[0]));
DEFINE(THREAD_FPSCR, offsetof(struct thread_struct, fpscr));
DEFINE(KSP, offsetof(struct thread_struct, ksp));
......
......@@ -163,8 +163,7 @@ release_thread(struct task_struct *t)
*/
int
copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
unsigned long unused,
struct task_struct *p, struct pt_regs *regs)
unsigned long unused, struct task_struct *p, struct pt_regs *regs)
{
struct pt_regs *childregs, *kregs;
extern void ret_from_fork(void);
......@@ -208,17 +207,6 @@ copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
*/
kregs->nip = *((unsigned long *)ret_from_fork);
/*
* copy fpu info - assume lazy fpu switch now always
* -- Cort
*/
if (regs->msr & MSR_FP) {
giveup_fpu(current);
childregs->msr &= ~(MSR_FP | MSR_FE0 | MSR_FE1);
}
memcpy(&p->thread.fpr, &current->thread.fpr, sizeof(p->thread.fpr));
p->thread.fpscr = current->thread.fpscr;
return 0;
}
......@@ -247,10 +235,38 @@ void start_thread(struct pt_regs *regs, unsigned long nip, unsigned long sp)
current->thread.fpscr = 0;
}
/* XXX temporary */
#define PR_FP_EXC_PRECISE 3 /* precise exception mode */
int set_fpexc_mode(struct task_struct *tsk, unsigned int val)
{
struct pt_regs *regs = tsk->thread.regs;
if (val > PR_FP_EXC_PRECISE)
return -EINVAL;
tsk->thread.fpexc_mode = __pack_fe01(val);
if (regs != NULL && (regs->msr & MSR_FP) != 0)
regs->msr = (regs->msr & ~(MSR_FE0|MSR_FE1))
| tsk->thread.fpexc_mode;
return 0;
}
int get_fpexc_mode(struct task_struct *tsk, unsigned long adr)
{
unsigned int val;
val = __unpack_fe01(tsk->thread.fpexc_mode);
return put_user(val, (unsigned int *) adr);
}
int sys_clone(int p1, int p2, int p3, int p4, int p5, int p6,
struct pt_regs *regs)
{
struct task_struct *p;
if (regs->msr & MSR_FP)
giveup_fpu(current);
p = do_fork(p1 & ~CLONE_IDLETASK, regs->gpr[1], regs, 0);
return IS_ERR(p) ? PTR_ERR(p) : p->pid;
}
......@@ -259,6 +275,10 @@ int sys_fork(int p1, int p2, int p3, int p4, int p5, int p6,
struct pt_regs *regs)
{
struct task_struct *p;
if (regs->msr & MSR_FP)
giveup_fpu(current);
p = do_fork(SIGCHLD, regs->gpr[1], regs, 0);
return IS_ERR(p) ? PTR_ERR(p) : p->pid;
}
......@@ -267,6 +287,10 @@ int sys_vfork(int p1, int p2, int p3, int p4, int p5, int p6,
struct pt_regs *regs)
{
struct task_struct *p;
if (regs->msr & MSR_FP)
giveup_fpu(current);
p = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->gpr[1], regs, 0);
return IS_ERR(p) ? PTR_ERR(p) : p->pid;
}
......
......@@ -177,10 +177,7 @@ int sys32_ptrace(long request, long pid, unsigned long addr, unsigned long data)
if (numReg >= PT_FPR0) {
if (child->thread.regs->msr & MSR_FP)
giveup_fpu(child);
if (numReg == PT_FPSCR)
tmp = ((unsigned int *)child->thread.fpscr);
else
tmp = ((unsigned long int *)child->thread.fpr)[numReg - PT_FPR0];
tmp = ((unsigned long int *)child->thread.fpr)[numReg - PT_FPR0];
} else { /* register within PT_REGS struct */
tmp = get_reg(child, numReg);
}
......
......@@ -55,7 +55,19 @@
* able to continue 'til the next breakpoint from within the signal
* handler, even if the handler returns.
*/
#if 0
#define MSR_USERCHANGE (MSR_FE0 | MSR_FE1)
#else
/*
* glibc tries to set FE0/FE1 via a signal handler. Since it only ever
* sets both bits and this is the default setting we now disable this
* behaviour. This is done to insure the new prctl which alters FE0/FE1 does
* not get overriden by glibc. Setting and clearing FE0/FE1 via signal
* handler has always been bogus since load_up_fpu used to set FE0/FE1
* unconditionally.
*/
#define MSR_USERCHANGE 0
#endif
/*
* When we have signals to deliver, we set up on the
......
......@@ -39,7 +39,19 @@
* able to continue 'til the next breakpoint from within the signal
* handler, even if the handler returns.
*/
#if 0
#define MSR_USERCHANGE (MSR_FE0 | MSR_FE1)
#else
/*
* glibc tries to set FE0/FE1 via a signal handler. Since it only ever
* sets both bits and this is the default setting we now disable this
* behaviour. This is done to insure the new prctl which alters FE0/FE1 does
* not get overriden by glibc. Setting and clearing FE0/FE1 via signal
* handler has always been bogus since load_up_fpu used to set FE0/FE1
* unconditionally.
*/
#define MSR_USERCHANGE 0
#endif
struct timespec32 {
s32 tv_sec;
......
......@@ -240,14 +240,12 @@ InstructionBreakpointException(struct pt_regs *regs)
static void parse_fpe(struct pt_regs *regs)
{
siginfo_t info;
unsigned int *tmp;
unsigned int fpscr;
unsigned long fpscr;
if (regs->msr & MSR_FP)
giveup_fpu(current);
tmp = &current->thread.fpscr;
fpscr = *tmp;
fpscr = current->thread.fpscr;
/* Invalid operation */
if ((fpscr & FPSCR_VE) && (fpscr & FPSCR_VX))
......
......@@ -652,6 +652,7 @@ struct thread_struct {
mm_segment_t fs; /* for get_fs() validation */
double fpr[32]; /* Complete floating point set */
unsigned long fpscr; /* Floating point status */
unsigned int fpexc_mode; /* Floating-point exception mode */
};
#define INIT_SP (sizeof(init_stack) + (unsigned long) &init_stack)
......@@ -661,7 +662,8 @@ struct thread_struct {
(struct pt_regs *)INIT_SP - 1, /* regs */ \
KERNEL_DS, /*fs*/ \
{0}, /* fpr */ \
0 /* fpscr */ \
0, /* fpscr */ \
MSR_FE0|MSR_FE1, /* fpexc_mode */ \
}
/*
......@@ -689,6 +691,23 @@ unsigned long get_wchan(struct task_struct *p);
#define KSTK_EIP(tsk) ((tsk)->thread.regs? (tsk)->thread.regs->nip: 0)
#define KSTK_ESP(tsk) ((tsk)->thread.regs? (tsk)->thread.regs->gpr[1]: 0)
/* Get/set floating-point exception mode */
#define GET_FPEXC_CTL(tsk, adr) get_fpexc_mode((tsk), (adr))
#define SET_FPEXC_CTL(tsk, val) set_fpexc_mode((tsk), (val))
extern int get_fpexc_mode(struct task_struct *tsk, unsigned long adr);
extern int set_fpexc_mode(struct task_struct *tsk, unsigned int val);
static inline unsigned int __unpack_fe01(unsigned long msr_bits)
{
return ((msr_bits & MSR_FE0) >> 10) | ((msr_bits & MSR_FE1) >> 8);
}
static inline unsigned int __pack_fe01(unsigned int fpmode)
{
return ((fpmode << 10) & MSR_FE0) | ((fpmode << 8) & MSR_FE1);
}
#define cpu_relax() barrier()
/*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment