xref: /linux/arch/riscv/kernel/module.c (revision a13f2ef168cb2a033a284eb841bcc481ffbc90cf)
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_sub32_rela(struct module *me, u32 *location,
267  				    Elf_Addr v)
268  {
269  	*(u32 *)location -= (u32)v;
270  	return 0;
271  }
272  
273  static int (*reloc_handlers_rela[]) (struct module *me, u32 *location,
274  				Elf_Addr v) = {
275  	[R_RISCV_32]			= apply_r_riscv_32_rela,
276  	[R_RISCV_64]			= apply_r_riscv_64_rela,
277  	[R_RISCV_BRANCH]		= apply_r_riscv_branch_rela,
278  	[R_RISCV_JAL]			= apply_r_riscv_jal_rela,
279  	[R_RISCV_RVC_BRANCH]		= apply_r_riscv_rcv_branch_rela,
280  	[R_RISCV_RVC_JUMP]		= apply_r_riscv_rvc_jump_rela,
281  	[R_RISCV_PCREL_HI20]		= apply_r_riscv_pcrel_hi20_rela,
282  	[R_RISCV_PCREL_LO12_I]		= apply_r_riscv_pcrel_lo12_i_rela,
283  	[R_RISCV_PCREL_LO12_S]		= apply_r_riscv_pcrel_lo12_s_rela,
284  	[R_RISCV_HI20]			= apply_r_riscv_hi20_rela,
285  	[R_RISCV_LO12_I]		= apply_r_riscv_lo12_i_rela,
286  	[R_RISCV_LO12_S]		= apply_r_riscv_lo12_s_rela,
287  	[R_RISCV_GOT_HI20]		= apply_r_riscv_got_hi20_rela,
288  	[R_RISCV_CALL_PLT]		= apply_r_riscv_call_plt_rela,
289  	[R_RISCV_CALL]			= apply_r_riscv_call_rela,
290  	[R_RISCV_RELAX]			= apply_r_riscv_relax_rela,
291  	[R_RISCV_ALIGN]			= apply_r_riscv_align_rela,
292  	[R_RISCV_ADD32]			= apply_r_riscv_add32_rela,
293  	[R_RISCV_SUB32]			= apply_r_riscv_sub32_rela,
294  };
295  
296  int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab,
297  		       unsigned int symindex, unsigned int relsec,
298  		       struct module *me)
299  {
300  	Elf_Rela *rel = (void *) sechdrs[relsec].sh_addr;
301  	int (*handler)(struct module *me, u32 *location, Elf_Addr v);
302  	Elf_Sym *sym;
303  	u32 *location;
304  	unsigned int i, type;
305  	Elf_Addr v;
306  	int res;
307  
308  	pr_debug("Applying relocate section %u to %u\n", relsec,
309  	       sechdrs[relsec].sh_info);
310  
311  	for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
312  		/* This is where to make the change */
313  		location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
314  			+ rel[i].r_offset;
315  		/* This is the symbol it is referring to */
316  		sym = (Elf_Sym *)sechdrs[symindex].sh_addr
317  			+ ELF_RISCV_R_SYM(rel[i].r_info);
318  		if (IS_ERR_VALUE(sym->st_value)) {
319  			/* Ignore unresolved weak symbol */
320  			if (ELF_ST_BIND(sym->st_info) == STB_WEAK)
321  				continue;
322  			pr_warn("%s: Unknown symbol %s\n",
323  				me->name, strtab + sym->st_name);
324  			return -ENOENT;
325  		}
326  
327  		type = ELF_RISCV_R_TYPE(rel[i].r_info);
328  
329  		if (type < ARRAY_SIZE(reloc_handlers_rela))
330  			handler = reloc_handlers_rela[type];
331  		else
332  			handler = NULL;
333  
334  		if (!handler) {
335  			pr_err("%s: Unknown relocation type %u\n",
336  			       me->name, type);
337  			return -EINVAL;
338  		}
339  
340  		v = sym->st_value + rel[i].r_addend;
341  
342  		if (type == R_RISCV_PCREL_LO12_I || type == R_RISCV_PCREL_LO12_S) {
343  			unsigned int j;
344  
345  			for (j = 0; j < sechdrs[relsec].sh_size / sizeof(*rel); j++) {
346  				unsigned long hi20_loc =
347  					sechdrs[sechdrs[relsec].sh_info].sh_addr
348  					+ rel[j].r_offset;
349  				u32 hi20_type = ELF_RISCV_R_TYPE(rel[j].r_info);
350  
351  				/* Find the corresponding HI20 relocation entry */
352  				if (hi20_loc == sym->st_value
353  				    && (hi20_type == R_RISCV_PCREL_HI20
354  					|| hi20_type == R_RISCV_GOT_HI20)) {
355  					s32 hi20, lo12;
356  					Elf_Sym *hi20_sym =
357  						(Elf_Sym *)sechdrs[symindex].sh_addr
358  						+ ELF_RISCV_R_SYM(rel[j].r_info);
359  					unsigned long hi20_sym_val =
360  						hi20_sym->st_value
361  						+ rel[j].r_addend;
362  
363  					/* Calculate lo12 */
364  					size_t offset = hi20_sym_val - hi20_loc;
365  					if (IS_ENABLED(CONFIG_MODULE_SECTIONS)
366  					    && hi20_type == R_RISCV_GOT_HI20) {
367  						offset = module_emit_got_entry(
368  							 me, hi20_sym_val);
369  						offset = offset - hi20_loc;
370  					}
371  					hi20 = (offset + 0x800) & 0xfffff000;
372  					lo12 = offset - hi20;
373  					v = lo12;
374  
375  					break;
376  				}
377  			}
378  			if (j == sechdrs[relsec].sh_size / sizeof(*rel)) {
379  				pr_err(
380  				  "%s: Can not find HI20 relocation information\n",
381  				  me->name);
382  				return -EINVAL;
383  			}
384  		}
385  
386  		res = handler(me, location, v);
387  		if (res)
388  			return res;
389  	}
390  
391  	return 0;
392  }
393  
394  #if defined(CONFIG_MMU) && defined(CONFIG_64BIT)
395  #define VMALLOC_MODULE_START \
396  	 max(PFN_ALIGN((unsigned long)&_end - SZ_2G), VMALLOC_START)
397  void *module_alloc(unsigned long size)
398  {
399  	return __vmalloc_node_range(size, 1, VMALLOC_MODULE_START,
400  				    VMALLOC_END, GFP_KERNEL,
401  				    PAGE_KERNEL_EXEC, 0, NUMA_NO_NODE,
402  				    __builtin_return_address(0));
403  }
404  #endif
405