1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20#undef DEBUG
21
22#include <linux/moduleloader.h>
23#include <linux/elf.h>
24#include <linux/vmalloc.h>
25#include <linux/slab.h>
26#include <linux/fs.h>
27#include <linux/string.h>
28#include <linux/kernel.h>
29
30struct mips_hi16 {
31 struct mips_hi16 *next;
32 Elf32_Addr *addr;
33 Elf32_Addr value;
34};
35
36static struct mips_hi16 *mips_hi16_list;
37
38void *module_alloc(unsigned long size)
39{
40 if (size == 0)
41 return NULL;
42 return vmalloc(size);
43}
44
45
46
47void module_free(struct module *mod, void *module_region)
48{
49 vfree(module_region);
50
51
52}
53
54int module_frob_arch_sections(Elf_Ehdr *hdr,
55 Elf_Shdr *sechdrs,
56 char *secstrings,
57 struct module *mod)
58{
59 return 0;
60}
61
62static int apply_r_mips_none(struct module *me, uint32_t *location,
63 Elf32_Addr v)
64{
65 return 0;
66}
67
68static int apply_r_mips_32(struct module *me, uint32_t *location,
69 Elf32_Addr v)
70{
71 *location += v;
72
73 return 0;
74}
75
76static int apply_r_mips_26(struct module *me, uint32_t *location,
77 Elf32_Addr v)
78{
79 if (v % 4) {
80 printk(KERN_ERR "module %s: dangerous relocation\n", me->name);
81 return -ENOEXEC;
82 }
83
84 if ((v & 0xf0000000) != (((unsigned long)location + 4) & 0xf0000000)) {
85 printk(KERN_ERR
86 "module %s: relocation overflow\n",
87 me->name);
88 return -ENOEXEC;
89 }
90
91 *location = (*location & ~0x03ffffff) |
92 ((*location + (v >> 2)) & 0x03ffffff);
93
94 return 0;
95}
96
97static int apply_r_mips_hi16(struct module *me, uint32_t *location,
98 Elf32_Addr v)
99{
100 struct mips_hi16 *n;
101
102
103
104
105
106
107 n = kmalloc(sizeof *n, GFP_KERNEL);
108 if (!n)
109 return -ENOMEM;
110
111 n->addr = location;
112 n->value = v;
113 n->next = mips_hi16_list;
114 mips_hi16_list = n;
115
116 return 0;
117}
118
119static int apply_r_mips_lo16(struct module *me, uint32_t *location,
120 Elf32_Addr v)
121{
122 unsigned long insnlo = *location;
123 Elf32_Addr val, vallo;
124
125
126 vallo = ((insnlo & 0xffff) ^ 0x8000) - 0x8000;
127
128 if (mips_hi16_list != NULL) {
129 struct mips_hi16 *l;
130
131 l = mips_hi16_list;
132 while (l != NULL) {
133 struct mips_hi16 *next;
134 unsigned long insn;
135
136
137
138
139 if (v != l->value)
140 goto out_danger;
141
142
143
144
145
146
147
148 insn = *l->addr;
149 val = ((insn & 0xffff) << 16) + vallo;
150 val += v;
151
152
153
154
155
156 val = ((val >> 16) + ((val & 0x8000) != 0)) & 0xffff;
157
158 insn = (insn & ~0xffff) | val;
159 *l->addr = insn;
160
161 next = l->next;
162 kfree(l);
163 l = next;
164 }
165
166 mips_hi16_list = NULL;
167 }
168
169
170
171
172 val = v + vallo;
173 insnlo = (insnlo & ~0xffff) | (val & 0xffff);
174 *location = insnlo;
175
176 return 0;
177
178out_danger:
179 printk(KERN_ERR "module %s: dangerous " "relocation\n", me->name);
180
181 return -ENOEXEC;
182}
183
184static int (*reloc_handlers[]) (struct module *me, uint32_t *location,
185 Elf32_Addr v) = {
186 [R_MIPS_NONE] = apply_r_mips_none,
187 [R_MIPS_32] = apply_r_mips_32,
188 [R_MIPS_26] = apply_r_mips_26,
189 [R_MIPS_HI16] = apply_r_mips_hi16,
190 [R_MIPS_LO16] = apply_r_mips_lo16
191};
192
193int apply_relocate(Elf32_Shdr *sechdrs,
194 const char *strtab,
195 unsigned int symindex,
196 unsigned int relsec,
197 struct module *me)
198{
199 Elf32_Rel *rel = (void *) sechdrs[relsec].sh_addr;
200 Elf32_Sym *sym;
201 uint32_t *location;
202 unsigned int i;
203 Elf32_Addr v;
204 int res;
205
206 pr_debug("Applying relocate section %u to %u\n", relsec,
207 sechdrs[relsec].sh_info);
208
209 for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
210 Elf32_Word r_info = rel[i].r_info;
211
212
213 location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
214 + rel[i].r_offset;
215
216 sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
217 + ELF32_R_SYM(r_info);
218 if (!sym->st_value) {
219 printk(KERN_WARNING "%s: Unknown symbol %s\n",
220 me->name, strtab + sym->st_name);
221 return -ENOENT;
222 }
223
224 v = sym->st_value;
225
226 res = reloc_handlers[ELF32_R_TYPE(r_info)](me, location, v);
227 if (res)
228 return res;
229 }
230
231 return 0;
232}
233
234int apply_relocate_add(Elf32_Shdr *sechdrs,
235 const char *strtab,
236 unsigned int symindex,
237 unsigned int relsec,
238 struct module *me)
239{
240
241
242
243
244 if (!sechdrs[relsec].sh_size)
245 return 0;
246
247 printk(KERN_ERR "module %s: ADD RELOCATION unsupported\n",
248 me->name);
249 return -ENOEXEC;
250}
251