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

Commit 41d59102 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
* 'x86-fpu-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip:
  x86, fpu: Use static_cpu_has() to implement use_xsave()
  x86: Add new static_cpu_has() function using alternatives
  x86, fpu: Use the proper asm constraint in use_xsave()
  x86, fpu: Unbreak FPU emulation
  x86: Introduce 'struct fpu' and related API
  x86: Eliminate TS_XSAVE
  x86-32: Don't set ignore_fpu_irq in simd exception
  x86: Merge kernel_math_error() into math_error()
  x86: Merge simd_math_error() into math_error()
  x86-32: Rework cache flush denied handler

Fix trivial conflict in arch/x86/kernel/process.c
parents 3e1dd193 c9775b4c
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -338,6 +338,10 @@ config X86_F00F_BUG
	def_bool y
	depends on M586MMX || M586TSC || M586 || M486 || M386

config X86_INVD_BUG
	def_bool y
	depends on M486 || M386

config X86_WP_WORKS_OK
	def_bool y
	depends on !M386
+57 −0
Original line number Diff line number Diff line
@@ -176,6 +176,7 @@

#if defined(__KERNEL__) && !defined(__ASSEMBLY__)

#include <asm/asm.h>
#include <linux/bitops.h>

extern const char * const x86_cap_flags[NCAPINTS*32];
@@ -284,6 +285,62 @@ extern const char * const x86_power_flags[32];

#endif /* CONFIG_X86_64 */

/*
 * Static testing of CPU features.  Used the same as boot_cpu_has().
 * These are only valid after alternatives have run, but will statically
 * patch the target code for additional performance.
 *
 */
static __always_inline __pure bool __static_cpu_has(u8 bit)
{
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)
		asm goto("1: jmp %l[t_no]\n"
			 "2:\n"
			 ".section .altinstructions,\"a\"\n"
			 _ASM_ALIGN "\n"
			 _ASM_PTR "1b\n"
			 _ASM_PTR "0\n" 	/* no replacement */
			 " .byte %P0\n"		/* feature bit */
			 " .byte 2b - 1b\n"	/* source len */
			 " .byte 0\n"		/* replacement len */
			 " .byte 0xff + 0 - (2b-1b)\n"	/* padding */
			 ".previous\n"
			 : : "i" (bit) : : t_no);
		return true;
	t_no:
		return false;
#else
		u8 flag;
		/* Open-coded due to __stringify() in ALTERNATIVE() */
		asm volatile("1: movb $0,%0\n"
			     "2:\n"
			     ".section .altinstructions,\"a\"\n"
			     _ASM_ALIGN "\n"
			     _ASM_PTR "1b\n"
			     _ASM_PTR "3f\n"
			     " .byte %P1\n"		/* feature bit */
			     " .byte 2b - 1b\n"		/* source len */
			     " .byte 4f - 3f\n"		/* replacement len */
			     " .byte 0xff + (4f-3f) - (2b-1b)\n" /* padding */
			     ".previous\n"
			     ".section .altinstr_replacement,\"ax\"\n"
			     "3: movb $1,%0\n"
			     "4:\n"
			     ".previous\n"
			     : "=qm" (flag) : "i" (bit));
		return flag;
#endif
}

#define static_cpu_has(bit)					\
(								\
	__builtin_constant_p(boot_cpu_has(bit)) ?		\
		boot_cpu_has(bit) :				\
	(__builtin_constant_p(bit) && !((bit) & ~0xff)) ?	\
		__static_cpu_has(bit) :				\
		boot_cpu_has(bit)				\
)

#endif /* defined(__KERNEL__) && !defined(__ASSEMBLY__) */

#endif /* _ASM_X86_CPUFEATURE_H */
+95 −34
Original line number Diff line number Diff line
@@ -16,7 +16,9 @@
#include <linux/kernel_stat.h>
#include <linux/regset.h>
#include <linux/hardirq.h>
#include <linux/slab.h>
#include <asm/asm.h>
#include <asm/cpufeature.h>
#include <asm/processor.h>
#include <asm/sigcontext.h>
#include <asm/user.h>
@@ -56,6 +58,11 @@ extern int restore_i387_xstate_ia32(void __user *buf);

#define X87_FSW_ES (1 << 7)	/* Exception Summary */

static __always_inline __pure bool use_xsave(void)
{
	return static_cpu_has(X86_FEATURE_XSAVE);
}

#ifdef CONFIG_X86_64

/* Ignore delayed exceptions from user space */
@@ -91,15 +98,15 @@ static inline int fxrstor_checking(struct i387_fxsave_struct *fx)
   values. The kernel data segment can be sometimes 0 and sometimes
   new user value. Both should be ok.
   Use the PDA as safe address because it should be already in L1. */
