diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-11-30 20:00:23 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-11-30 20:00:23 -0500 |
commit | 7c17e486e865d616f0e37c7f7f0e4dcfab704cd8 (patch) | |
tree | f238c1c0055100f9e7a134211e934c5aecf6d873 | |
parent | 8fdd78eeb11aeda018b22424f863344ef83a92d3 (diff) | |
parent | 644c154186386bb1fa6446bc5e037b9ed098db46 (diff) |
Merge branch 'x86/urgent' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86 fixes from Peter Anvin.
This includes the resume-time FPU corruption fix from the chromeos guys,
marked for stable.
* 'x86/urgent' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
x86, fpu: Avoid FPU lazy restore after suspend
x86-32: Unbreak booting on some 486 clones
x86, kvm: Remove incorrect redundant assembly constraint
-rw-r--r-- | arch/x86/include/asm/fpu-internal.h | 15 | ||||
-rw-r--r-- | arch/x86/kernel/head_32.S | 9 | ||||
-rw-r--r-- | arch/x86/kernel/smpboot.c | 5 | ||||
-rw-r--r-- | arch/x86/kvm/emulate.c | 3 |
4 files changed, 22 insertions, 10 deletions
diff --git a/arch/x86/include/asm/fpu-internal.h b/arch/x86/include/asm/fpu-internal.h index 831dbb9c6c02..41ab26ea6564 100644 --- a/arch/x86/include/asm/fpu-internal.h +++ b/arch/x86/include/asm/fpu-internal.h | |||
@@ -399,14 +399,17 @@ static inline void drop_init_fpu(struct task_struct *tsk) | |||
399 | typedef struct { int preload; } fpu_switch_t; | 399 | typedef struct { int preload; } fpu_switch_t; |
400 | 400 | ||
401 | /* | 401 | /* |
402 | * FIXME! We could do a totally lazy restore, but we need to | 402 | * Must be run with preemption disabled: this clears the fpu_owner_task, |
403 | * add a per-cpu "this was the task that last touched the FPU | 403 | * on this CPU. |
404 | * on this CPU" variable, and the task needs to have a "I last | ||
405 | * touched the FPU on this CPU" and check them. | ||
406 | * | 404 | * |
407 | * We don't do that yet, so "fpu_lazy_restore()" always returns | 405 | * This will disable any lazy FPU state restore of the current FPU state, |
408 | * false, but some day.. | 406 | * but if the current thread owns the FPU, it will still be saved by. |
409 | */ | 407 | */ |
408 | static inline void __cpu_disable_lazy_restore(unsigned int cpu) | ||
409 | { | ||
410 | per_cpu(fpu_owner_task, cpu) = NULL; | ||
411 | } | ||
412 | |||
410 | static inline int fpu_lazy_restore(struct task_struct *new, unsigned int cpu) | 413 | static inline int fpu_lazy_restore(struct task_struct *new, unsigned int cpu) |
411 | { | 414 | { |
412 | return new == this_cpu_read_stable(fpu_owner_task) && | 415 | return new == this_cpu_read_stable(fpu_owner_task) && |
diff --git a/arch/x86/kernel/head_32.S b/arch/x86/kernel/head_32.S index 957a47aec64e..4dac2f68ed4a 100644 --- a/arch/x86/kernel/head_32.S +++ b/arch/x86/kernel/head_32.S | |||
@@ -292,8 +292,8 @@ default_entry: | |||
292 | * be using the global pages. | 292 | * be using the global pages. |
293 | * | 293 | * |
294 | * NOTE! If we are on a 486 we may have no cr4 at all! | 294 | * NOTE! If we are on a 486 we may have no cr4 at all! |
295 | * Specifically, cr4 exists if and only if CPUID exists, | 295 | * Specifically, cr4 exists if and only if CPUID exists |
296 | * which in turn exists if and only if EFLAGS.ID exists. | 296 | * and has flags other than the FPU flag set. |
297 | */ | 297 | */ |
298 | movl $X86_EFLAGS_ID,%ecx | 298 | movl $X86_EFLAGS_ID,%ecx |
299 | pushl %ecx | 299 | pushl %ecx |
@@ -308,6 +308,11 @@ default_entry: | |||
308 | testl %ecx,%eax | 308 | testl %ecx,%eax |
309 | jz 6f # No ID flag = no CPUID = no CR4 | 309 | jz 6f # No ID flag = no CPUID = no CR4 |
310 | 310 | ||
311 | movl $1,%eax | ||
312 | cpuid | ||
313 | andl $~1,%edx # Ignore CPUID.FPU | ||
314 | jz 6f # No flags or only CPUID.FPU = no CR4 | ||
315 | |||
311 | movl pa(mmu_cr4_features),%eax | 316 | movl pa(mmu_cr4_features),%eax |
312 | movl %eax,%cr4 | 317 | movl %eax,%cr4 |
313 | 318 | ||
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c index c80a33bc528b..f3e2ec878b8c 100644 --- a/arch/x86/kernel/smpboot.c +++ b/arch/x86/kernel/smpboot.c | |||
@@ -68,6 +68,8 @@ | |||
68 | #include <asm/mwait.h> | 68 | #include <asm/mwait.h> |
69 | #include <asm/apic.h> | 69 | #include <asm/apic.h> |
70 | #include <asm/io_apic.h> | 70 | #include <asm/io_apic.h> |
71 | #include <asm/i387.h> | ||
72 | #include <asm/fpu-internal.h> | ||
71 | #include <asm/setup.h> | 73 | #include <asm/setup.h> |
72 | #include <asm/uv/uv.h> | 74 | #include <asm/uv/uv.h> |
73 | #include <linux/mc146818rtc.h> | 75 | #include <linux/mc146818rtc.h> |
@@ -818,6 +820,9 @@ int __cpuinit native_cpu_up(unsigned int cpu, struct task_struct *tidle) | |||
818 | 820 | ||
819 | per_cpu(cpu_state, cpu) = CPU_UP_PREPARE; | 821 | per_cpu(cpu_state, cpu) = CPU_UP_PREPARE; |
820 | 822 | ||
823 | /* the FPU context is blank, nobody can own it */ | ||
824 | __cpu_disable_lazy_restore(cpu); | ||
825 | |||
821 | err = do_boot_cpu(apicid, cpu, tidle); | 826 | err = do_boot_cpu(apicid, cpu, tidle); |
822 | if (err) { | 827 | if (err) { |
823 | pr_debug("do_boot_cpu failed %d\n", err); | 828 | pr_debug("do_boot_cpu failed %d\n", err); |
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index 39171cb307ea..bba39bfa1c4b 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c | |||
@@ -426,8 +426,7 @@ static void invalidate_registers(struct x86_emulate_ctxt *ctxt) | |||
426 | _ASM_EXTABLE(1b, 3b) \ | 426 | _ASM_EXTABLE(1b, 3b) \ |
427 | : "=m" ((ctxt)->eflags), "=&r" (_tmp), \ | 427 | : "=m" ((ctxt)->eflags), "=&r" (_tmp), \ |
428 | "+a" (*rax), "+d" (*rdx), "+qm"(_ex) \ | 428 | "+a" (*rax), "+d" (*rdx), "+qm"(_ex) \ |
429 | : "i" (EFLAGS_MASK), "m" ((ctxt)->src.val), \ | 429 | : "i" (EFLAGS_MASK), "m" ((ctxt)->src.val)); \ |
430 | "a" (*rax), "d" (*rdx)); \ | ||
431 | } while (0) | 430 | } while (0) |
432 | 431 | ||
433 | /* instruction has only one source operand, destination is implicit (e.g. mul, div, imul, idiv) */ | 432 | /* instruction has only one source operand, destination is implicit (e.g. mul, div, imul, idiv) */ |