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