File: /usr/src/linux/arch/ppc/mm/extable.c
1 /*
2 * BK Id: SCCS/s.extable.c 1.5 05/17/01 18:14:23 cort
3 */
4 /*
5 * linux/arch/ppc/mm/extable.c
6 *
7 * from linux/arch/i386/mm/extable.c
8 */
9
10 #include <linux/config.h>
11 #include <linux/module.h>
12 #include <asm/uaccess.h>
13
14 extern struct exception_table_entry __start___ex_table[];
15 extern struct exception_table_entry __stop___ex_table[];
16
17 /*
18 * The exception table needs to be sorted because we use the macros
19 * which put things into the exception table in a variety of segments
20 * such as the prep, pmac, chrp, etc. segments as well as the init
21 * segment and the main kernel text segment.
22 */
23 static inline void
24 sort_ex_table(struct exception_table_entry *start,
25 struct exception_table_entry *finish)
26 {
27 struct exception_table_entry el, *p, *q;
28
29 /* insertion sort */
30 for (p = start + 1; p < finish; ++p) {
31 /* start .. p-1 is sorted */
32 if (p[0].insn < p[-1].insn) {
33 /* move element p down to its right place */
34 el = *p;
35 q = p;
36 do {
37 /* el comes before q[-1], move q[-1] up one */
38 q[0] = q[-1];
39 --q;
40 } while (q > start && el.insn < q[-1].insn);
41 *q = el;
42 }
43 }
44 }
45
46 void
47 sort_exception_table(void)
48 {
49 sort_ex_table(__start___ex_table, __stop___ex_table);
50 }
51
52 static inline unsigned long
53 search_one_table(const struct exception_table_entry *first,
54 const struct exception_table_entry *last,
55 unsigned long value)
56 {
57 while (first <= last) {
58 const struct exception_table_entry *mid;
59 long diff;
60
61 mid = (last - first) / 2 + first;
62 diff = mid->insn - value;
63 if (diff == 0)
64 return mid->fixup;
65 else if (diff < 0)
66 first = mid+1;
67 else
68 last = mid-1;
69 }
70 return 0;
71 }
72
73 unsigned long
74 search_exception_table(unsigned long addr)
75 {
76 unsigned long ret;
77
78 #ifndef CONFIG_MODULES
79 /* There is only the kernel to search. */
80 ret = search_one_table(__start___ex_table, __stop___ex_table-1, addr);
81 if (ret) return ret;
82 #else
83 /* The kernel is the last "module" -- no need to treat it special. */
84 struct module *mp;
85 for (mp = module_list; mp != NULL; mp = mp->next) {
86 if (mp->ex_table_start == NULL)
87 continue;
88 ret = search_one_table(mp->ex_table_start,
89 mp->ex_table_end - 1, addr);
90 if (ret)
91 return ret;
92 }
93 #endif
94
95 return 0;
96 }
97