x86/fpu changes for v3.7
Subsystems (5)
Linus,
Please pull the latest x86-fpu-for-linus git tree from:
git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git x86-fpu-for-linus
HEAD: b1a74bf8212367be2b1d6685c11a84e056eaaaf1 x86, kvm: fix kvm's usage of kernel_fpu_begin/end()
The biggest change is the addition of the non-lazy (eager) FPU saving support model and enabling it on CPUs with optimized xsaveopt/xrstor FPU state saving instructions.
There's also various Sparse fixes.
out-of-topic modifications in x86-fpu-for-linus:
------------------------------------------------drivers/lguest/x86/core.c # 9c6ff8b: lguest, x86: handle guest TS bit
Thanks,
Ingo
------------------>
Mathias Krause (7):
x86: Fix __user annotations in asm/sys_ia32.h
x86/vdso: Add __user annotation to VDSO32_SYMBOL x86/signals: ia32_signal.c: add __user casts to fix sparse warnings x86/pci/probe_roms: Add missing __iomem annotation to pci_map_biosrom() x86/fpu/xsave: Keep __user annotation in casts
x86/iommu: Drop duplicate const in __IOMMU_INIT
x86/iommu: Use NULL instead of plain 0 for __IOMMU_INIT
Suresh Siddha (14):
x86, signal: Cleanup ifdefs and is_ia32, is_x32
x86, fpu: Consolidate inline asm routines for saving/restoring fpu state x86, fpu: Unify signal handling code paths for x86 and x86_64 kernels x86, fpu: drop_fpu() before restoring new state from sigframe x86, fpu: remove unnecessary user_fpu_end() in save_xstate_sig() x86, kvm: use kernel_fpu_begin/end() in kvm_load/put_guest_fpu() x86, fpu: always use kernel_fpu_begin/end() for in-kernel FPU usage lguest, x86: handle guest TS bit for lazy/non-lazy fpu host models x86, fpu: use non-lazy fpu restore for processors supporting xsave x86, fpu: decouple non-lazy/eager fpu restore from xsave x86, fpu: enable eagerfpu by default for xsaveopt
x86, fpu: make eagerfpu= boot param tri-state
x86, fpu: remove cpu_has_xmm check in the fx_finit()
x86, kvm: fix kvm's usage of kernel_fpu_begin/end()
Documentation/kernel-parameters.txt | 6 + arch/x86/ia32/ia32_signal.c | 20 +- arch/x86/ia32/sys_ia32.c | 2 +- arch/x86/include/asm/cpufeature.h | 3 + arch/x86/include/asm/fpu-internal.h | 390 +++++++++++++++------------ arch/x86/include/asm/i387.h | 29 +- arch/x86/include/asm/iommu_table.h | 6 +- arch/x86/include/asm/signal.h | 4 + arch/x86/include/asm/sys_ia32.h | 2 +- arch/x86/include/asm/vdso.h | 3 +- arch/x86/include/asm/xor_32.h | 56 +--- arch/x86/include/asm/xor_64.h | 61 +---- arch/x86/include/asm/xor_avx.h | 54 +--- arch/x86/include/asm/xsave.h | 13 +- arch/x86/kernel/cpu/bugs.c | 7 +- arch/x86/kernel/cpu/common.c | 2 - arch/x86/kernel/i387.c | 292 ++------------------ arch/x86/kernel/probe_roms.c | 2 +- arch/x86/kernel/process.c | 22 +- arch/x86/kernel/process_32.c | 4 - arch/x86/kernel/process_64.c | 4 - arch/x86/kernel/ptrace.c | 3 - arch/x86/kernel/signal.c | 211 +++++++-------- arch/x86/kernel/traps.c | 5 +- arch/x86/kernel/xsave.c | 517 +++++++++++++++++++++++------------- arch/x86/kvm/vmx.c | 10 +- arch/x86/kvm/x86.c | 3 +- drivers/lguest/x86/core.c | 10 +- 28 files changed, 805 insertions(+), 936 deletions(-)
Documentation/kernel-parameters.txt +6 -0
@@ -1833,6 +1833,12 @@ bytes respectively. Such letter suffixes can also be entirely omitted. and restore using xsave. The kernel will fallback to enabling legacy floating-point and sse state. + eagerfpu= [X86] + on enable eager fpu restore + off disable eager fpu restore + auto selects the default scheme, which automatically + enables eagerfpu restore for xsaveopt. + nohlt [BUGS=ARM,SH] Tells the kernel that the sleep(SH) or wfi(ARM) instruction doesn't work correctly and not to use it. This is also useful when using JTAG debugger.
arch/x86/ia32/ia32_signal.c +12 -8
@@ -162,7 +162,8 @@ asmlinkage long sys32_sigaltstack(const stack_ia32_t __user *uss_ptr, } seg =get_fs ();set_fs (KERNEL_DS ); - ret =do_sigaltstack (uss_ptr ? &uss :NULL , &uoss, regs->sp); + ret =do_sigaltstack ((stack_t __force __user *) (uss_ptr ? &uss :NULL ), + (stack_t __force __user *) &uoss, regs->sp);set_fs (seg);if (ret >=0 && uoss_ptr) {if (!access_ok (VERIFY_WRITE , uoss_ptr,sizeof (stack_ia32_t)))
@@ -250,7 +251,7 @@ static int ia32_restore_sigcontext(struct pt_regs *regs,get_user_ex (tmp, &sc->fpstate); buf =compat_ptr (tmp); - err |=restore_i387_xstate_ia32 (buf); + err |=restore_xstate_sig (buf,1 );get_user_ex (*pax, &sc->ax); }get_user_catch (err);
@@ -361,7 +362,7 @@ static int ia32_setup_sigcontext(struct sigcontext_ia32 __user *sc,*/ static void __user *get_sigframe (struct k_sigaction *ka,struct pt_regs *regs,size_t frame_size, -void **fpstate) +void __user **fpstate) {unsigned long sp;
@@ -381,9 +382,12 @@ static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, sp = (unsigned long ) ka->sa.sa_restorer;if (used_math ()) { - sp = sp - sig_xstate_ia32_size; - *fpstate = (struct _fpstate_ia32 *) sp; -if (save_i387_xstate_ia32 (*fpstate) <0 ) +unsigned long fx_aligned, math_size; + + sp =alloc_mathframe (sp,1 , &fx_aligned, &math_size); + *fpstate = (struct _fpstate_ia32 __user *) sp; +if (save_xstate_sig (*fpstate, (void __user *)fx_aligned, + math_size) <0 )return (void __user *)-1L ; }
@@ -448,7 +452,7 @@ int ia32_setup_frame(int sig, struct k_sigaction *ka,* These are actually not used anymore, but left because some * gdb versions depend on them as a marker. */ -put_user_ex (*((u64 *)&code), (u64 *)frame->retcode); +put_user_ex (*((u64 *)&code), (u64 __user *)frame->retcode); }put_user_catch (err);if (err)
@@ -529,7 +533,7 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,* Not actually used anymore, but left because some gdb * versions need it. */ -put_user_ex (*((u64 *)&code), (u64 *)frame->retcode); +put_user_ex (*((u64 *)&code), (u64 __user *)frame->retcode); }put_user_catch (err);if (err)
arch/x86/ia32/sys_ia32.c +1 -1
@@ -287,7 +287,7 @@ asmlinkage long sys32_sigaction(int sig, struct old_sigaction32 __user *act,return ret; } -asmlinkage long sys32_waitpid (compat_pid_t pid,unsigned int *stat_addr, +asmlinkage long sys32_waitpid (compat_pid_t pid,unsigned int __user *stat_addr,int options) {return compat_sys_wait4 (pid, stat_addr, options,NULL );
arch/x86/include/asm/cpufeature.h +3 -0
@@ -97,6 +97,7 @@#define X86_FEATURE_EXTD_APICID (3*32+26)/* has extended APICID (8 bits) */ #define X86_FEATURE_AMD_DCM (3*32+27)/* multi-node processor */ #define X86_FEATURE_APERFMPERF (3*32+28)/* APERFMPERF */ +#define X86_FEATURE_EAGER_FPU (3*32+29)/* "eagerfpu" Non lazy FPU restore */ /* Intel-defined CPU features, CPUID level 0x00000001 (ecx), word 4 */ #define X86_FEATURE_XMM3 (4*32+ 0)/* "pni" SSE-3 */
@@ -299,12 +300,14 @@ extern const char * const x86_power_flags[32];#define cpu_has_xmm4_2 boot_cpu_has(X86_FEATURE_XMM4_2)#define cpu_has_x2apic boot_cpu_has(X86_FEATURE_X2APIC)#define cpu_has_xsave boot_cpu_has(X86_FEATURE_XSAVE) +#define cpu_has_xsaveopt boot_cpu_has(X86_FEATURE_XSAVEOPT)#define cpu_has_osxsave boot_cpu_has(X86_FEATURE_OSXSAVE)#define cpu_has_hypervisor boot_cpu_has(X86_FEATURE_HYPERVISOR)#define cpu_has_pclmulqdq boot_cpu_has(X86_FEATURE_PCLMULQDQ)#define cpu_has_perfctr_core boot_cpu_has(X86_FEATURE_PERFCTR_CORE)#define cpu_has_cx8 boot_cpu_has(X86_FEATURE_CX8)#define cpu_has_cx16 boot_cpu_has(X86_FEATURE_CX16) +#define cpu_has_eager_fpu boot_cpu_has(X86_FEATURE_EAGER_FPU)#if defined(CONFIG_X86_INVLPG ) || defined(CONFIG_X86_64 )# define cpu_has_invlpg 1
arch/x86/include/asm/fpu-internal.h +226 -164
544 lines not on this page · raw message
arch/x86/include/asm/i387.h +27 -2
@@ -19,12 +19,37 @@ struct pt_regs;struct user_i387_struct ;extern int init_fpu (struct task_struct *child); +extern void fpu_finit (struct fpu *fpu);extern int dump_fpu (struct pt_regs *,struct user_i387_struct *);extern void math_state_restore (void );extern bool irq_fpu_usable (void ); -extern void kernel_fpu_begin (void ); -extern void kernel_fpu_end (void ); + +/* +* Careful: __kernel_fpu_begin/end() must be called with preempt disabled +* and they don't touch the preempt state on their own. +* If you enable preemption after __kernel_fpu_begin(), preempt notifier +* should call the __kernel_fpu_end() to prevent the kernel/user FPU +* state from getting corrupted. KVM for example uses this model. +* +* All other cases use kernel_fpu_begin/end() which disable preemption +* during kernel FPU usage. +*/ +extern void __kernel_fpu_begin (void ); +extern void __kernel_fpu_end (void ); + +static inline void kernel_fpu_begin (void ) +{ +WARN_ON_ONCE (!irq_fpu_usable ()); +preempt_disable (); +__kernel_fpu_begin (); +} + +static inline void kernel_fpu_end (void ) +{ +__kernel_fpu_end (); +preempt_enable (); +}/* * Some instructions like VIA's padlock instructions generate a spurious
arch/x86/include/asm/iommu_table.h +3 -3
@@ -48,7 +48,7 @@ struct iommu_table_entry {#define __IOMMU_INIT (_detect, _depend, _early_init, _late_init, _finish)\ - static const struct iommu_table_entry const \ + static const struct iommu_table_entry \ __iommu_entry_##_detect __used \ __attribute__ ((unused, __section__(".iommu_table"), \ aligned((sizeof(void *))))) \
@@ -63,10 +63,10 @@ struct iommu_table_entry {* to stop detecting the other IOMMUs after yours has been detected. */ #define IOMMU_INIT_POST (_detect) \ - __IOMMU_INIT(_detect, pci_swiotlb_detect_4gb, 0, 0, 0) + __IOMMU_INIT(_detect, pci_swiotlb_detect_4gb, NULL, NULL, 0)#define IOMMU_INIT_POST_FINISH (detect) \ - __IOMMU_INIT(_detect, pci_swiotlb_detect_4gb, 0, 0, 1) + __IOMMU_INIT(_detect, pci_swiotlb_detect_4gb, NULL, NULL, 1)/* * A more sophisticated version of IOMMU_INIT. This variant requires:
arch/x86/include/asm/signal.h +4 -0
@@ -31,6 +31,10 @@ typedef struct { unsigned long sig[_NSIG_WORDS]; } sigset_t; +#ifndef CONFIG_COMPAT +typedef sigset_t compat_sigset_t ; +#endif +#else /* Here we must cater to libcs that poke about in kernel headers. */
arch/x86/include/asm/sys_ia32.h +1 -1
@@ -40,7 +40,7 @@ asmlinkage long sys32_sigaction(int, struct old_sigaction32 __user *, struct old_sigaction32 __user *);asmlinkage long sys32_alarm (unsigned int ); -asmlinkage long sys32_waitpid (compat_pid_t ,unsigned int *,int ); +asmlinkage long sys32_waitpid (compat_pid_t ,unsigned int __user *,int );asmlinkage long sys32_sysfs (int ,u32 ,u32 ); asmlinkage long sys32_sched_rr_get_interval(compat_pid_t,
arch/x86/include/asm/vdso.h +2 -1
@@ -11,7 +11,8 @@ extern const char VDSO32_PRELINK[];#define VDSO32_SYMBOL (base, name) \ ({ \ extern const char VDSO32_##name[]; \ - (void *)(VDSO32_##name - VDSO32_PRELINK + (unsigned long)(base)); \ + (void __user *)(VDSO32_##name - VDSO32_PRELINK + \ + (unsigned long)(base)); \ })#endif
arch/x86/include/asm/xor_32.h +8 -48
114 lines not on this page · raw message
arch/x86/include/asm/xor_64.h +9 -52
119 lines not on this page · raw message
arch/x86/include/asm/xor_avx.h +12 -42
109 lines not on this page · raw message
arch/x86/include/asm/xsave.h +3 -10
@@ -34,17 +34,14 @@extern unsigned int xstate_size;extern u64 pcntxt_mask;extern u64 xstate_fx_sw_bytes[USER_XSTATE_FX_SW_WORDS ]; +extern struct xsave_struct *init_xstate_buf;extern void xsave_init (void );extern void update_regset_xstate_info (unsigned int size,u64 xstate_mask);extern int init_fpu (struct task_struct *child); -extern int check_for_xstate (struct i387_fxsave_struct __user *buf, -void __user *fpstate, -struct _fpx_sw_bytes *sw); -static inline int fpu_xrstor_checking (struct fpu *fpu) +static inline int fpu_xrstor_checking (struct xsave_struct *fx) { -struct xsave_struct *fx = &fpu->state->xsave;int err; asm volatile("1: .byte " REX_PREFIX "0x0f,0xae,0x2f\n\t"
@@ -69,8 +66,7 @@ static inline int xsave_user(struct xsave_struct __user *buf)* Clear the xsave header first, so that reserved fields are * initialized to zero. */ - err =__clear_user (&buf->xsave_hdr, -sizeof (struct xsave_hdr_struct )); + err =__clear_user (&buf->xsave_hdr,sizeof (buf->xsave_hdr));if (unlikely (err))return -EFAULT ;
@@ -84,9 +80,6 @@ static inline int xsave_user(struct xsave_struct __user *buf) : [err] "=r" (err) : "D" (buf), "a" (-1), "d" (-1), "0" (0) : "memory"); -if (unlikely (err) &&__clear_user (buf, xstate_size)) - err = -EFAULT ; -/* No need to clear here because the caller clears USED_MATH */ return err; }
arch/x86/kernel/cpu/bugs.c +6 -1
@@ -165,10 +165,15 @@ void __init check_bugs(void)print_cpu_info (&boot_cpu_data);#endif check_config (); -check_fpu ();check_hlt ();check_popad ();init_utsname ()->machine[1 ] ='0' + (boot_cpu_data.x86 >6 ?6 : boot_cpu_data.x86);alternative_instructions (); + +/* +* kernel_fpu_begin/end() in check_fpu() relies on the patched +* alternative instructions. +*/ +check_fpu (); }
arch/x86/kernel/cpu/common.c +0 -2
@@ -1297,7 +1297,6 @@ void __cpuinit cpu_init(void)dbg_restore_debug_regs ();fpu_init (); -xsave_init ();raw_local_save_flags (kernel_eflags);
@@ -1352,6 +1351,5 @@ void __cpuinit cpu_init(void)dbg_restore_debug_regs (); fpu_init(); - xsave_init(); }#endif
arch/x86/kernel/i387.c +28 -264
376 lines not on this page · raw message
arch/x86/kernel/probe_roms.c +1 -1
@@ -150,7 +150,7 @@ static struct resource *find_oprom(struct pci_dev *pdev)return oprom; } -void *pci_map_biosrom (struct pci_dev *pdev) +void __iomem *pci_map_biosrom (struct pci_dev *pdev) {struct resource *oprom =find_oprom (pdev);
arch/x86/kernel/process.c +8 -14
@@ -66,15 +66,13 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src) {int ret; -unlazy_fpu (src); - *dst = *src;if (fpu_allocated (&src->thread.fpu)) {memset (&dst->thread.fpu,0 ,sizeof (dst->thread.fpu)); ret =fpu_alloc (&dst->thread.fpu);if (ret)return ret; -fpu_copy (&dst->thread.fpu, &src->thread.fpu); +fpu_copy (dst, src); }return 0 ; }
@@ -97,16 +95,6 @@ void arch_task_cache_init(void) SLAB_PANIC | SLAB_NOTRACK, NULL); } -static inline void drop_fpu (struct task_struct *tsk) -{ -/* -* Forget coprocessor state.. -*/ - tsk->fpu_counter =0 ; -clear_fpu (tsk); -clear_used_math (); -} -/* * Free current thread data structures etc.. */
@@ -163,7 +151,13 @@ void flush_thread(void)flush_ptrace_hw_breakpoint (tsk);memset (tsk->thread.tls_array,0 ,sizeof (tsk->thread.tls_array)); -drop_fpu (tsk); +drop_init_fpu (tsk); +/* +* Free the FPU state for non xsave platforms. They get reallocated +* lazily at the first use. +*/ +if (!use_eager_fpu ()) +free_thread_xstate (tsk); }static void hard_disable_TSC (void )
arch/x86/kernel/process_32.c +0 -4
@@ -190,10 +190,6 @@ start_thread(struct pt_regs *regs, unsigned long new_ip, unsigned long new_sp) regs->cs = __USER_CS; regs->ip = new_ip; regs->sp = new_sp; -/* -* Free the old FP and other extended state -*/ -free_thread_xstate (current); }EXPORT_SYMBOL_GPL (start_thread);
arch/x86/kernel/process_64.c +0 -4
@@ -232,10 +232,6 @@ start_thread_common(struct pt_regs *regs, unsigned long new_ip, regs->cs = _cs; regs->ss = _ss; regs->flags =X86_EFLAGS_IF ; -/* -* Free the old FP and other extended state -*/ -free_thread_xstate (current); }void
arch/x86/kernel/ptrace.c +0 -3
@@ -1332,9 +1332,6 @@ static const struct user_regset_view user_x86_64_view = {#define genregs32_get genregs_get#define genregs32_set genregs_set -#define user_i387_ia32_struct user_i387_struct -#define user32_fxsr_struct user_fxsr_struct -#endif /* CONFIG_X86_64 */ #if definedCONFIG_X86_32 || definedCONFIG_IA32_EMULATION
arch/x86/kernel/signal.c +89 -122
272 lines not on this page · raw message
arch/x86/kernel/traps.c +4 -1
@@ -613,11 +613,12 @@ void math_state_restore(void) }__thread_fpu_begin (tsk); +/* * Paranoid restore. send a SIGSEGV if we fail to restore the state. */ if (unlikely (restore_fpu_checking (tsk))) { -__thread_fpu_end (tsk); +drop_init_fpu (tsk);force_sig (SIGSEGV , tsk);return ; }
@@ -629,6 +630,8 @@ EXPORT_SYMBOL_GPL(math_state_restore); dotraplinkage void __kprobesdo_device_not_available (struct pt_regs *regs,long error_code) { +BUG_ON (use_eager_fpu ()); +#ifdef CONFIG_MATH_EMULATION if (read_cr0 () &X86_CR0_EM ) {struct math_emu_info info = { };
arch/x86/kernel/xsave.c +336 -181
650 lines not on this page · raw message
arch/x86/kvm/vmx.c +7 -3
@@ -1493,8 +1493,12 @@ static void __vmx_load_host_state(struct vcpu_vmx *vmx)#ifdef CONFIG_X86_64 wrmsrl (MSR_KERNEL_GS_BASE , vmx->msr_host_kernel_gs_base);#endif -if (user_has_fpu ()) -clts (); +/* +* If the FPU is not active (through the host task or +* the guest vcpu), then restore the cr0.TS bit. +*/ +if (!user_has_fpu () && !vmx->vcpu.guest_fpu_loaded) +stts ();load_gdt (&__get_cpu_var (host_gdt)); }
@@ -3730,7 +3734,7 @@ static void vmx_set_constant_host_state(void)unsigned long tmpl;struct desc_ptr dt; -vmcs_writel (HOST_CR0 ,read_cr0 () |X86_CR0_TS );/* 22.2.3 */ +vmcs_writel (HOST_CR0 ,read_cr0 () & ~X86_CR0_TS );/* 22.2.3 */ vmcs_writel (HOST_CR4 ,read_cr4 ());/* 22.2.3, 22.2.5 */ vmcs_writel (HOST_CR3 ,read_cr3 ());/* 22.2.3 FIXME: shadow tables */
arch/x86/kvm/x86.c +2 -1
@@ -5972,7 +5972,7 @@ void kvm_load_guest_fpu(struct kvm_vcpu *vcpu)*/ kvm_put_guest_xcr0 (vcpu); vcpu->guest_fpu_loaded =1 ; -unlazy_fpu (current); +__kernel_fpu_begin ();fpu_restore_checking (&vcpu->arch.guest_fpu);trace_kvm_fpu (1 ); }
@@ -5986,6 +5986,7 @@ void kvm_put_guest_fpu(struct kvm_vcpu *vcpu) vcpu->guest_fpu_loaded =0 ;fpu_save_init (&vcpu->arch.guest_fpu); +__kernel_fpu_end (); ++vcpu->stat.fpu_reload;kvm_make_request (KVM_REQ_DEACTIVATE_FPU , vcpu);trace_kvm_fpu (0 );
drivers/lguest/x86/core.c +7 -3
@@ -203,8 +203,8 @@ void lguest_arch_run_guest(struct lg_cpu *cpu)* we set it now, so we can trap and pass that trap to the Guest if it * uses the FPU. */ -if (cpu->ts) -unlazy_fpu (current); +if (cpu->ts &&user_has_fpu ()) +stts ();/* * SYSENTER is an optimized way of doing system calls. We can't allow
@@ -234,6 +234,10 @@ void lguest_arch_run_guest(struct lg_cpu *cpu)if (boot_cpu_has (X86_FEATURE_SEP ))wrmsr (MSR_IA32_SYSENTER_CS , __KERNEL_CS,0 ); +/* Clear the host TS bit if it was set above. */ +if (cpu->ts &&user_has_fpu ()) +clts (); +/* * If the Guest page faulted, then the cr2 register will tell us the * bad virtual address. We have to grab this now, because once we
@@ -249,7 +253,7 @@ void lguest_arch_run_guest(struct lg_cpu *cpu)* a different CPU. So all the critical stuff should be done * before this. */ - else if (cpu->regs->trapnum == 7) + else if (cpu->regs->trapnum == 7 && !user_has_fpu()) math_state_restore(); }