xref: /openbmc/linux/arch/loongarch/kernel/module.c (revision 5f7e2f3e)
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Author: Hanlu Li <lihanlu@loongson.cn>
4  *         Huacai Chen <chenhuacai@loongson.cn>
5  *
6  * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
7  */
8 
9 #define pr_fmt(fmt) "kmod: " fmt
10 
11 #include <linux/moduleloader.h>
12 #include <linux/elf.h>
13 #include <linux/mm.h>
14 #include <linux/numa.h>
15 #include <linux/vmalloc.h>
16 #include <linux/slab.h>
17 #include <linux/fs.h>
18 #include <linux/string.h>
19 #include <linux/kernel.h>
20 
21 static inline bool signed_imm_check(long val, unsigned int bit)
22 {
23 	return -(1L << (bit - 1)) <= val && val < (1L << (bit - 1));
24 }
25 
26 static inline bool unsigned_imm_check(unsigned long val, unsigned int bit)
27 {
28 	return val < (1UL << bit);
29 }
30 
31 static int rela_stack_push(s64 stack_value, s64 *rela_stack, size_t *rela_stack_top)
32 {
33 	if (*rela_stack_top >= RELA_STACK_DEPTH)
34 		return -ENOEXEC;
35 
36 	rela_stack[(*rela_stack_top)++] = stack_value;
37 	pr_debug("%s stack_value = 0x%llx\n", __func__, stack_value);
38 
39 	return 0;
40 }
41 
42 static int rela_stack_pop(s64 *stack_value, s64 *rela_stack, size_t *rela_stack_top)
43 {
44 	if (*rela_stack_top == 0)
45 		return -ENOEXEC;
46 
47 	*stack_value = rela_stack[--(*rela_stack_top)];
48 	pr_debug("%s stack_value = 0x%llx\n", __func__, *stack_value);
49 
50 	return 0;
51 }
52 
53 static int apply_r_larch_none(struct module *mod, u32 *location, Elf_Addr v,
54 			s64 *rela_stack, size_t *rela_stack_top, unsigned int type)
55 {
56 	return 0;
57 }
58 
59 static int apply_r_larch_error(struct module *me, u32 *location, Elf_Addr v,
60 			s64 *rela_stack, size_t *rela_stack_top, unsigned int type)
61 {
62 	pr_err("%s: Unsupport relocation type %u, please add its support.\n", me->name, type);
63 	return -EINVAL;
64 }
65 
66 static int apply_r_larch_32(struct module *mod, u32 *location, Elf_Addr v,
67 			s64 *rela_stack, size_t *rela_stack_top, unsigned int type)
68 {
69 	*location = v;
70 	return 0;
71 }
72 
73 static int apply_r_larch_64(struct module *mod, u32 *location, Elf_Addr v,
74 			s64 *rela_stack, size_t *rela_stack_top, unsigned int type)
75 {
76 	*(Elf_Addr *)location = v;
77 	return 0;
78 }
79 
80 static int apply_r_larch_sop_push_pcrel(struct module *mod, u32 *location, Elf_Addr v,
81 			s64 *rela_stack, size_t *rela_stack_top, unsigned int type)
82 {
83 	return rela_stack_push(v - (u64)location, rela_stack, rela_stack_top);
84 }
85 
86 static int apply_r_larch_sop_push_absolute(struct module *mod, u32 *location, Elf_Addr v,
87 			s64 *rela_stack, size_t *rela_stack_top, unsigned int type)
88 {
89 	return rela_stack_push(v, rela_stack, rela_stack_top);
90 }
91 
92 static int apply_r_larch_sop_push_dup(struct module *mod, u32 *location, Elf_Addr v,
93 			s64 *rela_stack, size_t *rela_stack_top, unsigned int type)
94 {
95 	int err = 0;
96 	s64 opr1;
97 
98 	err = rela_stack_pop(&opr1, rela_stack, rela_stack_top);
99 	if (err)
100 		return err;
101 	err = rela_stack_push(opr1, rela_stack, rela_stack_top);
102 	if (err)
103 		return err;
104 	err = rela_stack_push(opr1, rela_stack, rela_stack_top);
105 	if (err)
106 		return err;
107 
108 	return 0;
109 }
110 
111 static int apply_r_larch_sop_push_plt_pcrel(struct module *mod, u32 *location, Elf_Addr v,
112 			s64 *rela_stack, size_t *rela_stack_top, unsigned int type)
113 {
114 	ptrdiff_t offset = (void *)v - (void *)location;
115 
116 	if (offset >= SZ_128M)
117 		v = module_emit_plt_entry(mod, v);
118 
119 	if (offset < -SZ_128M)
120 		v = module_emit_plt_entry(mod, v);
121 
122 	return apply_r_larch_sop_push_pcrel(mod, location, v, rela_stack, rela_stack_top, type);
123 }
124 
125 static int apply_r_larch_sop(struct module *mod, u32 *location, Elf_Addr v,
126 			s64 *rela_stack, size_t *rela_stack_top, unsigned int type)
127 {
128 	int err = 0;
129 	s64 opr1, opr2, opr3;
130 
131 	if (type == R_LARCH_SOP_IF_ELSE) {
132 		err = rela_stack_pop(&opr3, rela_stack, rela_stack_top);
133 		if (err)
134 			return err;
135 	}
136 
137 	err = rela_stack_pop(&opr2, rela_stack, rela_stack_top);
138 	if (err)
139 		return err;
140 	err = rela_stack_pop(&opr1, rela_stack, rela_stack_top);
141 	if (err)
142 		return err;
143 
144 	switch (type) {
145 	case R_LARCH_SOP_AND:
146 		err = rela_stack_push(opr1 & opr2, rela_stack, rela_stack_top);
147 		break;
148 	case R_LARCH_SOP_ADD:
149 		err = rela_stack_push(opr1 + opr2, rela_stack, rela_stack_top);
150 		break;
151 	case R_LARCH_SOP_SUB:
152 		err = rela_stack_push(opr1 - opr2, rela_stack, rela_stack_top);
153 		break;
154 	case R_LARCH_SOP_SL:
155 		err = rela_stack_push(opr1 << opr2, rela_stack, rela_stack_top);
156 		break;
157 	case R_LARCH_SOP_SR:
158 		err = rela_stack_push(opr1 >> opr2, rela_stack, rela_stack_top);
159 		break;
160 	case R_LARCH_SOP_IF_ELSE:
161 		err = rela_stack_push(opr1 ? opr2 : opr3, rela_stack, rela_stack_top);
162 		break;
163 	default:
164 		pr_err("%s: Unsupport relocation type %u\n", mod->name, type);
165 		return -EINVAL;
166 	}
167 
168 	return err;
169 }
170 
171 static int apply_r_larch_sop_imm_field(struct module *mod, u32 *location, Elf_Addr v,
172 			s64 *rela_stack, size_t *rela_stack_top, unsigned int type)
173 {
174 	int err = 0;
175 	s64 opr1;
176 	union loongarch_instruction *insn = (union loongarch_instruction *)location;
177 
178 	err = rela_stack_pop(&opr1, rela_stack, rela_stack_top);
179 	if (err)
180 		return err;
181 
182 	switch (type) {
183 	case R_LARCH_SOP_POP_32_U_10_12:
184 		if (!unsigned_imm_check(opr1, 12))
185 			goto overflow;
186 
187 		/* (*(uint32_t *) PC) [21 ... 10] = opr [11 ... 0] */
188 		insn->reg2i12_format.immediate = opr1 & 0xfff;
189 		return 0;
190 	case R_LARCH_SOP_POP_32_S_10_12:
191 		if (!signed_imm_check(opr1, 12))
192 			goto overflow;
193 
194 		insn->reg2i12_format.immediate = opr1 & 0xfff;
195 		return 0;
196 	case R_LARCH_SOP_POP_32_S_10_16:
197 		if (!signed_imm_check(opr1, 16))
198 			goto overflow;
199 
200 		insn->reg2i16_format.immediate = opr1 & 0xffff;
201 		return 0;
202 	case R_LARCH_SOP_POP_32_S_10_16_S2:
203 		if (opr1 % 4)
204 			goto unaligned;
205 
206 		if (!signed_imm_check(opr1, 18))
207 			goto overflow;
208 
209 		insn->reg2i16_format.immediate = (opr1 >> 2) & 0xffff;
210 		return 0;
211 	case R_LARCH_SOP_POP_32_S_5_20:
212 		if (!signed_imm_check(opr1, 20))
213 			goto overflow;
214 
215 		insn->reg1i20_format.immediate = (opr1) & 0xfffff;
216 		return 0;
217 	case R_LARCH_SOP_POP_32_S_0_5_10_16_S2:
218 		if (opr1 % 4)
219 			goto unaligned;
220 
221 		if (!signed_imm_check(opr1, 23))
222 			goto overflow;
223 
224 		opr1 >>= 2;
225 		insn->reg1i21_format.immediate_l = opr1 & 0xffff;
226 		insn->reg1i21_format.immediate_h = (opr1 >> 16) & 0x1f;
227 		return 0;
228 	case R_LARCH_SOP_POP_32_S_0_10_10_16_S2:
229 		if (opr1 % 4)
230 			goto unaligned;
231 
232 		if (!signed_imm_check(opr1, 28))
233 			goto overflow;
234 
235 		opr1 >>= 2;
236 		insn->reg0i26_format.immediate_l = opr1 & 0xffff;
237 		insn->reg0i26_format.immediate_h = (opr1 >> 16) & 0x3ff;
238 		return 0;
239 	case R_LARCH_SOP_POP_32_U:
240 		if (!unsigned_imm_check(opr1, 32))
241 			goto overflow;
242 
243 		/* (*(uint32_t *) PC) = opr */
244 		*location = (u32)opr1;
245 		return 0;
246 	default:
247 		pr_err("%s: Unsupport relocation type %u\n", mod->name, type);
248 		return -EINVAL;
249 	}
250 
251 overflow:
252 	pr_err("module %s: opr1 = 0x%llx overflow! dangerous %s (%u) relocation\n",
253 		mod->name, opr1, __func__, type);
254 	return -ENOEXEC;
255 
256 unaligned:
257 	pr_err("module %s: opr1 = 0x%llx unaligned! dangerous %s (%u) relocation\n",
258 		mod->name, opr1, __func__, type);
259 	return -ENOEXEC;
260 }
261 
262 static int apply_r_larch_add_sub(struct module *mod, u32 *location, Elf_Addr v,
263 			s64 *rela_stack, size_t *rela_stack_top, unsigned int type)
264 {
265 	switch (type) {
266 	case R_LARCH_ADD32:
267 		*(s32 *)location += v;
268 		return 0;
269 	case R_LARCH_ADD64:
270 		*(s64 *)location += v;
271 		return 0;
272 	case R_LARCH_SUB32:
273 		*(s32 *)location -= v;
274 		return 0;
275 	case R_LARCH_SUB64:
276 		*(s64 *)location -= v;
277 		return 0;
278 	default:
279 		pr_err("%s: Unsupport relocation type %u\n", mod->name, type);
280 		return -EINVAL;
281 	}
282 }
283 
284 /*
285  * reloc_handlers_rela() - Apply a particular relocation to a module
286  * @mod: the module to apply the reloc to
287  * @location: the address at which the reloc is to be applied
288  * @v: the value of the reloc, with addend for RELA-style
289  * @rela_stack: the stack used for store relocation info, LOCAL to THIS module
290  * @rela_stac_top: where the stack operation(pop/push) applies to
291  *
292  * Return: 0 upon success, else -ERRNO
293  */
294 typedef int (*reloc_rela_handler)(struct module *mod, u32 *location, Elf_Addr v,
295 			s64 *rela_stack, size_t *rela_stack_top, unsigned int type);
296 
297 /* The handlers for known reloc types */
298 static reloc_rela_handler reloc_rela_handlers[] = {
299 	[R_LARCH_NONE ... R_LARCH_SUB64]		     = apply_r_larch_error,
300 
301 	[R_LARCH_NONE]					     = apply_r_larch_none,
302 	[R_LARCH_32]					     = apply_r_larch_32,
303 	[R_LARCH_64]					     = apply_r_larch_64,
304 	[R_LARCH_MARK_LA]				     = apply_r_larch_none,
305 	[R_LARCH_MARK_PCREL]				     = apply_r_larch_none,
306 	[R_LARCH_SOP_PUSH_PCREL]			     = apply_r_larch_sop_push_pcrel,
307 	[R_LARCH_SOP_PUSH_ABSOLUTE]			     = apply_r_larch_sop_push_absolute,
308 	[R_LARCH_SOP_PUSH_DUP]				     = apply_r_larch_sop_push_dup,
309 	[R_LARCH_SOP_PUSH_PLT_PCREL]			     = apply_r_larch_sop_push_plt_pcrel,
310 	[R_LARCH_SOP_SUB ... R_LARCH_SOP_IF_ELSE] 	     = apply_r_larch_sop,
311 	[R_LARCH_SOP_POP_32_S_10_5 ... R_LARCH_SOP_POP_32_U] = apply_r_larch_sop_imm_field,
312 	[R_LARCH_ADD32 ... R_LARCH_SUB64]		     = apply_r_larch_add_sub,
313 };
314 
315 int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab,
316 		       unsigned int symindex, unsigned int relsec,
317 		       struct module *mod)
318 {
319 	int i, err;
320 	unsigned int type;
321 	s64 rela_stack[RELA_STACK_DEPTH];
322 	size_t rela_stack_top = 0;
323 	reloc_rela_handler handler;
324 	void *location;
325 	Elf_Addr v;
326 	Elf_Sym *sym;
327 	Elf_Rela *rel = (void *) sechdrs[relsec].sh_addr;
328 
329 	pr_debug("%s: Applying relocate section %u to %u\n", __func__, relsec,
330 	       sechdrs[relsec].sh_info);
331 
332 	rela_stack_top = 0;
333 	for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
334 		/* This is where to make the change */
335 		location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr + rel[i].r_offset;
336 		/* This is the symbol it is referring to */
337 		sym = (Elf_Sym *)sechdrs[symindex].sh_addr + ELF_R_SYM(rel[i].r_info);
338 		if (IS_ERR_VALUE(sym->st_value)) {
339 			/* Ignore unresolved weak symbol */
340 			if (ELF_ST_BIND(sym->st_info) == STB_WEAK)
341 				continue;
342 			pr_warn("%s: Unknown symbol %s\n", mod->name, strtab + sym->st_name);
343 			return -ENOENT;
344 		}
345 
346 		type = ELF_R_TYPE(rel[i].r_info);
347 
348 		if (type < ARRAY_SIZE(reloc_rela_handlers))
349 			handler = reloc_rela_handlers[type];
350 		else
351 			handler = NULL;
352 
353 		if (!handler) {
354 			pr_err("%s: Unknown relocation type %u\n", mod->name, type);
355 			return -EINVAL;
356 		}
357 
358 		pr_debug("type %d st_value %llx r_addend %llx loc %llx\n",
359 		       (int)ELF_R_TYPE(rel[i].r_info),
360 		       sym->st_value, rel[i].r_addend, (u64)location);
361 
362 		v = sym->st_value + rel[i].r_addend;
363 		err = handler(mod, location, v, rela_stack, &rela_stack_top, type);
364 		if (err)
365 			return err;
366 	}
367 
368 	return 0;
369 }
370 
371 void *module_alloc(unsigned long size)
372 {
373 	return __vmalloc_node_range(size, 1, MODULES_VADDR, MODULES_END,
374 			GFP_KERNEL, PAGE_KERNEL, 0, NUMA_NO_NODE, __builtin_return_address(0));
375 }
376