Linus Torvalds wrote:
> 
> On Fri, 13 Oct 2000, Brian Gerst wrote:
> >
> > Also, Could somebody who has a machine with a known buggy processor give
> > this patch a try?
> 
> I like the patch. Would you mind re-writing the exception handling the
> other way around, though:

[snip]

> which basically means that if flag stays as "1", then the exception
> happened, but if the exception didn't happen the code will fall through
> the "xor" and clear "flag".
> 
> After that, and testing that it works on a broken machine, I'd love to
> apply it.
> 
>                 Linus

Patch reworked

-- 

                                                Brian Gerst
diff -urN linux-2.4.0t10p2/Documentation/exception.txt 
linux/Documentation/exception.txt
--- linux-2.4.0t10p2/Documentation/exception.txt        Fri Jul 28 01:28:07 2000
+++ linux/Documentation/exception.txt   Sat Oct 14 08:55:03 2000
@@ -284,3 +284,9 @@
 successful, -EFAULT on failure. Our original code did not test this
 return value, however the inline assembly code in get_user tries to
 return -EFAULT. GCC selected EAX to return this value.
+
+NOTE:
+Due to the way that the exception table is built and needs to be ordered,
+only use exceptions for code in the .text section.  Any other section
+will cause the exception table to not be sorted correctly, and the
+exceptions will fail.
diff -urN linux-2.4.0t10p2/arch/i386/mm/fault.c linux/arch/i386/mm/fault.c
--- linux-2.4.0t10p2/arch/i386/mm/fault.c       Thu Oct 12 19:48:23 2000
+++ linux/arch/i386/mm/fault.c  Sat Oct 14 08:55:03 2000
@@ -77,31 +77,6 @@
        return 0;
 }
 
-static void __init handle_wp_test (void)
-{
-       const unsigned long vaddr = PAGE_OFFSET;
-       pgd_t *pgd;
-       pmd_t *pmd;
-       pte_t *pte;
-
-       /*
-        * make it read/writable temporarily, so that the fault
-        * can be handled.
-        */
-       pgd = swapper_pg_dir + __pgd_offset(vaddr);
-       pmd = pmd_offset(pgd, vaddr);
-       pte = pte_offset(pmd, vaddr);
-       *pte = mk_pte_phys(0, PAGE_KERNEL);
-       __flush_tlb_all();
-
-       boot_cpu_data.wp_works_ok = 1;
-       /*
-        * Beware: Black magic here. The printk is needed here to flush
-        * CPU state on certain buggy processors.
-        */
-       printk("Ok");
-}
-
 asmlinkage void do_invalid_op(struct pt_regs *, unsigned long);
 extern unsigned long idt;
 
@@ -274,14 +249,7 @@
 /*
  * Oops. The kernel tried to access some bad page. We'll have to
  * terminate things with extreme prejudice.
- *
- * First we check if it was the bootup rw-test, though..
  */
-       if (boot_cpu_data.wp_works_ok < 0 &&
-                       address == PAGE_OFFSET && (error_code & 1)) {
-               handle_wp_test();
-               return;
-       }
 
        if (address < PAGE_SIZE)
                printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
diff -urN linux-2.4.0t10p2/arch/i386/mm/init.c linux/arch/i386/mm/init.c
--- linux-2.4.0t10p2/arch/i386/mm/init.c        Thu Aug 10 08:10:02 2000
+++ linux/arch/i386/mm/init.c   Sat Oct 14 09:10:09 2000
@@ -491,16 +491,42 @@
  * before and after the test are here to work-around some nasty CPU bugs.
  */
 
+/*
+ * This function cannot be __init, since exceptions don't work in that
+ * section.
+ */
+static int do_test_wp_bit(unsigned long vaddr)
+{
+       char tmp_reg;
+       int flag;
+
+       __asm__ __volatile__(
+               "       movb %0,%1      \n"
+               "1:     movb %1,%0      \n"
+               "       xorl %2,%2      \n"
+               "2:                     \n"
+               ".section __ex_table,\"a\"\n"
+               "       .align 4        \n"
+               "       .long 1b,2b     \n"
+               ".previous              \n"
+               :"=m" (*(char *) vaddr),
+                "=q" (tmp_reg),
+                "=r" (flag)
+               :"2" (1)
+               :"memory");
+       
+       return flag;
+}
+
 void __init test_wp_bit(void)
 {
 /*
- * Ok, all PAE-capable CPUs are definitely handling the WP bit right.
+ * Ok, all PSE-capable CPUs are definitely handling the WP bit right.
  */
        const unsigned long vaddr = PAGE_OFFSET;
        pgd_t *pgd;
        pmd_t *pmd;
        pte_t *pte, old_pte;
-       char tmp_reg;
 
        printk("Checking if this processor honours the WP bit even in supervisor 
mode... ");
 
@@ -511,27 +537,19 @@
        *pte = mk_pte_phys(0, PAGE_READONLY);
        local_flush_tlb();
 
-       __asm__ __volatile__(
-               "jmp 1f; 1:\n"
-               "movb %0,%1\n"
-               "movb %1,%0\n"
-               "jmp 1f; 1:\n"
-               :"=m" (*(char *) vaddr),
-                "=q" (tmp_reg)
-               :/* no inputs */
-               :"memory");
+       boot_cpu_data.wp_works_ok = do_test_wp_bit(vaddr);
 
        *pte = old_pte;
        local_flush_tlb();
 
-       if (boot_cpu_data.wp_works_ok < 0) {
-               boot_cpu_data.wp_works_ok = 0;
+       if (!boot_cpu_data.wp_works_ok) {
                printk("No.\n");
 #ifdef CONFIG_X86_WP_WORKS_OK
                panic("This kernel doesn't support CPU's with broken WP. Recompile it 
for a 386!");
 #endif
-       } else
-               printk(".\n");
+       } else {
+               printk("Ok.\n");
+       }
 }
 
 static inline int page_is_ram (unsigned long pagenr)

Reply via email to