]> git.hungrycats.org Git - linux/commitdiff
ia64: Implement exception-table sorting for real.
authorDavid Mosberger <davidm@tiger.hpl.hp.com>
Tue, 27 Jan 2004 13:23:19 +0000 (05:23 -0800)
committerDavid Mosberger <davidm@tiger.hpl.hp.com>
Tue, 27 Jan 2004 13:23:19 +0000 (05:23 -0800)
arch/ia64/kernel/unaligned.c
arch/ia64/mm/extable.c
arch/ia64/mm/fault.c
include/asm-ia64/uaccess.h

index 95f77b1dfa117db9693076cb4ba57b8cb6d3fcb6..6cb14f493cd9f05f74ef953564063e8f9f1b82ff 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Architecture-specific unaligned trap handling.
  *
- * Copyright (C) 1999-2002 Hewlett-Packard Co
+ * Copyright (C) 1999-2002, 2004 Hewlett-Packard Co
  *     Stephane Eranian <eranian@hpl.hp.com>
  *     David Mosberger-Tang <davidm@hpl.hp.com>
  *
@@ -1328,7 +1328,7 @@ ia64_handle_unaligned (unsigned long ifa, struct pt_regs *regs)
         * handler into reading an arbitrary kernel addresses...
         */
        if (!user_mode(regs))
-               eh = SEARCH_EXCEPTION_TABLE(regs);
+               eh = search_exception_tables(regs->cr_iip + ia64_psr(regs)->ri);
        if (user_mode(regs) || eh) {
                if ((current->thread.flags & IA64_THREAD_UAC_SIGBUS) != 0)
                        goto force_sigbus;
index 7f7955395173d5ec446699e4ca5efc40001c6bac..58ef7a74601235d56d49fea66267fe0d7c748644 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Kernel exception handling table support.  Derived from arch/alpha/mm/extable.c.
  *
- * Copyright (C) 1998, 1999, 2001-2002 Hewlett-Packard Co
+ * Copyright (C) 1998, 1999, 2001-2002, 2004 Hewlett-Packard Co
  *     David Mosberger-Tang <davidm@hpl.hp.com>
  */
 
 #include <asm/uaccess.h>
 #include <asm/module.h>
 
-void sort_extable(struct exception_table_entry *start,
-                 struct exception_table_entry *finish)
+static inline int
+compare_entries (struct exception_table_entry *l, struct exception_table_entry *r)
 {
+       u64 lip = (u64) &l->addr + l->addr;
+       u64 rip = (u64) &r->addr + r->addr;
+
+       if (lip < rip)
+               return -1;
+       if (lip == rip)
+               return 0;
+       else
+               return 1;
+}
+
+static inline void
+swap_entries (struct exception_table_entry *l, struct exception_table_entry *r)
+{
+       u64 delta = (u64) r - (u64) l;
+       struct exception_table_entry tmp;
+
+       tmp = *l;
+       l->addr = r->addr + delta;
+       l->cont = r->cont + delta;
+       r->addr = tmp.addr - delta;
+       r->cont = tmp.cont - delta;
+}
+
+/*
+ * Sort the exception table.  It's usually already sorted, but there may be unordered
+ * entries due to multiple text sections (such as the .init text section).  Note that the
+ * exception-table-entries contain location-relative addresses, which requires a bit of
+ * care during sorting to avoid overflows in the offset members (e.g., it would not be
+ * safe to make a temporary copy of an exception-table entry on the stack, because the
+ * stack may be more than 2GB away from the exception-table).
+ */
+void
+sort_extable (struct exception_table_entry *start, struct exception_table_entry *finish)
+{
+       struct exception_table_entry *p, *q;
+
+       /* insertion sort */
+       for (p = start + 1; p < finish; ++p)
+               /* start .. p-1 is sorted; push p down to it's proper place */
+               for (q = p; q > start && compare_entries(&q[0], &q[-1]) < 0; --q)
+                       swap_entries(&q[0], &q[-1]);
 }
 
 const struct exception_table_entry *
index fa66ec8b4cfb4beb8f7ab1517f47b91ecf834645..9584a1b2248ab54e943fa78634439d42848d3b33 100644 (file)
@@ -58,7 +58,7 @@ mapped_kernel_page_is_present (unsigned long address)
        if (pgd_none(*pgd) || pgd_bad(*pgd))
                return 0;
 
-       pmd = pmd_offset(pgd,address);
+       pmd = pmd_offset(pgd, address);
        if (pmd_none(*pmd) || pmd_bad(*pmd))
                return 0;
 
index add46cb74d48a13f9e5cf1740bc4244b97879a58..60e77a780790457deea6e178d39fa88b11243ebd 100644 (file)
@@ -28,7 +28,7 @@
  *
  * Based on <asm-alpha/uaccess.h>.
  *
- * Copyright (C) 1998, 1999, 2001-2003 Hewlett-Packard Co
+ * Copyright (C) 1998, 1999, 2001-2004 Hewlett-Packard Co
  *     David Mosberger-Tang <davidm@hpl.hp.com>
  */
 
@@ -283,24 +283,23 @@ extern unsigned long __strnlen_user (const char *, long);
        __su_ret;                                               \
 })
 
+/* Generic code can't deal with the location-relative format that we use for compactness.  */
 #define ARCH_HAS_SORT_EXTABLE
 #define ARCH_HAS_SEARCH_EXTABLE
 
 struct exception_table_entry {
-       int addr;       /* gp-relative address of insn this fixup is for */
-       int cont;       /* gp-relative continuation address; if bit 2 is set, r9 is set to 0 */
+       int addr;       /* location-relative address of insn this fixup is for */
+       int cont;       /* location-relative continuation addr.; if bit 2 is set, r9 is set to 0 */
 };
 
 extern void handle_exception (struct pt_regs *regs, const struct exception_table_entry *e);
 extern const struct exception_table_entry *search_exception_tables (unsigned long addr);
 
-# define SEARCH_EXCEPTION_TABLE(regs) search_exception_tables(regs->cr_iip + ia64_psr(regs)->ri)
-
 static inline int
 done_with_exception (struct pt_regs *regs)
 {
        const struct exception_table_entry *e;
-       e = SEARCH_EXCEPTION_TABLE(regs);
+       e = search_exception_tables(regs->cr_iip + ia64_psr(regs)->ri);
        if (e) {
                handle_exception(regs, e);
                return 1;