Commit | Line | Data |
---|---|---|
b2441318 | 1 | // SPDX-License-Identifier: GPL-2.0 |
1da177e4 LT |
2 | /* |
3 | * linux/arch/sparc/mm/extable.c | |
4 | */ | |
5 | ||
1da177e4 | 6 | #include <linux/module.h> |
5437344c | 7 | #include <linux/extable.h> |
7c0f6ba6 | 8 | #include <linux/uaccess.h> |
1da177e4 LT |
9 | |
10 | void sort_extable(struct exception_table_entry *start, | |
11 | struct exception_table_entry *finish) | |
12 | { | |
13 | } | |
14 | ||
15 | /* Caller knows they are in a range if ret->fixup == 0 */ | |
16 | const struct exception_table_entry * | |
a94c33dd TM |
17 | search_extable(const struct exception_table_entry *base, |
18 | const size_t num, | |
1da177e4 LT |
19 | unsigned long value) |
20 | { | |
a94c33dd | 21 | int i; |
1da177e4 LT |
22 | |
23 | /* Single insn entries are encoded as: | |
24 | * word 1: insn address | |
25 | * word 2: fixup code address | |
26 | * | |
27 | * Range entries are encoded as: | |
28 | * word 1: first insn address | |
29 | * word 2: 0 | |
30 | * word 3: last insn address + 4 bytes | |
31 | * word 4: fixup code address | |
32 | * | |
ad6561df RR |
33 | * Deleted entries are encoded as: |
34 | * word 1: unused | |
35 | * word 2: -1 | |
36 | * | |
1da177e4 LT |
37 | * See asm/uaccess.h for more details. |
38 | */ | |
39 | ||
40 | /* 1. Try to find an exact match. */ | |
a94c33dd TM |
41 | for (i = 0; i < num; i++) { |
42 | if (base[i].fixup == 0) { | |
1da177e4 | 43 | /* A range entry, skip both parts. */ |
a94c33dd | 44 | i++; |
1da177e4 LT |
45 | continue; |
46 | } | |
47 | ||
ad6561df | 48 | /* A deleted entry; see trim_init_extable */ |
a94c33dd | 49 | if (base[i].fixup == -1) |
ad6561df RR |
50 | continue; |
51 | ||
a94c33dd TM |
52 | if (base[i].insn == value) |
53 | return &base[i]; | |
1da177e4 LT |
54 | } |
55 | ||
56 | /* 2. Try to find a range match. */ | |
a94c33dd TM |
57 | for (i = 0; i < (num - 1); i++) { |
58 | if (base[i].fixup) | |
1da177e4 LT |
59 | continue; |
60 | ||
a94c33dd TM |
61 | if (base[i].insn <= value && base[i + 1].insn > value) |
62 | return &base[i]; | |
1da177e4 | 63 | |
a94c33dd | 64 | i++; |
1da177e4 LT |
65 | } |
66 | ||
67 | return NULL; | |
68 | } | |
69 | ||
ad6561df RR |
70 | #ifdef CONFIG_MODULES |
71 | /* We could memmove them around; easier to mark the trimmed ones. */ | |
72 | void trim_init_extable(struct module *m) | |
73 | { | |
74 | unsigned int i; | |
75 | bool range; | |
76 | ||
77 | for (i = 0; i < m->num_exentries; i += range ? 2 : 1) { | |
78 | range = m->extable[i].fixup == 0; | |
79 | ||
80 | if (within_module_init(m->extable[i].insn, m)) { | |
81 | m->extable[i].fixup = -1; | |
82 | if (range) | |
83 | m->extable[i+1].fixup = -1; | |
84 | } | |
85 | if (range) | |
86 | i++; | |
87 | } | |
88 | } | |
89 | #endif /* CONFIG_MODULES */ | |
90 | ||
1da177e4 LT |
91 | /* Special extable search, which handles ranges. Returns fixup */ |
92 | unsigned long search_extables_range(unsigned long addr, unsigned long *g2) | |
93 | { | |
94 | const struct exception_table_entry *entry; | |
95 | ||
96 | entry = search_exception_tables(addr); | |
97 | if (!entry) | |
98 | return 0; | |
99 | ||
100 | /* Inside range? Fix g2 and return correct fixup */ | |
101 | if (!entry->fixup) { | |
102 | *g2 = (addr - entry->insn) / 4; | |
103 | return (entry + 1)->fixup; | |
104 | } | |
105 | ||
106 | return entry->fixup; | |
107 | } |