static inline void clear_fpu_state(struct task_struct *tsk)
static inline void fpu_clear(struct fpu *fpu)
{
	struct xsave_struct *xstate = &tsk->thread.xstate->xsave;
	struct i387_fxsave_struct *fx = &tsk->thread.xstate->fxsave;
	struct xsave_struct *xstate = &fpu->state->xsave;
	struct i387_fxsave_struct *fx = &fpu->state->fxsave;

	/*
	 * xsave header may indicate the init state of the FP.
	 */
	if ((task_thread_info(tsk)->status & TS_XSAVE) &&
	if (use_xsave() &&
	    !(xstate->xsave_hdr.xstate_bv & XSTATE_FP))
		return;

@@ -111,6 +118,11 @@ static inline void clear_fpu_state(struct task_struct *tsk)
			  X86_FEATURE_FXSAVE_LEAK);
}

static inline void clear_fpu_state(struct task_struct *tsk)
{
	fpu_clear(&tsk->thread.fpu);
}

static inline int fxsave_user(struct i387_fxsave_struct __user *fx)
{
	int err;
@@ -135,7 +147,7 @@ static inline int fxsave_user(struct i387_fxsave_struct __user *fx)
	return err;
}

static inline void fxsave(struct task_struct *tsk)
static inline void fpu_fxsave(struct fpu *fpu)
{
	/* Using "rex64; fxsave %0" is broken because, if the memory operand
	   uses any extended registers for addressing, a second REX prefix
@@ -145,42 +157,45 @@ static inline void fxsave(struct task_struct *tsk)
	/* Using "fxsaveq %0" would be the ideal choice, but is only supported
	   starting with gas 2.16. */
	__asm__ __volatile__("fxsaveq %0"
			     : "=m" (tsk->thread.xstate->fxsave));
			     : "=m" (fpu->state->fxsave));
#elif 0
	/* Using, as a workaround, the properly prefixed form below isn't
	   accepted by any binutils version so far released, complaining that
	   the same type of prefix is used twice if an extended register is
	   needed for addressing (fix submitted to mainline 2005-11-21). */
	__asm__ __volatile__("rex64/fxsave %0"
			     : "=m" (tsk->thread.xstate->fxsave));
			     : "=m" (fpu->state->fxsave));
#else
	/* This, however, we can work around by forcing the compiler to select
	   an addressing mode that doesn't require extended registers. */
	__asm__ __volatile__("rex64/fxsave (%1)"
			     : "=m" (tsk->thread.xstate->fxsave)
			     : "cdaSDb" (&tsk->thread.xstate->fxsave));
			     : "=m" (fpu->state->fxsave)
			     : "cdaSDb" (&fpu->state->fxsave));
#endif
}

static inline void __save_init_fpu(struct task_struct *tsk)
static inline void fpu_save_init(struct fpu *fpu)
{
	if (task_thread_info(tsk)->status & TS_XSAVE)
		xsave(tsk);
	if (use_xsave())
		fpu_xsave(fpu);
	else
		fxsave(tsk);
		fpu_fxsave(fpu);

	fpu_clear(fpu);
}

	clear_fpu_state(tsk);
static inline void __save_init_fpu(struct task_struct *tsk)
{
	fpu_save_init(&tsk->thread.fpu);
	task_thread_info(tsk)->status &= ~TS_USEDFPU;
}

#else  /* CONFIG_X86_32 */

#ifdef CONFIG_MATH_EMULATION
extern void finit_task(struct task_struct *tsk);
extern void finit_soft_fpu(struct i387_soft_struct *soft);
#else
static inline void finit_task(struct task_struct *tsk)
{
}
static inline void finit_soft_fpu(struct i387_soft_struct *soft) {}
#endif

static inline void tolerant_fwait(void)
@@ -216,13 +231,13 @@ static inline int fxrstor_checking(struct i387_fxsave_struct *fx)
/*
 * These must be called with preempt disabled
 */
