linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Andi Kleen <ak@suse.de>
To: richard.brunner@amd.com
Cc: linux-kernel@vger.kernel.org, akpm@osdl.org, torvalds@osdl.org
Subject: [PATCH] 2.6 workaround for Athlon/Opteron prefetch errata
Date: Thu, 11 Sep 2003 03:27:08 +0200	[thread overview]
Message-ID: <20030911012708.GD3134@wotan.suse.de> (raw)
In-Reply-To: <99F2150714F93F448942F9A9F112634C0638B196@txexmtae.amd.com>

>     works just fine. (Andi will be posting them soon when he 
>     wakes up ;-)

He's still awake ;-)

Here is a patch to detect a prefect exception for 2.6.0test5/i386

I'm posting the versions for 2.4.22/x86-64 and 2.4.22/i386 in separate
mail. 2.6/x86-64 is not done yet, but will be in my next merge.

The patches only change the slow path in the page fault handler - 
PREFETCH is only checked for when the kernel would send a signal
anyways or print an oops. The check is also rather cheap so it is
unconditionally enabled.

It handles SSE2 prefetches and 3dnow! style prefetches.

The only tricky bit is that it has to be careful to avoid recursive
segfaults. The prefetch checker can cause another page fault when
it does __get_user, but these should not recurse more than once.

This is insured by the placement of the checks in the page fault handler and
only checking for prefetches if the fault came from user space
or the exception tables have been already checked.
To make this work without a per task exception nest counter
I had to change the SIGBUS handling path slightly. Now when
an get/put_user in kernel causes a SIGBUS it is not delivered
to user space. Instead you just get the standard EFAULT back.

It also removed Andrew's old workaround for the problem.

-Andi

--- linux-2.6.0test5-work/arch/i386/mm/fault.c-o	2003-05-27 03:00:20.000000000 +0200
+++ linux-2.6.0test5-work/arch/i386/mm/fault.c	2003-09-10 23:58:52.000000000 +0200
@@ -55,6 +55,77 @@
 	console_loglevel = loglevel_save;
 }
 
+/* Sometimes the CPU reports invalid exceptions on prefetch.
+   Check that here and ignore.
+   Opcode checker based on code by Richard Brunner */
+static int is_prefetch(struct pt_regs *regs, unsigned long addr)
+{ 
+	unsigned char *instr = (unsigned char *)(regs->eip);
+	int scan_more = 1;
+	int prefetch = 0; 
+	unsigned char *max_instr = instr + 15;
+
+	/* Avoid recursive faults. This makes kernel jumping to nirvana
+	   reporting work better. */
+	if (regs->eip == addr)
+		return 0; 
+
+	while (scan_more && instr < max_instr) { 
+		unsigned char opcode;
+		unsigned char instr_hi;
+		unsigned char instr_lo;
+
+		if (__get_user(opcode, instr))
+			break; 
+
+		instr_hi = opcode & 0xf0; 
+		instr_lo = opcode & 0x0f; 
+		instr++;
+
+		switch (instr_hi) { 
+		case 0x20:
+		case 0x30:
+			/* Values 0x26,0x2E,0x36,0x3E are valid x86
+			   prefixes.  In long mode, the CPU will signal
+			   invalid opcode if some of these prefixes are
+			   present so we will never get here anyway */
+			scan_more = ((instr_lo & 7) == 0x6);
+			break;
+			
+		case 0x40:
+			/* May be valid in long mode (REX prefixes) */
+			break; 
+			
+		case 0x60:
+			/* 0x64 thru 0x67 are valid prefixes in all modes. */
+			scan_more = (instr_lo & 0xC) == 0x4;
+			break;		
+		case 0xF0:
+			/* 0xF0, 0xF2, and 0xF3 are valid prefixes in all modes. */
+			scan_more = !instr_lo || (instr_lo>>1) == 1;
+			break;			
+		case 0x00:
+			/* Prefetch instruction is 0x0F0D or 0x0F18 */
+			scan_more = 0;
+			if (__get_user(opcode, instr)) 
+				break;
+			prefetch = (instr_lo == 0xF) &&
+				(opcode == 0x0D || opcode == 0x18);
+			break;			
+		default:
+			scan_more = 0;
+			break;
+		} 
+	}
+
+#if 0
+	if (prefetch)
+		printk("%s: prefetch caused page fault at %lx/%lx\n", current->comm,
+		       regs->eip, addr);
+#endif
+	return prefetch;
+}
+
 asmlinkage void do_invalid_op(struct pt_regs *, unsigned long);
 
 /*
@@ -110,7 +181,7 @@
 	 * atomic region then we must not take the fault..
 	 */
 	if (in_atomic() || !mm)
-		goto no_context;
+		goto bad_area_nosemaphore;
 
 	down_read(&mm->mmap_sem);
 
