Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * linux/arch/sparc/mm/extable.c | |
3 | */ | |
4 | ||
5 | #include <linux/config.h> | |
6 | #include <linux/module.h> | |
7 | #include <asm/uaccess.h> | |
8 | ||
9 | void sort_extable(struct exception_table_entry *start, | |
10 | struct exception_table_entry *finish) | |
11 | { | |
12 | } | |
13 | ||
14 | /* Caller knows they are in a range if ret->fixup == 0 */ | |
15 | const struct exception_table_entry * | |
16 | search_extable(const struct exception_table_entry *start, | |
17 | const struct exception_table_entry *last, | |
18 | unsigned long value) | |
19 | { | |
20 | const struct exception_table_entry *walk; | |
21 | ||
22 | /* Single insn entries are encoded as: | |
23 | * word 1: insn address | |
24 | * word 2: fixup code address | |
25 | * | |
26 | * Range entries are encoded as: | |
27 | * word 1: first insn address | |
28 | * word 2: 0 | |
29 | * word 3: last insn address + 4 bytes | |
30 | * word 4: fixup code address | |
31 | * | |
32 | * See asm/uaccess.h for more details. | |
33 | */ | |
34 | ||
35 | /* 1. Try to find an exact match. */ | |
36 | for (walk = start; walk <= last; walk++) { | |
37 | if (walk->fixup == 0) { | |
38 | /* A range entry, skip both parts. */ | |
39 | walk++; | |
40 | continue; | |
41 | } | |
42 | ||
43 | if (walk->insn == value) | |
44 | return walk; | |
45 | } | |
46 | ||
47 | /* 2. Try to find a range match. */ | |
48 | for (walk = start; walk <= (last - 1); walk++) { | |
49 | if (walk->fixup) | |
50 | continue; | |
51 | ||
52 | if (walk[0].insn <= value && walk[1].insn > value) | |
53 | return walk; | |
54 | ||
55 | walk++; | |
56 | } | |
57 | ||
58 | return NULL; | |
59 | } | |
60 | ||
61 | /* Special extable search, which handles ranges. Returns fixup */ | |
62 | unsigned long search_extables_range(unsigned long addr, unsigned long *g2) | |
63 | { | |
64 | const struct exception_table_entry *entry; | |
65 | ||
66 | entry = search_exception_tables(addr); | |
67 | if (!entry) | |
68 | return 0; | |
69 | ||
70 | /* Inside range? Fix g2 and return correct fixup */ | |
71 | if (!entry->fixup) { | |
72 | *g2 = (addr - entry->insn) / 4; | |
73 | return (entry + 1)->fixup; | |
74 | } | |
75 | ||
76 | return entry->fixup; | |
77 | } |