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