static inline void __save_init_fpu(struct task_struct *tsk)
static inline void fpu_save_init(struct fpu *fpu)
{
	if (task_thread_info(tsk)->status & TS_XSAVE) {
		struct xsave_struct *xstate = &tsk->thread.xstate->xsave;
		struct i387_fxsave_struct *fx = &tsk->thread.xstate->fxsave;
	if (use_xsave()) {
		struct xsave_struct *xstate = &fpu->state->xsave;
		struct i387_fxsave_struct *fx = &fpu->state->fxsave;

		xsave(tsk);
		fpu_xsave(fpu);

		/*
		 * xsave header may indicate the init state of the FP.
@@ -246,8 +261,8 @@ static inline void __save_init_fpu(struct task_struct *tsk)
		"fxsave %[fx]\n"
		"bt $7,%[fsw] ; jnc 1f ; fnclex\n1:",
		X86_FEATURE_FXSR,
		[fx] "m" (tsk->thread.xstate->fxsave),
		[fsw] "m" (tsk->thread.xstate->fxsave.swd) : "memory");
		[fx] "m" (fpu->state->fxsave),
		[fsw] "m" (fpu->state->fxsave.swd) : "memory");
clear_state:
	/* AMD K7/K8 CPUs don't save/restore FDP/FIP/FOP unless an exception
	   is pending.  Clear the x87 state here by setting it to fixed
@@ -259,17 +274,34 @@ static inline void __save_init_fpu(struct task_struct *tsk)
		X86_FEATURE_FXSAVE_LEAK,
		[addr] "m" (safe_address));
end:
	;
}

static inline void __save_init_fpu(struct task_struct *tsk)
{
	fpu_save_init(&tsk->thread.fpu);
	task_thread_info(tsk)->status &= ~TS_USEDFPU;
}


#endif	/* CONFIG_X86_64 */

static inline int restore_fpu_checking(struct task_struct *tsk)
static inline int fpu_fxrstor_checking(struct fpu *fpu)
{
	if (task_thread_info(tsk)->status & TS_XSAVE)
		return xrstor_checking(&tsk->thread.xstate->xsave);
	return fxrstor_checking(&fpu->state->fxsave);
}

static inline int fpu_restore_checking(struct fpu *fpu)
{
	if (use_xsave())
		return fpu_xrstor_checking(fpu);
	else
		return fxrstor_checking(&tsk->thread.xstate->fxsave);
		return fpu_fxrstor_checking(fpu);
}

static inline int restore_fpu_checking(struct task_struct *tsk)
{
	return fpu_restore_checking(&tsk->thread.fpu);
}

/*
@@ -397,30 +429,59 @@ static inline void clear_fpu(struct task_struct *tsk)
static inline unsigned short get_fpu_cwd(struct task_struct *tsk)
{
	if (cpu_has_fxsr) {
		return tsk->thread.xstate->fxsave.cwd;
		return tsk->thread.fpu.state->fxsave.cwd;
	} else {
		return (unsigned short)tsk->thread.xstate->fsave.cwd;
		return (unsigned short)tsk->thread.fpu.state->fsave.cwd;
	}
}

static inline unsigned short get_fpu_swd(struct task_struct *tsk)
{
	if (cpu_has_fxsr) {
		return tsk->thread.xstate->fxsave.swd;
		return tsk->thread.fpu.state->fxsave.swd;
	} else {
		return (unsigned short)tsk->thread.xstate->fsave.swd;
		return (unsigned short)tsk->thread.fpu.state->fsave.swd;
	}
}

static inline unsigned short get_fpu_mxcsr(struct task_struct *tsk)
{
	if (cpu_has_xmm) {
		return tsk->thread.xstate->fxsave.mxcsr;
		return tsk->thread.fpu.state->fxsave.mxcsr;
	} else {
		return MXCSR_DEFAULT;
	}
}

static bool fpu_allocated(struct fpu *fpu)
{
	return fpu->state != NULL;
}

static inline int fpu_alloc(struct fpu *fpu)
{
	if (fpu_allocated(fpu))
		return 0;
	fpu->state = kmem_cache_alloc(task_xstate_cachep, GFP_KERNEL);
	if (!fpu->state)
		return -ENOMEM;
	WARN_ON((unsigned long)fpu->state & 15);
	return 0;
}

static inline void fpu_free(struct fpu *fpu)
{
	if (fpu->state) {
		kmem_cache_free(task_xstate_cachep, fpu->state);
		fpu->state = NULL;
	}
}

static inline void fpu_copy(struct fpu *dst, struct fpu *src)
{
	memcpy(dst->state, src->state, xstate_size);
}

#endif /* __ASSEMBLY__ */

#define PSHUFB_XMM5_XMM0 .byte 0x66, 0x0f, 0x38, 0x00, 0xc5
+5 −1
Original line number Diff line number Diff line
@@ -376,6 +376,10 @@ union thread_xstate {
	struct xsave_struct		xsave;
};

struct fpu {
	union thread_xstate *state;
};

#ifdef CONFIG_X86_64
DECLARE_PER_CPU(struct orig_ist, orig_ist);

@@ -453,7 +457,7 @@ struct thread_struct {
	unsigned long		trap_no;
	unsigned long		error_code;
	/* floating point and extended processor state */
	union thread_xstate	*xstate;
	struct fpu		fpu;
#ifdef CONFIG_X86_32
	/* Virtual 86 mode info */
	struct vm86_struct __user *vm86_info;
+0 −1
Original line number Diff line number Diff line
@@ -242,7 +242,6 @@ static inline struct thread_info *current_thread_info(void)
#define TS_POLLING		0x0004	/* true if in idle loop
					   and not sleeping */
#define TS_RESTORE_SIGMASK	0x0008	/* restore signal mask in do_signal() */
#define TS_XSAVE		0x0010	/* Use xsave/xrstor */

#define tsk_is_polling(t) (task_thread_info(t)->status & TS_POLLING)

Loading