Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e8a496ac authored by Suresh Siddha's avatar Suresh Siddha Committed by Thomas Gleixner
Browse files

x86: fix broken math-emu with lazy allocation of fpu area



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: default avatarSuresh Siddha <suresh.b.siddha@intel.com>
Cc: hpa@zytor.com
Cc: mingo@elte.hu
Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
parent 5c1ea082
Loading
Loading
Loading
Loading
+29 −15
Original line number Diff line number Diff line
@@ -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
@@ -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;
	}
@@ -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;

@@ -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,
@@ -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);
@@ -474,10 +488,9 @@ static int restore_i387_fxsave(struct _fpstate_ia32 __user *buf)
int restore_i387_ia32(struct _fpstate_ia32 __user *buf)
{
	int err;

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

	if (HAVE_HWFP)
		clear_fpu(tsk);

	if (!used_math()) {
@@ -486,6 +499,7 @@ int restore_i387_ia32(struct _fpstate_ia32 __user *buf)
			return err;
	}

	if (HAVE_HWFP) {
		if (cpu_has_fxsr)
			err = restore_i387_fxsave(buf);
		else
+8 −5
Original line number Diff line number Diff line
@@ -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"
@@ -146,6 +147,13 @@ 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");
@@ -153,11 +161,6 @@ asmlinkage void math_emulate(long arg)
	RE_ENTRANT_CHECK_ON;
#endif /* RE_ENTRANT_CHECKING */

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

	SETUP_DATA_AREA(arg);

	FPU_ORIG_EIP = FPU_EIP;
+2 −0
Original line number Diff line number Diff line
@@ -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");