@@ -198,8 +269,12 @@
 bad_area:
 	up_read(&mm->mmap_sem);
 
+bad_area_nosemaphore:
 	/* User mode accesses just cause a SIGSEGV */
 	if (error_code & 4) {
+		if (is_prefetch(regs, address))
+			return;
+
 		tsk->thread.cr2 = address;
 		tsk->thread.error_code = error_code;
 		tsk->thread.trap_no = 14;
@@ -232,6 +307,9 @@
 	if (fixup_exception(regs))
 		return;
 
+ 	if (is_prefetch(regs, address))
+ 		return;
+
 /*
  * Oops. The kernel tried to access some bad page. We'll have to
  * terminate things with extreme prejudice.
@@ -286,10 +364,13 @@
 do_sigbus:
 	up_read(&mm->mmap_sem);
 
-	/*
-	 * Send a sigbus, regardless of whether we were in kernel
-	 * or user mode.
-	 */
+	/* Kernel mode? Handle exceptions or die */
+	if (!(error_code & 4))
+		goto no_context;
+
+	if (is_prefetch(regs, address))
+		return;
+
 	tsk->thread.cr2 = address;
 	tsk->thread.error_code = error_code;
 	tsk->thread.trap_no = 14;
@@ -298,10 +379,6 @@
 	info.si_code = BUS_ADRERR;
 	info.si_addr = (void *)address;
 	force_sig_info(SIGBUS, &info, tsk);
-
-	/* Kernel mode? Handle exceptions or die */
-	if (!(error_code & 4))
-		goto no_context;
 	return;
 
 vmalloc_fault:
--- linux-2.6.0test5-work/include/asm-i386/processor.h-o	2003-09-09 20:55:46.000000000 +0200
+++ linux-2.6.0test5-work/include/asm-i386/processor.h	2003-09-11 03:22:16.000000000 +0200
@@ -578,8 +578,6 @@
 #define ARCH_HAS_PREFETCH
 extern inline void prefetch(const void *x)
 {
-	if (cpu_data[0].x86_vendor == X86_VENDOR_AMD)
-		return;		/* Some athlons fault if the address is bad */
 	alternative_input(ASM_NOP4,
 			  "prefetchnta (%1)",
 			  X86_FEATURE_XMM,

  reply	other threads:[~2003-09-11  1:27 UTC|newest]

Thread overview: 123+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2003-09-11  0:56 Update on AMD Athlon/Opteron/Athlon64 Prefetch Errata richard.brunner
2003-09-11  1:27 ` Andi Kleen [this message]
2003-09-11  1:44   ` [PATCH] 2.6 workaround for Athlon/Opteron prefetch errata Andrew Morton
2003-09-11  1:47     ` Andi Kleen
2003-09-11 14:15       ` Jeff Garzik
2003-09-11 14:26         ` Andi Kleen
2003-09-11 14:34           ` Jeff Garzik
2003-09-11 14:58             ` Andi Kleen
2003-09-11 15:06               ` Jeff Garzik
2003-09-11 20:08               ` bill davidsen
2003-09-11 19:56             ` bill davidsen
2003-09-11 20:44               ` Alan Cox
2003-09-11 21:29                 ` Mike Fedyk
2003-09-11 21:38                 ` bill davidsen
2003-09-12 17:32             ` Eric W. Biederman
2003-09-12 17:56               ` Andi Kleen
2003-09-12 17:59                 ` Jeff Garzik
2003-09-12 18:22                   ` Adrian Bunk
2003-09-12 18:28                     ` Andi Kleen
2003-09-12 18:39                       ` Jeff Garzik
2003-09-12 18:45                       ` Jeff Garzik
2003-09-12 18:48                       ` Adrian Bunk
2003-09-12 19:07                         ` Andi Kleen
2003-09-12 19:05                       ` Martin Schlemmer
2003-09-12 19:30                         ` Andi Kleen
2003-09-12 19:58                           ` Martin Schlemmer
2003-09-12 20:00                           ` Adrian Bunk
2003-09-15  0:15                           ` bill davidsen
2003-09-14 23:51                       ` bill davidsen
2003-09-14 23:49                     ` bill davidsen
2003-09-14 23:47                 ` bill davidsen
2003-09-15  1:02                   ` Zwane Mwaikambo
2003-09-15  2:08                     ` Nick Piggin
2003-09-15  3:55                     ` Bill Davidsen
2003-09-15  7:45                       ` Alan Cox
2003-09-15 12:11                         ` Bill Davidsen
2003-09-15 13:48                           ` Alan Cox
2003-09-15 18:50                             ` Bill Davidsen
2003-09-12 18:03               ` Mike Fedyk
2003-09-11 13:54   ` Linus Torvalds
2003-09-11 14:01     ` Andi Kleen
2003-09-11 14:14       ` Dave Jones
2003-09-11 14:29         ` Andi Kleen
2003-09-11 14:14     ` Alan Cox
2003-09-11 14:24       ` Andi Kleen
2003-09-11 14:28         ` Dave Jones
2003-09-11 14:32           ` Andi Kleen
2003-09-11 20:14         ` bill davidsen
2003-09-11 16:58   ` Jamie Lokier
2003-09-11 17:05     ` Andi Kleen
2003-09-11 17:32       ` Jamie Lokier
2003-09-11 17:39         ` Andi Kleen
2003-09-11 17:48           ` Jamie Lokier
2003-09-11 18:18             ` Andi Kleen
2003-09-11 18:59               ` Jamie Lokier
2003-09-11  3:43 Nakajima, Jun
2003-09-11  4:03 ` Valdis.Kletnieks
     [not found] <uqD5.3BI.3@gated-at.bofh.it>
2003-09-11  4:14 ` Andi Kleen
2003-09-11  4:58   ` dada1
2003-09-11  5:11     ` Andi Kleen
2003-09-11  5:58       ` dada1
2003-09-11  4:55 richard.brunner
2003-09-11 16:55 ` Jamie Lokier
2003-09-12 14:14 ` Martin Schlemmer
2003-09-11 17:09 richard.brunner
2003-09-11 17:14 richard.brunner
2003-09-11 17:17 richard.brunner
2003-09-13 16:54 ` Pavel Machek
2003-09-12 21:24 John Bradford
2003-09-15  6:32 John Bradford
2003-09-15  7:40 ` Alan Cox
2003-09-15 12:02   ` Bill Davidsen
2003-09-15 11:48 ` Bill Davidsen
2003-09-15 20:55 ` Adrian Bunk
2003-09-16  0:26   ` Bill Davidsen
2003-09-15  8:31 John Bradford
2003-09-15  8:32 ` Nick Piggin
2003-09-15 20:51   ` Adrian Bunk
2003-09-15  9:39 John Bradford
2003-09-15  9:58 ` Nick Piggin
2003-09-15 10:54 John Bradford
2003-09-15 10:52 ` Nick Piggin
2003-09-15 13:45 ` Alan Cox
2003-09-15 18:44   ` Bill Davidsen
2003-09-15 11:46 John Bradford
2003-09-15 12:38 ` Nick Piggin
2003-09-15 13:46   ` Chris Meadors
2003-09-15 14:00     ` Nick Piggin
2003-09-16 15:06   ` Bill Davidsen
2003-09-16 15:24     ` Nick Piggin
2003-09-15 12:28 Mikael Pettersson
2003-09-15 18:13 ` Bill Davidsen
2003-09-16 11:54 ` Jamie Lokier
2003-09-15 12:43 John Bradford
2003-09-15 18:21 ` Bill Davidsen
2003-09-15 14:21 John Bradford
2003-09-15 16:21 richard.brunner
2003-09-15 19:15 ` Bill Davidsen
2003-09-16 11:46 ` Jamie Lokier
2003-09-16 13:30   ` Dave Jones
2003-09-16 13:52     ` Bill Davidsen
2003-09-16 15:25       ` Timothy Miller
2003-09-16 16:53         ` Bill Davidsen
2003-09-16 17:22         ` Jamie Lokier
2003-09-16 17:23       ` Jamie Lokier
2003-09-18  7:43 ` Pavel Machek
2003-09-18 14:05   ` Dave Jones
2003-09-18 15:56     ` Jamie Lokier
2003-09-18 17:34   ` Bill Davidsen
     [not found] <200309150632.h8F6WnHb000589@81-2-122-30.bradfords.org.uk.suse.lists.linux.kernel>
     [not found] ` <1063611650.2674.1.camel@dhcp23.swansea.linux.org.uk.suse.lists.linux.kernel>
2003-09-15 18:29   ` Andi Kleen
2003-09-15 19:19 John Bradford
2003-09-15 19:34 John Bradford
2003-09-15 19:25 ` Bill Davidsen
2003-09-15 22:28 ` Alan Cox
2003-09-15 19:51 richard.brunner
2003-09-16  0:01 ` David Lang
2003-09-16  0:20 ` Bill Davidsen
2003-09-16 11:50 ` Jamie Lokier
2003-09-16 13:46   ` Bill Davidsen
2003-09-16 17:21     ` Jamie Lokier
2003-09-15 20:03 Nakajima, Jun
2003-09-15 20:20 Nakajima, Jun
2003-09-16  2:23 richard.brunner

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20030911012708.GD3134@wotan.suse.de \
    --to=ak@suse.de \
    --cc=akpm@osdl.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=richard.brunner@amd.com \
    --cc=torvalds@osdl.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).