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