diff options
author | Ingo Molnar <mingo@kernel.org> | 2015-04-22 10:53:34 +0200 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2015-05-19 15:47:16 +0200 |
commit | 0c8675379048f36c76ad3a46519310ee2d626b2f (patch) | |
tree | 822665734b246224f21c4906886aedd4818eea05 /arch/x86/kernel/fpu/init.c | |
parent | f89e32e0a3df2f29d61fdc120ac62654ef267111 (diff) |
x86/fpu: Split out the boot time FPU init code into fpu/init.c
Move boot time FPU initialization code into init.c, to better
isolate it into its own domain.
Reviewed-by: Borislav Petkov <bp@alien8.de>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Dave Hansen <dave.hansen@linux.intel.com>
Cc: Fenghua Yu <fenghua.yu@intel.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'arch/x86/kernel/fpu/init.c')
-rw-r--r-- | arch/x86/kernel/fpu/init.c | 93 |
1 files changed, 93 insertions, 0 deletions
diff --git a/arch/x86/kernel/fpu/init.c b/arch/x86/kernel/fpu/init.c new file mode 100644 index 000000000000..0a666298abbd --- /dev/null +++ b/arch/x86/kernel/fpu/init.c @@ -0,0 +1,93 @@ +/* + * x86 FPU boot time init code + */ +#include <asm/fpu-internal.h> +#include <asm/tlbflush.h> + +unsigned int mxcsr_feature_mask __read_mostly = 0xffffffffu; +unsigned int xstate_size; +EXPORT_SYMBOL_GPL(xstate_size); +static struct i387_fxsave_struct fx_scratch; + +static void mxcsr_feature_mask_init(void) +{ + unsigned long mask = 0; + + if (cpu_has_fxsr) { + memset(&fx_scratch, 0, sizeof(struct i387_fxsave_struct)); + asm volatile("fxsave %0" : "+m" (fx_scratch)); + mask = fx_scratch.mxcsr_mask; + if (mask == 0) + mask = 0x0000ffbf; + } + mxcsr_feature_mask &= mask; +} + +static void fpstate_xstate_init_size(void) +{ + /* + * Note that xstate_size might be overwriten later during + * xsave_init(). + */ + + if (!cpu_has_fpu) { + /* + * Disable xsave as we do not support it if i387 + * emulation is enabled. + */ + setup_clear_cpu_cap(X86_FEATURE_XSAVE); + setup_clear_cpu_cap(X86_FEATURE_XSAVEOPT); + xstate_size = sizeof(struct i387_soft_struct); + return; + } + + if (cpu_has_fxsr) + xstate_size = sizeof(struct i387_fxsave_struct); + else + xstate_size = sizeof(struct i387_fsave_struct); +} + +/* + * Called on the boot CPU at bootup to set up the initial FPU state that + * is later cloned into all processes. + * + * Also called on secondary CPUs to set up the FPU state of their + * idle threads. + */ +void fpu__cpu_init(void) +{ + unsigned long cr0; + unsigned long cr4_mask = 0; + +#ifndef CONFIG_MATH_EMULATION + if (!cpu_has_fpu) { + pr_emerg("No FPU found and no math emulation present\n"); + pr_emerg("Giving up\n"); + for (;;) + asm volatile("hlt"); + } +#endif + if (cpu_has_fxsr) + cr4_mask |= X86_CR4_OSFXSR; + if (cpu_has_xmm) + cr4_mask |= X86_CR4_OSXMMEXCPT; + if (cr4_mask) + cr4_set_bits(cr4_mask); + + cr0 = read_cr0(); + cr0 &= ~(X86_CR0_TS|X86_CR0_EM); /* clear TS and EM */ + if (!cpu_has_fpu) + cr0 |= X86_CR0_EM; + write_cr0(cr0); + + /* + * fpstate_xstate_init_size() is only called once, to avoid overriding + * 'xstate_size' during (secondary CPU) bootup or during CPU hotplug. + */ + if (xstate_size == 0) + fpstate_xstate_init_size(); + + mxcsr_feature_mask_init(); + xsave_init(); + eager_fpu_init(); +} |