diff options
author | Ingo Molnar <mingo@elte.hu> | 2009-05-12 12:17:30 +0200 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-05-12 12:17:36 +0200 |
commit | 6cda3eb62ef42aa5acd649bf99c8db544e0f4051 (patch) | |
tree | 93f74ca002f5756c8e157611174f9540b5cf41c0 /arch/alpha/mm/extable.c | |
parent | b9c61b70075c87a8612624736faf4a2de5b1ed30 (diff) | |
parent | cec6be6d1069d697beb490bbb40a290d5ff554a2 (diff) |
Merge branch 'x86/apic' into irq/numa
Merge reason: both topics modify the APIC code but were able to do it in
parallel so far. An upcoming patch generates a conflict so
merge them to avoid the conflict.
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/alpha/mm/extable.c')
-rw-r--r-- | arch/alpha/mm/extable.c | 40 |
1 files changed, 39 insertions, 1 deletions
diff --git a/arch/alpha/mm/extable.c b/arch/alpha/mm/extable.c index dc7aeda1577..62dc379d301 100644 --- a/arch/alpha/mm/extable.c +++ b/arch/alpha/mm/extable.c @@ -3,11 +3,49 @@ */ #include <linux/module.h> +#include <linux/sort.h> #include <asm/uaccess.h> +static inline unsigned long ex_to_addr(const struct exception_table_entry *x) +{ + return (unsigned long)&x->insn + x->insn; +} + +static void swap_ex(void *a, void *b, int size) +{ + struct exception_table_entry *ex_a = a, *ex_b = b; + unsigned long addr_a = ex_to_addr(ex_a), addr_b = ex_to_addr(ex_b); + unsigned int t = ex_a->fixup.unit; + + ex_a->fixup.unit = ex_b->fixup.unit; + ex_b->fixup.unit = t; + ex_a->insn = (int)(addr_b - (unsigned long)&ex_a->insn); + ex_b->insn = (int)(addr_a - (unsigned long)&ex_b->insn); +} + +/* + * The exception table needs to be sorted so that the binary + * search that we use to find entries in it works properly. + * This is used both for the kernel exception table and for + * the exception tables of modules that get loaded. + */ +static int cmp_ex(const void *a, const void *b) +{ + const struct exception_table_entry *x = a, *y = b; + + /* avoid overflow */ + if (ex_to_addr(x) > ex_to_addr(y)) + return 1; + if (ex_to_addr(x) < ex_to_addr(y)) + return -1; + return 0; +} + void sort_extable(struct exception_table_entry *start, struct exception_table_entry *finish) { + sort(start, finish - start, sizeof(struct exception_table_entry), + cmp_ex, swap_ex); } const struct exception_table_entry * @@ -20,7 +58,7 @@ search_extable(const struct exception_table_entry *first, unsigned long mid_value; mid = (last - first) / 2 + first; - mid_value = (unsigned long)&mid->insn + mid->insn; + mid_value = ex_to_addr(mid); if (mid_value == value) return mid; else if (mid_value < value) |