riscv: Support R_RISCV_ADD64 and R_RISCV_SUB64 relocs
[linux-2.6-microblaze.git] / arch / riscv / kernel / module.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  *
4  *  Copyright (C) 2017 Zihao Yu
5  */
6
7 #include <linux/elf.h>
8 #include <linux/err.h>
9 #include <linux/errno.h>
10 #include <linux/moduleloader.h>
11 #include <linux/vmalloc.h>
12 #include <linux/sizes.h>
13 #include <linux/pgtable.h>
14 #include <asm/sections.h>
15
16 static int apply_r_riscv_32_rela(struct module *me, u32 *location, Elf_Addr v)
17 {
18         if (v != (u32)v) {
19                 pr_err("%s: value %016llx out of range for 32-bit field\n",
20                        me->name, (long long)v);
21                 return -EINVAL;
22         }
23         *location = v;
24         return 0;
25 }
26
27 static int apply_r_riscv_64_rela(struct module *me, u32 *location, Elf_Addr v)
28 {
29         *(u64 *)location = v;
30         return 0;
31 }
32
33 static int apply_r_riscv_branch_rela(struct module *me, u32 *location,
34                                      Elf_Addr v)
35 {
36         ptrdiff_t offset = (void *)v - (void *)location;
37         u32 imm12 = (offset & 0x1000) << (31 - 12);
38         u32 imm11 = (offset & 0x800) >> (11 - 7);
39         u32 imm10_5 = (offset & 0x7e0) << (30 - 10);
40         u32 imm4_1 = (offset & 0x1e) << (11 - 4);
41
42         *location = (*location & 0x1fff07f) | imm12 | imm11 | imm10_5 | imm4_1;
43         return 0;
44 }
45
46 static int apply_r_riscv_jal_rela(struct module *me, u32 *location,
47                                   Elf_Addr v)
48 {
49         ptrdiff_t offset = (void *)v - (void *)location;
50         u32 imm20 = (offset & 0x100000) << (31 - 20);
51         u32 imm19_12 = (offset & 0xff000);
52         u32 imm11 = (offset & 0x800) << (20 - 11);
53         u32 imm10_1 = (offset & 0x7fe) << (30 - 10);
54
55         *location = (*location & 0xfff) | imm20 | imm19_12 | imm11 | imm10_1;
56         return 0;
57 }
58
59 static int apply_r_riscv_rcv_branch_rela(struct module *me, u32 *location,
60                                          Elf_Addr v)
61 {
62         ptrdiff_t offset = (void *)v - (void *)location;
63         u16 imm8 = (offset & 0x100) << (12 - 8);
64         u16 imm7_6 = (offset & 0xc0) >> (6 - 5);
65         u16 imm5 = (offset & 0x20) >> (5 - 2);
66         u16 imm4_3 = (offset & 0x18) << (12 - 5);
67         u16 imm2_1 = (offset & 0x6) << (12 - 10);
68
69         *(u16 *)location = (*(u16 *)location & 0xe383) |
70                     imm8 | imm7_6 | imm5 | imm4_3 | imm2_1;
71         return 0;
72 }
73
74 static int apply_r_riscv_rvc_jump_rela(struct module *me, u32 *location,
75                                        Elf_Addr v)
76 {
77         ptrdiff_t offset = (void *)v - (void *)location;
78         u16 imm11 = (offset & 0x800) << (12 - 11);
79         u16 imm10 = (offset & 0x400) >> (10 - 8);
80         u16 imm9_8 = (offset & 0x300) << (12 - 11);
81         u16 imm7 = (offset & 0x80) >> (7 - 6);
82         u16 imm6 = (offset & 0x40) << (12 - 11);
83         u16 imm5 = (offset & 0x20) >> (5 - 2);
84         u16 imm4 = (offset & 0x10) << (12 - 5);
85         u16 imm3_1 = (offset & 0xe) << (12 - 10);
86
87         *(u16 *)location = (*(u16 *)location & 0xe003) |
88                     imm11 | imm10 | imm9_8 | imm7 | imm6 | imm5 | imm4 | imm3_1;
89         return 0;
90 }
91
92 static int apply_r_riscv_pcrel_hi20_rela(struct module *me, u32 *location,
93                                          Elf_Addr v)
94 {
95         ptrdiff_t offset = (void *)v - (void *)location;
96         s32 hi20;
97
98         if (offset != (s32)offset) {
99                 pr_err(
100                   "%s: target %016llx can not be addressed by the 32-bit offset from PC = %p\n",
101                   me->name, (long long)v, location);
102                 return -EINVAL;
103         }
104
105         hi20 = (offset + 0x800) & 0xfffff000;
106         *location = (*location & 0xfff) | hi20;
107         return 0;
108 }
109
110 static int apply_r_riscv_pcrel_lo12_i_rela(struct module *me, u32 *location,
111                                            Elf_Addr v)
112 {
113         /*
114          * v is the lo12 value to fill. It is calculated before calling this
115          * handler.
116          */
117         *location = (*location & 0xfffff) | ((v & 0xfff) << 20);
118         return 0;
119 }
120
121 static int apply_r_riscv_pcrel_lo12_s_rela(struct module *me, u32 *location,
122                                            Elf_Addr v)
123 {
124         /*
125          * v is the lo12 value to fill. It is calculated before calling this
126          * handler.
127          */
128         u32 imm11_5 = (v & 0xfe0) << (31 - 11);
129         u32 imm4_0 = (v & 0x1f) << (11 - 4);
130
131         *location = (*location & 0x1fff07f) | imm11_5 | imm4_0;
132         return 0;
133 }
134
135 static int apply_r_riscv_hi20_rela(struct module *me, u32 *location,
136                                    Elf_Addr v)
137 {
138         s32 hi20;
139
140         if (IS_ENABLED(CONFIG_CMODEL_MEDLOW)) {
141                 pr_err(
142                   "%s: target %016llx can not be addressed by the 32-bit offset from PC = %p\n",
143                   me->name, (long long)v, location);
144                 return -EINVAL;
145         }
146
147         hi20 = ((s32)v + 0x800) & 0xfffff000;
148         *location = (*location & 0xfff) | hi20;
149         return 0;
150 }
151
152 static int apply_r_riscv_lo12_i_rela(struct module *me, u32 *location,
153                                      Elf_Addr v)
154 {
155         /* Skip medlow checking because of filtering by HI20 already */
156         s32 hi20 = ((s32)v + 0x800) & 0xfffff000;
157         s32 lo12 = ((s32)v - hi20);
158         *location = (*location & 0xfffff) | ((lo12 & 0xfff) << 20);
159         return 0;
160 }
161
162 static int apply_r_riscv_lo12_s_rela(struct module *me, u32 *location,
163                                      Elf_Addr v)
164 {
165         /* Skip medlow checking because of filtering by HI20 already */
166         s32 hi20 = ((s32)v + 0x800) & 0xfffff000;
167         s32 lo12 = ((s32)v - hi20);
168         u32 imm11_5 = (lo12 & 0xfe0) << (31 - 11);
169         u32 imm4_0 = (lo12 & 0x1f) << (11 - 4);
170         *location = (*location & 0x1fff07f) | imm11_5 | imm4_0;
171         return 0;
172 }
173
174 static int apply_r_riscv_got_hi20_rela(struct module *me, u32 *location,
175                                        Elf_Addr v)
176 {
177         ptrdiff_t offset = (void *)v - (void *)location;
178         s32 hi20;
179
180         /* Always emit the got entry */
181         if (IS_ENABLED(CONFIG_MODULE_SECTIONS)) {
182                 offset = module_emit_got_entry(me, v);
183                 offset = (void *)offset - (void *)location;
184         } else {
185                 pr_err(
186                   "%s: can not generate the GOT entry for symbol = %016llx from PC = %p\n",
187                   me->name, (long long)v, location);
188                 return -EINVAL;
189         }
190
191         hi20 = (offset + 0x800) & 0xfffff000;
192         *location = (*location & 0xfff) | hi20;
193         return 0;
194 }
195
196 static int apply_r_riscv_call_plt_rela(struct module *me, u32 *location,
197                                        Elf_Addr v)
198 {
199         ptrdiff_t offset = (void *)v - (void *)location;
200         s32 fill_v = offset;
201         u32 hi20, lo12;
202
203         if (offset != fill_v) {
204                 /* Only emit the plt entry if offset over 32-bit range */
205                 if (IS_ENABLED(CONFIG_MODULE_SECTIONS)) {
206                         offset = module_emit_plt_entry(me, v);
207                         offset = (void *)offset - (void *)location;
208                 } else {
209                         pr_err(
210                           "%s: target %016llx can not be addressed by the 32-bit offset from PC = %p\n",
211                           me->name, (long long)v, location);
212                         return -EINVAL;
213                 }
214         }
215
216         hi20 = (offset + 0x800) & 0xfffff000;
217         lo12 = (offset - hi20) & 0xfff;
218         *location = (*location & 0xfff) | hi20;
219         *(location + 1) = (*(location + 1) & 0xfffff) | (lo12 << 20);
220         return 0;
221 }
222
223 static int apply_r_riscv_call_rela(struct module *me, u32 *location,
224                                    Elf_Addr v)
225 {
226         ptrdiff_t offset = (void *)v - (void *)location;
227         s32 fill_v = offset;
228         u32 hi20, lo12;
229
230         if (offset != fill_v) {
231                 pr_err(
232                   "%s: target %016llx can not be addressed by the 32-bit offset from PC = %p\n",
233                   me->name, (long long)v, location);
234                 return -EINVAL;
235         }
236
237         hi20 = (offset + 0x800) & 0xfffff000;
238         lo12 = (offset - hi20) & 0xfff;
239         *location = (*location & 0xfff) | hi20;
240         *(location + 1) = (*(location + 1) & 0xfffff) | (lo12 << 20);
241         return 0;
242 }
243
244 static int apply_r_riscv_relax_rela(struct module *me, u32 *location,
245                                     Elf_Addr v)
246 {
247         return 0;
248 }
249
250 static int apply_r_riscv_align_rela(struct module *me, u32 *location,
251                                     Elf_Addr v)
252 {
253         pr_err(
254           "%s: The unexpected relocation type 'R_RISCV_ALIGN' from PC = %p\n",
255           me->name, location);
256         return -EINVAL;
257 }
258
259 static int apply_r_riscv_add32_rela(struct module *me, u32 *location,
260                                     Elf_Addr v)
261 {
262         *(u32 *)location += (u32)v;
263         return 0;
264 }
265
266 static int apply_r_riscv_add64_rela(struct module *me, u32 *location,
267                                     Elf_Addr v)
268 {
269         *(u64 *)location += (u64)v;
270         return 0;
271 }
272
273 static int apply_r_riscv_sub32_rela(struct module *me, u32 *location,
274                                     Elf_Addr v)
275 {
276         *(u32 *)location -= (u32)v;
277         return 0;
278 }
279
280 static int apply_r_riscv_sub64_rela(struct module *me, u32 *location,
281                                     Elf_Addr v)
282 {
283         *(u64 *)location -= (u64)v;
284         return 0;
285 }
286
287 static int (*reloc_handlers_rela[]) (struct module *me, u32 *location,
288                                 Elf_Addr v) = {
289         [R_RISCV_32]                    = apply_r_riscv_32_rela,
290         [R_RISCV_64]                    = apply_r_riscv_64_rela,
291         [R_RISCV_BRANCH]                = apply_r_riscv_branch_rela,
292         [R_RISCV_JAL]                   = apply_r_riscv_jal_rela,
293         [R_RISCV_RVC_BRANCH]            = apply_r_riscv_rcv_branch_rela,
294         [R_RISCV_RVC_JUMP]              = apply_r_riscv_rvc_jump_rela,
295         [R_RISCV_PCREL_HI20]            = apply_r_riscv_pcrel_hi20_rela,
296         [R_RISCV_PCREL_LO12_I]          = apply_r_riscv_pcrel_lo12_i_rela,
297         [R_RISCV_PCREL_LO12_S]          = apply_r_riscv_pcrel_lo12_s_rela,
298         [R_RISCV_HI20]                  = apply_r_riscv_hi20_rela,
299         [R_RISCV_LO12_I]                = apply_r_riscv_lo12_i_rela,
300         [R_RISCV_LO12_S]                = apply_r_riscv_lo12_s_rela,
301         [R_RISCV_GOT_HI20]              = apply_r_riscv_got_hi20_rela,
302         [R_RISCV_CALL_PLT]              = apply_r_riscv_call_plt_rela,
303         [R_RISCV_CALL]                  = apply_r_riscv_call_rela,
304         [R_RISCV_RELAX]                 = apply_r_riscv_relax_rela,
305         [R_RISCV_ALIGN]                 = apply_r_riscv_align_rela,
306         [R_RISCV_ADD32]                 = apply_r_riscv_add32_rela,
307         [R_RISCV_ADD64]                 = apply_r_riscv_add64_rela,
308         [R_RISCV_SUB32]                 = apply_r_riscv_sub32_rela,
309         [R_RISCV_SUB64]                 = apply_r_riscv_sub64_rela,
310 };
311
312 int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab,
313                        unsigned int symindex, unsigned int relsec,
314                        struct module *me)
315 {
316         Elf_Rela *rel = (void *) sechdrs[relsec].sh_addr;
317         int (*handler)(struct module *me, u32 *location, Elf_Addr v);
318         Elf_Sym *sym;
319         u32 *location;
320         unsigned int i, type;
321         Elf_Addr v;
322         int res;
323
324         pr_debug("Applying relocate section %u to %u\n", relsec,
325                sechdrs[relsec].sh_info);
326
327         for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
328                 /* This is where to make the change */
329                 location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
330                         + rel[i].r_offset;
331                 /* This is the symbol it is referring to */
332                 sym = (Elf_Sym *)sechdrs[symindex].sh_addr
333                         + ELF_RISCV_R_SYM(rel[i].r_info);
334                 if (IS_ERR_VALUE(sym->st_value)) {
335                         /* Ignore unresolved weak symbol */
336                         if (ELF_ST_BIND(sym->st_info) == STB_WEAK)
337                                 continue;
338                         pr_warn("%s: Unknown symbol %s\n",
339                                 me->name, strtab + sym->st_name);
340                         return -ENOENT;
341                 }
342
343                 type = ELF_RISCV_R_TYPE(rel[i].r_info);
344
345                 if (type < ARRAY_SIZE(reloc_handlers_rela))
346                         handler = reloc_handlers_rela[type];
347                 else
348                         handler = NULL;
349
350                 if (!handler) {
351                         pr_err("%s: Unknown relocation type %u\n",
352                                me->name, type);
353                         return -EINVAL;
354                 }
355
356                 v = sym->st_value + rel[i].r_addend;
357
358                 if (type == R_RISCV_PCREL_LO12_I || type == R_RISCV_PCREL_LO12_S) {
359                         unsigned int j;
360
361                         for (j = 0; j < sechdrs[relsec].sh_size / sizeof(*rel); j++) {
362                                 unsigned long hi20_loc =
363                                         sechdrs[sechdrs[relsec].sh_info].sh_addr
364                                         + rel[j].r_offset;
365                                 u32 hi20_type = ELF_RISCV_R_TYPE(rel[j].r_info);
366
367                                 /* Find the corresponding HI20 relocation entry */
368                                 if (hi20_loc == sym->st_value
369                                     && (hi20_type == R_RISCV_PCREL_HI20
370                                         || hi20_type == R_RISCV_GOT_HI20)) {
371                                         s32 hi20, lo12;
372                                         Elf_Sym *hi20_sym =
373                                                 (Elf_Sym *)sechdrs[symindex].sh_addr
374                                                 + ELF_RISCV_R_SYM(rel[j].r_info);
375                                         unsigned long hi20_sym_val =
376                                                 hi20_sym->st_value
377                                                 + rel[j].r_addend;
378
379                                         /* Calculate lo12 */
380                                         size_t offset = hi20_sym_val - hi20_loc;
381                                         if (IS_ENABLED(CONFIG_MODULE_SECTIONS)
382                                             && hi20_type == R_RISCV_GOT_HI20) {
383                                                 offset = module_emit_got_entry(
384                                                          me, hi20_sym_val);
385                                                 offset = offset - hi20_loc;
386                                         }
387                                         hi20 = (offset + 0x800) & 0xfffff000;
388                                         lo12 = offset - hi20;
389                                         v = lo12;
390
391                                         break;
392                                 }
393                         }
394                         if (j == sechdrs[relsec].sh_size / sizeof(*rel)) {
395                                 pr_err(
396                                   "%s: Can not find HI20 relocation information\n",
397                                   me->name);
398                                 return -EINVAL;
399                         }
400                 }
401
402                 res = handler(me, location, v);
403                 if (res)
404                         return res;
405         }
406
407         return 0;
408 }
409
410 #if defined(CONFIG_MMU) && defined(CONFIG_64BIT)
411 #define VMALLOC_MODULE_START \
412          max(PFN_ALIGN((unsigned long)&_end - SZ_2G), VMALLOC_START)
413 void *module_alloc(unsigned long size)
414 {
415         return __vmalloc_node_range(size, 1, VMALLOC_MODULE_START,
416                                     VMALLOC_END, GFP_KERNEL,
417                                     PAGE_KERNEL_EXEC, 0, NUMA_NO_NODE,
418                                     __builtin_return_address(0));
419 }
420 #endif