Skip to content

Commit

Permalink
x86: fix broken math-emu with lazy allocation of fpu area
Browse files Browse the repository at this point in the history
Fix the math emulation that got broken with the recent lazy allocation of FPU
area. init_fpu() need to be added for the math-emulation path aswell
for the FPU area allocation.

math emulation enabled kernel booted fine with this, in the presence
of "no387 nofxsr" boot param.

Signed-off-by: Suresh Siddha <suresh.b.siddha@intel.com>
Cc: hpa@zytor.com
Cc: mingo@elte.hu
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
  • Loading branch information
Suresh Siddha authored and Thomas Gleixner committed Jun 4, 2008
1 parent 5c1ea08 commit e8a496a
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 20 deletions.
44 changes: 29 additions & 15 deletions arch/x86/kernel/i387.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,11 @@ void __cpuinit mxcsr_feature_mask_init(void)

void __init init_thread_xstate(void)
{
if (!HAVE_HWFP) {
xstate_size = sizeof(struct i387_soft_struct);
return;
}

if (cpu_has_fxsr)
xstate_size = sizeof(struct i387_fxsave_struct);
#ifdef CONFIG_X86_32
Expand Down Expand Up @@ -94,7 +99,7 @@ void __cpuinit fpu_init(void)
int init_fpu(struct task_struct *tsk)
{
if (tsk_used_math(tsk)) {
if (tsk == current)
if (HAVE_HWFP && tsk == current)
unlazy_fpu(tsk);
return 0;
}
Expand All @@ -109,6 +114,15 @@ int init_fpu(struct task_struct *tsk)
return -ENOMEM;
}

#ifdef CONFIG_X86_32
if (!HAVE_HWFP) {
memset(tsk->thread.xstate, 0, xstate_size);
finit();
set_stopped_child_used_math(tsk);
return 0;
}
#endif

if (cpu_has_fxsr) {
struct i387_fxsave_struct *fx = &tsk->thread.xstate->fxsave;

Expand Down Expand Up @@ -330,13 +344,13 @@ int fpregs_get(struct task_struct *target, const struct user_regset *regset,
struct user_i387_ia32_struct env;
int ret;

if (!HAVE_HWFP)
return fpregs_soft_get(target, regset, pos, count, kbuf, ubuf);

ret = init_fpu(target);
if (ret)
return ret;

if (!HAVE_HWFP)
return fpregs_soft_get(target, regset, pos, count, kbuf, ubuf);

if (!cpu_has_fxsr) {
return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
&target->thread.xstate->fsave, 0,
Expand All @@ -360,15 +374,15 @@ int fpregs_set(struct task_struct *target, const struct user_regset *regset,
struct user_i387_ia32_struct env;
int ret;

if (!HAVE_HWFP)
return fpregs_soft_set(target, regset, pos, count, kbuf, ubuf);

ret = init_fpu(target);
if (ret)
return ret;

set_stopped_child_used_math(target);

if (!HAVE_HWFP)
return fpregs_soft_set(target, regset, pos, count, kbuf, ubuf);

if (!cpu_has_fxsr) {
return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
&target->thread.xstate->fsave, 0, -1);
Expand Down Expand Up @@ -474,18 +488,18 @@ static int restore_i387_fxsave(struct _fpstate_ia32 __user *buf)
int restore_i387_ia32(struct _fpstate_ia32 __user *buf)
{
int err;
struct task_struct *tsk = current;

if (HAVE_HWFP) {
struct task_struct *tsk = current;

if (HAVE_HWFP)
clear_fpu(tsk);

if (!used_math()) {
err = init_fpu(tsk);
if (err)
return err;
}
if (!used_math()) {
err = init_fpu(tsk);
if (err)
return err;
}

if (HAVE_HWFP) {
if (cpu_has_fxsr)
err = restore_i387_fxsave(buf);
else
Expand Down
13 changes: 8 additions & 5 deletions arch/x86/math-emu/fpu_entry.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include <asm/uaccess.h>
#include <asm/desc.h>
#include <asm/user.h>
#include <asm/i387.h>

#include "fpu_system.h"
#include "fpu_emu.h"
Expand Down Expand Up @@ -146,18 +147,20 @@ asmlinkage void math_emulate(long arg)
unsigned long code_limit = 0; /* Initialized to stop compiler warnings */
struct desc_struct code_descriptor;

if (!used_math()) {
if (init_fpu(current)) {
do_group_exit(SIGKILL);
return;
}
}

#ifdef RE_ENTRANT_CHECKING
if (emulating) {
printk("ERROR: wm-FPU-emu is not RE-ENTRANT!\n");
}
RE_ENTRANT_CHECK_ON;
#endif /* RE_ENTRANT_CHECKING */

if (!used_math()) {
finit();
set_used_math();
}

SETUP_DATA_AREA(arg);

FPU_ORIG_EIP = FPU_EIP;
Expand Down
2 changes: 2 additions & 0 deletions include/asm-x86/i387.h
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,8 @@ static inline int restore_i387(struct _fpstate __user *buf)

#else /* CONFIG_X86_32 */

extern void finit(void);

static inline void tolerant_fwait(void)
{
asm volatile("fnclex ; fwait");
Expand Down

0 comments on commit e8a496a

Please sign in to comment.