]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
extable: add support for relative extables to search and sort routines
authorArd Biesheuvel <ard.biesheuvel@linaro.org>
Tue, 9 Feb 2016 23:13:15 +0000 (10:13 +1100)
committerStephen Rothwell <sfr@canb.auug.org.au>
Tue, 9 Feb 2016 23:13:15 +0000 (10:13 +1100)
There are currently four architectures (x86, ia64, alpha and s390) whose
user-access exception tables are relative to the table entry address
rather than absolute.  Each of these architectures has its own
search_extable() and sort_extable() implementation, which are not only
mostly identical to each other, but also deviate very little from the
generic absolute implementations in lib/extable.c that they override.

So before making arm64 the fifth architecture that reimplements this,
let's refactor the existing code so that all of these architectures use
common code for searching and sorting the relative extables.  Archs may
set ARCH_HAS_RELATIVE_EXTABLE to indicate that the table consists of a
pair of relative ints, and may define swap_ex_entry_fixup() if the fixup
member needs special treatment in the swapping step of the sorting routine
(such as alpha).

This patch (of 6):

Add support to the generic search_extable() and sort_extable()
implementations for dealing with exception table entries whose fields
contain relative offsets rather than absolute addresses.

Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Acked-by: Helge Deller <deller@gmx.de>
Acked-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Acked-by: H. Peter Anvin <hpa@linux.intel.com>
Acked-by: Tony Luck <tony.luck@intel.com>
Acked-by: Will Deacon <will.deacon@arm.com>
Acked-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
lib/extable.c

index 4cac81ec225e09af4cfd69c36d63a574a8418110..0be02ad561e9e346c01a65434873f9960472047a 100644 (file)
 #include <linux/sort.h>
 #include <asm/uaccess.h>
 
+#ifndef ARCH_HAS_RELATIVE_EXTABLE
+#define ex_to_insn(x)  ((x)->insn)
+#else
+static inline unsigned long ex_to_insn(const struct exception_table_entry *x)
+{
+       return (unsigned long)&x->insn + x->insn;
+}
+#endif
+
 #ifndef ARCH_HAS_SORT_EXTABLE
+#ifndef ARCH_HAS_RELATIVE_EXTABLE
+#define swap_ex                NULL
+#else
+static void swap_ex(void *a, void *b, int size)
+{
+       struct exception_table_entry *x = a, *y = b, tmp;
+       int delta = b - a;
+
+       tmp = *x;
+       x->insn = y->insn + delta;
+       y->insn = tmp.insn - delta;
+
+#ifdef swap_ex_entry_fixup
+       swap_ex_entry_fixup(x, y, tmp, delta);
+#else
+       x->fixup = y->fixup + delta;
+       y->fixup = tmp.fixup - delta;
+#endif
+}
+#endif /* ARCH_HAS_RELATIVE_EXTABLE */
+
 /*
  * The exception table needs to be sorted so that the binary
  * search that we use to find entries in it works properly.
@@ -26,9 +56,9 @@ static int cmp_ex(const void *a, const void *b)
        const struct exception_table_entry *x = a, *y = b;
 
        /* avoid overflow */
-       if (x->insn > y->insn)
+       if (ex_to_insn(x) > ex_to_insn(y))
                return 1;
-       if (x->insn < y->insn)
+       if (ex_to_insn(x) < ex_to_insn(y))
                return -1;
        return 0;
 }
@@ -37,7 +67,7 @@ void sort_extable(struct exception_table_entry *start,
                  struct exception_table_entry *finish)
 {
        sort(start, finish - start, sizeof(struct exception_table_entry),
-            cmp_ex, NULL);
+            cmp_ex, swap_ex);
 }
 
 #ifdef CONFIG_MODULES
@@ -48,13 +78,15 @@ void sort_extable(struct exception_table_entry *start,
 void trim_init_extable(struct module *m)
 {
        /*trim the beginning*/
-       while (m->num_exentries && within_module_init(m->extable[0].insn, m)) {
+       while (m->num_exentries &&
+              within_module_init(ex_to_insn(&m->extable[0]), m)) {
                m->extable++;
                m->num_exentries--;
        }
        /*trim the end*/
        while (m->num_exentries &&
-               within_module_init(m->extable[m->num_exentries-1].insn, m))
+              within_module_init(ex_to_insn(&m->extable[m->num_exentries - 1]),
+                                 m))
                m->num_exentries--;
 }
 #endif /* CONFIG_MODULES */
@@ -81,13 +113,13 @@ search_extable(const struct exception_table_entry *first,
                 * careful, the distance between value and insn
                 * can be larger than MAX_LONG:
                 */
-               if (mid->insn < value)
+               if (ex_to_insn(mid) < value)
                        first = mid + 1;
-               else if (mid->insn > value)
+               else if (ex_to_insn(mid) > value)
                        last = mid - 1;
                else
                        return mid;
-        }
-        return NULL;
+       }
+       return NULL;
 }
 #endif