Linux-libre 5.3.12-gnu
[librecmc/linux-libre.git] / arch / sparc / mm / extable.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * linux/arch/sparc/mm/extable.c
4  */
5
6 #include <linux/module.h>
7 #include <linux/extable.h>
8 #include <linux/uaccess.h>
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 *
17 search_extable(const struct exception_table_entry *base,
18                const size_t num,
19                unsigned long value)
20 {
21         int i;
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          *
33          * Deleted entries are encoded as:
34          *      word 1: unused
35          *      word 2: -1
36          *
37          * See asm/uaccess.h for more details.
38          */
39
40         /* 1. Try to find an exact match. */
41         for (i = 0; i < num; i++) {
42                 if (base[i].fixup == 0) {
43                         /* A range entry, skip both parts. */
44                         i++;
45                         continue;
46                 }
47
48                 /* A deleted entry; see trim_init_extable */
49                 if (base[i].fixup == -1)
50                         continue;
51
52                 if (base[i].insn == value)
53                         return &base[i];
54         }
55
56         /* 2. Try to find a range match. */
57         for (i = 0; i < (num - 1); i++) {
58                 if (base[i].fixup)
59                         continue;
60
61                 if (base[i].insn <= value && base[i + 1].insn > value)
62                         return &base[i];
63
64                 i++;
65         }
66
67         return NULL;
68 }
69
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
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 }