Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * linux/arch/alpha/mm/extable.c | |
3 | */ | |
4 | ||
1da177e4 | 5 | #include <linux/module.h> |
08a42e86 | 6 | #include <linux/sort.h> |
1da177e4 LT |
7 | #include <asm/uaccess.h> |
8 | ||
08a42e86 IK |
9 | static inline unsigned long ex_to_addr(const struct exception_table_entry *x) |
10 | { | |
11 | return (unsigned long)&x->insn + x->insn; | |
12 | } | |
13 | ||
14 | static void swap_ex(void *a, void *b, int size) | |
15 | { | |
16 | struct exception_table_entry *ex_a = a, *ex_b = b; | |
17 | unsigned long addr_a = ex_to_addr(ex_a), addr_b = ex_to_addr(ex_b); | |
18 | unsigned int t = ex_a->fixup.unit; | |
19 | ||
20 | ex_a->fixup.unit = ex_b->fixup.unit; | |
21 | ex_b->fixup.unit = t; | |
22 | ex_a->insn = (int)(addr_b - (unsigned long)&ex_a->insn); | |
23 | ex_b->insn = (int)(addr_a - (unsigned long)&ex_b->insn); | |
24 | } | |
25 | ||
26 | /* | |
27 | * The exception table needs to be sorted so that the binary | |
28 | * search that we use to find entries in it works properly. | |
29 | * This is used both for the kernel exception table and for | |
30 | * the exception tables of modules that get loaded. | |
31 | */ | |
32 | static int cmp_ex(const void *a, const void *b) | |
33 | { | |
34 | const struct exception_table_entry *x = a, *y = b; | |
35 | ||
36 | /* avoid overflow */ | |
37 | if (ex_to_addr(x) > ex_to_addr(y)) | |
38 | return 1; | |
39 | if (ex_to_addr(x) < ex_to_addr(y)) | |
40 | return -1; | |
41 | return 0; | |
42 | } | |
43 | ||
1da177e4 LT |
44 | void sort_extable(struct exception_table_entry *start, |
45 | struct exception_table_entry *finish) | |
46 | { | |
08a42e86 IK |
47 | sort(start, finish - start, sizeof(struct exception_table_entry), |
48 | cmp_ex, swap_ex); | |
1da177e4 LT |
49 | } |
50 | ||
ad6561df RR |
51 | #ifdef CONFIG_MODULES |
52 | /* | |
53 | * Any entry referring to the module init will be at the beginning or | |
54 | * the end. | |
55 | */ | |
56 | void trim_init_extable(struct module *m) | |
57 | { | |
58 | /*trim the beginning*/ | |
59 | while (m->num_exentries && | |
60 | within_module_init(ex_to_addr(&m->extable[0]), m)) { | |
61 | m->extable++; | |
62 | m->num_exentries--; | |
63 | } | |
64 | /*trim the end*/ | |
65 | while (m->num_exentries && | |
66 | within_module_init(ex_to_addr(&m->extable[m->num_exentries-1]), | |
67 | m)) | |
68 | m->num_exentries--; | |
69 | } | |
70 | #endif /* CONFIG_MODULES */ | |
71 | ||
1da177e4 LT |
72 | const struct exception_table_entry * |
73 | search_extable(const struct exception_table_entry *first, | |
74 | const struct exception_table_entry *last, | |
75 | unsigned long value) | |
76 | { | |
77 | while (first <= last) { | |
78 | const struct exception_table_entry *mid; | |
79 | unsigned long mid_value; | |
80 | ||
81 | mid = (last - first) / 2 + first; | |
08a42e86 | 82 | mid_value = ex_to_addr(mid); |
1da177e4 LT |
83 | if (mid_value == value) |
84 | return mid; | |
85 | else if (mid_value < value) | |
86 | first = mid+1; | |
87 | else | |
88 | last = mid-1; | |
89 | } | |
90 | ||
91 | return NULL; | |
92 | } |