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

Commit 40d2e763 authored by Brian Gerst's avatar Brian Gerst Committed by H. Peter Anvin
Browse files

x86-32: Rework cache flush denied handler



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: default avatarBrian Gerst <brgerst@gmail.com>
LKML-Reference: <1269176446-2489-2-git-send-email-brgerst@gmail.com>
Signed-off-by: default avatarH. Peter Anvin <hpa@zytor.com>
parent be1066bb
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
+19 −0
Original line number Diff line number Diff line
@@ -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
+3 −28
Original line number Diff line number Diff line
@@ -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);
#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