]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
x86-32: Rework cache flush denied handler
authorBrian Gerst <brgerst@gmail.com>
Sun, 21 Mar 2010 13:00:43 +0000 (09:00 -0400)
committerH. Peter Anvin <hpa@zytor.com>
Mon, 3 May 2010 20:39:26 +0000 (13:39 -0700)
The cache flush denied error is an erratum on some AMD 486 clones.  If an invd
instruction is executed in userspace, the processor calls exception 19 (13 hex)
instead of #GP (13 decimal).  On cpus where XMM is not supported, redirect
exception 19 to do_general_protection().  Also, remove die_if_kernel(), since
this was the last user.

Signed-off-by: Brian Gerst <brgerst@gmail.com>
LKML-Reference: <1269176446-2489-2-git-send-email-brgerst@gmail.com>
Signed-off-by: H. Peter Anvin <hpa@zytor.com>
arch/x86/Kconfig.cpu
arch/x86/kernel/entry_32.S
arch/x86/kernel/traps.c

index a19829374e6a006b80a5db969a19c4f7dbae3449..6f6792c56015301067f0f706d9459aa8c1c9ffbb 100644 (file)
@@ -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
index 44a8e0dc6737d9f28ba0fe258655e0d43b02226d..cd49141cf153fb124dc46a6497dbc863a3c81ad9 100644 (file)
@@ -53,6 +53,7 @@
 #include <asm/processor-flags.h>
 #include <asm/ftrace.h>
 #include <asm/irq_vectors.h>
+#include <asm/cpufeature.h>
 
 /* Avoid __ASSEMBLER__'ifying <linux/audit.h> just for this.  */
 #include <linux/elf-em.h>
@@ -905,7 +906,25 @@ ENTRY(simd_coprocessor_error)
        RING0_INT_FRAME
        pushl $0
        CFI_ADJUST_CFA_OFFSET 4
+#ifdef CONFIG_X86_INVD_BUG
+       /* AMD 486 bug: invd from userspace calls exception 19 instead of #GP */
+661:   pushl $do_general_protection
+662:
+.section .altinstructions,"a"
+       .balign 4
+       .long 661b
+       .long 663f
+       .byte X86_FEATURE_XMM
+       .byte 662b-661b
+       .byte 664f-663f
+.previous
+.section .altinstr_replacement,"ax"
+663:   pushl $do_simd_coprocessor_error
+664:
+.previous
+#else
        pushl $do_simd_coprocessor_error
+#endif
        CFI_ADJUST_CFA_OFFSET 4
        jmp error_code
        CFI_ENDPROC
index 1168e44541887e441e0cb8422cdaf67e86bfe4e5..a16c9dfe6b70ffd117090bb8a37b2dcfe8e9cd90 100644 (file)
@@ -108,15 +108,6 @@ static inline void preempt_conditional_cli(struct pt_regs *regs)
        dec_preempt_count();
 }
 
-#ifdef CONFIG_X86_32
-static inline void
-die_if_kernel(const char *str, struct pt_regs *regs, long err)
-{
-       if (!user_mode_vm(regs))
-               die(str, regs, err);
-}
-#endif
-
 static void __kprobes
 do_trap(int trapnr, int signr, char *str, struct pt_regs *regs,
        long error_code, siginfo_t *info)
@@ -729,30 +720,14 @@ do_simd_coprocessor_error(struct pt_regs *regs, long error_code)
        conditional_sti(regs);
 
 #ifdef CONFIG_X86_32
-       if (cpu_has_xmm) {
-               /* Handle SIMD FPU exceptions on PIII+ processors. */
-               ignore_fpu_irq = 1;
-               simd_math_error((void __user *)regs->ip);
-               return;
-       }
-       /*
-        * Handle strange cache flush from user space exception
-        * in all other cases.  This is undocumented behaviour.
-        */
-       if (regs->flags & X86_VM_MASK) {
-               handle_vm86_fault((struct kernel_vm86_regs *)regs, error_code);
-               return;
-       }
-       current->thread.trap_no = 19;
-       current->thread.error_code = error_code;
-       die_if_kernel("cache flush denied", regs, error_code);
-       force_sig(SIGSEGV, current);
+       ignore_fpu_irq = 1;
 #else
        if (!user_mode(regs) &&
                        kernel_math_error(regs, "kernel simd math error", 19))
                return;
-       simd_math_error((void __user *)regs->ip);
 #endif
+
+       simd_math_error((void __user *)regs->ip);
 }
 
 dotraplinkage void