xref: /netbsd-src/sys/arch/riscv/riscv/kobj_machdep.c (revision 350efc6a7049e35930c843c566b621a013c1a294)
1 /*	$NetBSD: kobj_machdep.c,v 1.6 2024/01/18 03:36:24 msaitoh Exp $	*/
2 
3 /*-
4  * Copyright (c) 2014,2023 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Matt Thomas of 3am Software Foundry, and by Nick Hudson.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include <sys/cdefs.h>
33 
34 __RCSID("$NetBSD: kobj_machdep.c,v 1.6 2024/01/18 03:36:24 msaitoh Exp $");
35 
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/kobj_impl.h>
39 #include <sys/kobj.h>
40 #include <sys/exec.h>
41 #include <sys/exec_elf.h>
42 
43 #include <riscv/locore.h>
44 
45 struct hi20 {
46 	void *where;
47 	long addend;
48 	bool local;
49 } last_hi20;
50 
51 static int
kobj_findhi20(kobj_t ko,uintptr_t relocbase,bool local,const Elf_Rela * lo12,Elf_Addr * hi20addr)52 kobj_findhi20(kobj_t ko, uintptr_t relocbase, bool local, const Elf_Rela *lo12,
53     Elf_Addr *hi20addr)
54 {
55 	const Elf_Rela *relalim;
56 	const Elf_Rela *rela;
57 	/*
58 	 * Find the relocation section.
59 	 */
60 	for (size_t i = 0; i < ko->ko_nrela; i++) {
61 		rela = ko->ko_relatab[i].rela;
62 		if (rela == NULL) {
63 			continue;
64 		}
65 		relalim = rela + ko->ko_relatab[i].nrela;
66 
67 		/* Check that the relocation is in this section */
68 		if (lo12 < rela || relalim < lo12)
69 			continue;
70 
71 		/*
72 		 * Now find the HI20 relocation from the LO12 relocation
73 		 * address (hi20addr)
74 		 */
75 		for (; rela < relalim; rela++) {
76 			Elf_Addr * const where =
77 			    (Elf_Addr *)(relocbase + rela->r_offset);
78 
79 			if (where != hi20addr) {
80 				continue;
81 			}
82 			/* Found the referenced HI20 relocation */
83 			uintptr_t symidx = ELF_R_SYM(rela->r_info);
84 #if 0
85 			if (symidx >= ko->ko_symcnt) {
86 				continue;
87 			}
88 #endif
89 			/*
90 			 * If this symbol doesn't is global and we're doing
91 			 * the local symbols at this point then we can't
92 			 * resolve it yet, so tell our caller.
93 			 */
94 			const Elf_Sym *sym = kobj_symbol(ko, symidx);
95 			if (local && ELF_ST_BIND(sym->st_info) != STB_LOCAL) {
96 				last_hi20.local = false;
97 				return 1;
98 			}
99 
100 			last_hi20.local = true;
101 
102 			Elf_Addr addr;
103 			const int error = kobj_sym_lookup(ko, symidx, &addr);
104 			if (error)
105 				return -1;
106 
107 			long addend = rela->r_addend;	/* needs to be signed */
108 			addend -= (intptr_t)where;
109 
110 			last_hi20.where = where;
111 			last_hi20.addend = addend;
112 			addend += addr;
113 
114 			return 0;
115 		}
116 	}
117 	return -1;
118 }
119 
120 
121 int
kobj_reloc(kobj_t ko,uintptr_t relocbase,const void * data,bool isrela,bool local)122 kobj_reloc(kobj_t ko, uintptr_t relocbase, const void *data, bool isrela,
123     bool local)
124 {
125 	if (!isrela) {
126 		panic("kobj_reloc: REL relocations not supported");
127 	}
128 
129 	const Elf_Rela * const rela = (const Elf_Rela *)data;
130 	Elf_Addr * const where = (Elf_Addr *)(relocbase + rela->r_offset);
131 	long addend = rela->r_addend;	/* needs to be signed */
132 	uint32_t *wwhere = (uint32_t *)where;
133 	uint16_t * const hwhere = (uint16_t *)where;
134 	uint8_t * const bwhere = (uint8_t *)where;
135 	const u_int rtype = ELF_R_TYPE(rela->r_info);
136 	const u_int symidx = ELF_R_SYM(rela->r_info);
137 	const Elf_Sym *sym = kobj_symbol(ko, symidx);
138 
139 	/*
140 	 * Check that we need to process this relocation in this pass.
141 	 * All relocations to local symols can be done in the first pass
142 	 * apart from PCREL_LO12 that reference a HI20 to a global symbol.
143 	 */
144 	switch (rtype) {
145 	case R_RISCV_PCREL_LO12_I:
146 	case R_RISCV_PCREL_LO12_S:
147 		if (addend != 0) {
148 			printf("oops\n");
149 		}
150 	case R_RISCV_PCREL_HI20:
151 	case R_RISCV_HI20:
152 		break;
153 	default:
154 		/* Don't do other relocations again */
155 		if (!local && ELF_ST_BIND(sym->st_info) == STB_LOCAL) {
156 			return 0;
157 		}
158 	}
159 
160 	/* Relocation calculation */
161 	switch (rtype) {
162 	case R_RISCV_NONE:
163 	case R_RISCV_RELAX:
164 		return 0;
165 
166 	case R_RISCV_BRANCH:
167 	case R_RISCV_JAL:
168 		// XXXNH eh? what's with the symidx test?'
169 		if (symidx == 0)
170 			break;
171 		/* FALLTHROUGH */
172 
173 	case R_RISCV_CALL_PLT:
174 	case R_RISCV_CALL:
175 	case R_RISCV_PCREL_HI20:
176 	case R_RISCV_RVC_BRANCH:
177 	case R_RISCV_RVC_JUMP:
178 	case R_RISCV_32_PCREL:
179 		addend -= (intptr_t)where;		/* A -= P */
180 		/* FALLTHROUGH */
181 
182 #ifdef _LP64
183 	case R_RISCV_64:	/* doubleword64 S + A */
184 	case R_RISCV_ADD64:
185 	case R_RISCV_SUB64:
186 #endif
187 	case R_RISCV_HI20:
188 	case R_RISCV_PCREL_LO12_I:
189 	case R_RISCV_PCREL_LO12_S:
190 	case R_RISCV_LO12_I:
191 	case R_RISCV_LO12_S:
192 	case R_RISCV_ADD32:
193 	case R_RISCV_ADD16:
194 	case R_RISCV_ADD8:
195 	case R_RISCV_SUB32:
196 	case R_RISCV_SUB16:
197 	case R_RISCV_SUB8:
198 	case R_RISCV_SUB6:
199 	case R_RISCV_SET32:
200 	case R_RISCV_SET16:
201 	case R_RISCV_SET8:
202 	case R_RISCV_SET6: {
203 		Elf_Addr addr;
204 		const int error = kobj_sym_lookup(ko, symidx, &addr);
205 		if (error) {
206 			/*
207 			 * This is a fatal error in the 2nd pass, i.e.
208 			 * local == false
209 			 */
210 			if (!local)
211 				return -1;
212 			return 0;
213 		}
214 
215 		switch (rtype) {
216 		case R_RISCV_PCREL_HI20:
217 		case R_RISCV_HI20: {
218 
219 			// XXXNH why is this without middle?
220 			last_hi20.addend = addend + addr;
221 			last_hi20.where = where;
222 			last_hi20.local = ELF_ST_BIND(sym->st_info) == STB_LOCAL;
223 
224 			/*
225 			 * If this is the 2nd pass then and the symbol is
226 			 * local then it's already been fixed up.
227 			 */
228 			if (!local && last_hi20.local) {
229 //				last_hi20.global = false;
230 				return 0;
231 			}
232 			const uint32_t lobits = 12;
233 			const uint32_t middle = 1U << (lobits - 1);
234 
235 			addend += addr + middle;
236 			break;
237 		    }
238 		case R_RISCV_PCREL_LO12_I:
239 		case R_RISCV_PCREL_LO12_S: {
240 			if (last_hi20.where != (void *)addr) {
241 				int err = kobj_findhi20(ko, relocbase, local,
242 				    rela, (Elf_Addr *)addr);
243 				if (err < 0)
244 					return -1;
245 				else if (err > 0) {
246 					KASSERT(local);
247 					return 0;
248 				}
249 			}
250 			/*
251 			 * In the second pass if the HI20 symbol was local
252 			 * it was already processed.
253 			 */
254 			if (!local && last_hi20.local) {
255 				return 0;
256 			}
257 			addend = addend + (last_hi20.addend & __BITS(11,0));
258 			break;
259 		    }
260 		default:
261 			addend += addr;				/* A += S */
262 		}
263 		break;
264 	    }
265 
266 	default:
267 		printf("%s: unexpected relocation type %u\n\n", __func__, rtype);
268 		return -1;
269 	}
270 
271 	/* Relocation memory update */
272 	switch (rtype) {
273 	case R_RISCV_64:	/* word64 S + A */
274 		*where = addend;
275 		break;
276 
277 	case R_RISCV_32:	/* word32 S + A */
278 	case R_RISCV_SET32:	/* word32 S + A */
279 	case R_RISCV_32_PCREL:	/* word32 S + A - P */
280 		*wwhere = addend;
281 		break;
282 
283 	case R_RISCV_SET16:	/* word16 S + A */
284 		*hwhere = addend;
285 		break;
286 
287 	case R_RISCV_SET8:	/* word8 S + A */
288 		*bwhere = addend;
289 		break;
290 
291 	case R_RISCV_SET6: {	/* word6 S + A */
292 		const uint8_t mask = __BITS(5, 0);
293 
294 		*bwhere = (*bwhere & ~mask) | __SHIFTIN(addend, mask);
295 		break;
296 	    }
297 
298 	case R_RISCV_ADD64:	/* word64 V + S + A */
299 		*where += addend;
300 		break;
301 
302 	case R_RISCV_ADD32:	/* word32 V + S + A */
303 		*wwhere += addend;
304 		break;
305 
306 	case R_RISCV_ADD16:	/* word16 V + S + A */
307 		*hwhere += addend;
308 		break;
309 
310 	case R_RISCV_ADD8:	/* word8 V + S + A */
311 		*bwhere += addend;
312 		break;
313 
314 	case R_RISCV_SUB64:	/* word64 V - S - A */
315 		*where -= addend;
316 		break;
317 
318 	case R_RISCV_SUB32:	/* word32 V - S - A */
319 		*wwhere -= addend;
320 		break;
321 
322 	case R_RISCV_SUB16:	/* word16 V - S - A */
323 		*hwhere -= addend;
324 		break;
325 
326 	case R_RISCV_SUB8:	/* word8 V - S - A */
327 		*bwhere -= addend;
328 		break;
329 
330 	case R_RISCV_SUB6:	/* word6 V - S - A */
331 		// XXXNH
332 		*bwhere -= addend;
333 		break;
334 
335 	case R_RISCV_BRANCH: {
336 		/*
337 		 * B-type
338 		 *   31    | 30     25 | ... | 11     8 |    7     | ...
339 		 * imm[12] | imm[10:5] | ... | imm[4:1] | imm[11]  | ...
340 		 */
341 
342 		const uint32_t immA = __SHIFTOUT(addend, __BIT(12));
343 		const uint32_t immB = __SHIFTOUT(addend, __BITS(10,  5));
344 		const uint32_t immC = __SHIFTOUT(addend, __BITS( 4,  1));
345 		const uint32_t immD = __SHIFTOUT(addend, __BIT(11));
346 		addend =
347 		    __SHIFTIN(immA, __BIT(31)) |
348 		    __SHIFTIN(immB, __BITS(30, 25)) |
349 		    __SHIFTIN(immC, __BITS(11, 8)) |
350 		    __SHIFTIN(immD, __BIT(7));
351 		const uint32_t mask = __BITS(31, 25) | __BITS(11, 7);
352 
353 		*wwhere = (*wwhere & ~mask) | addend;
354 		break;
355 	    }
356 
357 	case R_RISCV_JAL: {
358 		/*
359 		 * J-type
360 		 *   31    | 30     21 |   20    | 19      12 | ...
361 		 * imm[20] | imm[10:1] | imm[11] | imm[19:12] | ...
362 		 */
363 
364 		const uint32_t immA = __SHIFTOUT(addend,  __BIT(20));
365 		const uint32_t immB = __SHIFTOUT(addend, __BITS(10,  1));
366 		const uint32_t immC = __SHIFTOUT(addend,  __BIT(11));
367 		const uint32_t immD = __SHIFTOUT(addend, __BITS(19, 12));
368 		addend =
369 		    __SHIFTIN(immA,  __BIT(31)) |
370 		    __SHIFTIN(immB, __BITS(30, 21)) |
371 		    __SHIFTIN(immC,  __BIT(20)) |
372 		    __SHIFTIN(immD, __BITS(19,12));
373 		/* FALLTHROUGH */
374 	    }
375 
376 	case R_RISCV_HI20:		/* LUI/AUIPC (S + A - P) */
377 	case R_RISCV_PCREL_HI20: {	/* LUI/AUIPC (S + A - P) */
378 		/*
379 		 * U-Type
380 		 * 31      12 | ...
381 		 * imm[31:12] | ...
382 		 */
383 		const uint32_t mask = __BITS(31, 12);
384 		*wwhere = (addend & mask) | (*wwhere & ~mask);
385 		break;
386 	    }
387 	case R_RISCV_PCREL_LO12_I:
388 	case R_RISCV_LO12_I: {		/* low12 I-type instructions */
389 		/*
390 		 * I-Type
391 		 * 31     20 | ...
392 		 * imm[11:0] | ...
393 		 */
394 
395 		*wwhere += ((addend) << 20);
396 		break;
397 	    }
398 	case R_RISCV_PCREL_LO12_S:
399 	case R_RISCV_LO12_S: {	/* low12 S-type instructions */
400 		/*
401 		 * S-type
402 		 *
403 		 * 31     25 | ... | 11     7 | ...
404 		 * imm[11:5] | ... | imm[4:0] | ...
405 		 *
406 		 */
407 		const uint32_t immA = __SHIFTOUT(addend, __BITS(11,  5));
408 		const uint32_t immB = __SHIFTOUT(addend, __BITS( 4,  0));
409 		const uint32_t mask = __BITS(31, 25) | __BITS(11, 7);
410 		addend =
411 		    __SHIFTIN(immA, __BITS(31, 25)) |
412 		    __SHIFTIN(immB, __BITS(11,  7));
413 		*wwhere = (*wwhere & ~mask) | addend;
414 		break;
415 	    }
416 	case R_RISCV_CALL:
417 	case R_RISCV_CALL_PLT: {
418 		/*
419 		 * U-type
420 		 *
421 		 * 31      12 | ...
422 		 * imm[31:12] | ...
423 		 *
424 		 *
425 		 * I-type
426 		 *
427 		 * 31     25 | ...
428 		 * imm[11:0] | ...
429 		 */
430 		// XXXNH better name...
431 		const int32_t check = (int32_t)addend >> 20;
432 		if (check == 0 || check == -1) {
433 			// This falls into the range for the JAL instruction.
434 			/*
435 			* J-type
436 			*   31    | 30     21 |   20    | 19      12 | ...
437 			* imm[20] | imm[10:1] | imm[11] | imm[19:12] | ...
438 			*/
439 
440 			const uint32_t immA = __SHIFTOUT(addend,  __BIT(20));
441 			const uint32_t immB = __SHIFTOUT(addend, __BITS(10,  1));
442 			const uint32_t immC = __SHIFTOUT(addend,  __BIT(11));
443 			const uint32_t immD = __SHIFTOUT(addend, __BITS(19, 12));
444 			addend =
445 			    __SHIFTIN(immA,  __BIT(31)) |
446 			    __SHIFTIN(immB, __BITS(30, 21)) |
447 			    __SHIFTIN(immC,  __BIT(20)) |
448 			    __SHIFTIN(immD, __BITS(19,12));
449 
450 			// Convert the auipc/jalr to a jal/nop
451 			wwhere[0] = addend | (wwhere[1] & 0xf80) | 0x6f;
452 			wwhere[1] = 0x00000013;	// nop (addi x0, x0, 0)
453 			printf("%s: %s where (%p) [0] -> %x, [1] -> %x\n", __func__,
454 			    "R_RISCV_CALL", wwhere, wwhere[0], wwhere[1]);
455 			break;
456 		}
457 		wwhere[0] = ((addend + 0x800) & 0xfffff000)
458 		    | (wwhere[0] & 0xfff);
459 		wwhere[1] = (addend << 20) | (wwhere[1] & 0x000fffff);
460 		printf("%s: %s where (%p) [0] -> %x, [1] -> %x\n", __func__,
461 		    "R_RISCV_CALL", wwhere, wwhere[0], wwhere[1]);
462 
463 		break;
464 	    }
465 	case R_RISCV_RVC_BRANCH: {
466 		/*
467 		 * CB-type
468 		 *
469 		 * ... | 12         10 | ... | 6        5   3 2  | ...
470 		 * ... | offset[8|4:3] | ... | offset[7:6|2:1|5] | ...
471 		 */
472 
473 		const uint16_t immA = __SHIFTOUT(addend, __BIT(8));
474 		const uint16_t immB = __SHIFTOUT(addend, __BITS(4, 3));
475 		const uint16_t immC = __SHIFTOUT(addend, __BITS(7, 6));
476 		const uint16_t immD = __SHIFTOUT(addend, __BITS(2, 1));
477 		const uint16_t immE = __SHIFTOUT(addend, __BIT(5));
478 		const uint16_t mask = __BITS(12, 10) | __BITS(6, 2);
479 		addend =
480 		    __SHIFTIN(immA, __BIT(12)) |
481 		    __SHIFTIN(immB, __BITS(11, 10)) |
482 		    __SHIFTIN(immC, __BITS( 6,  5)) |
483 		    __SHIFTIN(immD, __BITS( 4,  3)) |
484 		    __SHIFTIN(immE, __BIT(2));
485 		*hwhere = (*hwhere & ~mask) | addend;
486 		break;
487 	    }
488 
489 	case R_RISCV_RVC_JUMP: {
490 		/*
491 		 * CJ-type
492 		 *
493 		 * ... | 12                          2 | ...
494 		 * ... | offset[11|4|9:8|10|6|7|3:1|5] | ...
495 		 */
496 
497 		const uint16_t immA = __SHIFTOUT(addend, __BIT(11));
498 		const uint16_t immB = __SHIFTOUT(addend, __BIT(4));
499 		const uint16_t immC = __SHIFTOUT(addend, __BITS(9, 8));
500 		const uint16_t immD = __SHIFTOUT(addend, __BIT(10));
501 		const uint16_t immE = __SHIFTOUT(addend, __BIT(6));
502 		const uint16_t immF = __SHIFTOUT(addend, __BIT(7));
503 		const uint16_t immG = __SHIFTOUT(addend, __BITS(3, 1));
504 		const uint16_t immH = __SHIFTOUT(addend, __BIT(5));
505 		const uint16_t mask = __BITS(12, 2);
506 		addend =
507 		    __SHIFTIN(immA, __BIT(12)) |
508 		    __SHIFTIN(immB, __BIT(11)) |
509 		    __SHIFTIN(immC, __BITS(10,  9)) |
510 		    __SHIFTIN(immD, __BIT(8)) |
511 		    __SHIFTIN(immE, __BIT(7)) |
512 		    __SHIFTIN(immF, __BIT(6)) |
513 		    __SHIFTIN(immG, __BITS(5, 3)) |
514 		    __SHIFTIN(immH, __BIT(2));
515 		*hwhere = (*hwhere & ~mask) | addend;
516 		break;
517 	    }
518 
519 	case R_RISCV_RVC_LUI: {
520 		/*
521 		 * CI-type
522 		 *
523 		 * ... | 12         | ... | 6           2 | ...
524 		 * ... | offset[17] | ... | offset[16:12] | ...
525 		 */
526 
527 		const uint16_t immA = __SHIFTOUT(addend, __BIT(17));
528 		const uint16_t immB = __SHIFTOUT(addend, __BITS(16,12));
529 		const uint16_t mask = __BIT(12) | __BITS(6,  2);
530 		addend =
531 		    __SHIFTIN(immA, __BIT(12)) |
532 		    __SHIFTIN(immB, __BITS(6, 2));
533 		*hwhere = (*hwhere & ~mask) | addend;
534 		break;
535 	    }
536 
537 	default:
538 		printf("Unexpected relocation type %d\n", rtype);
539 	}
540 
541 	return 0;
542 }
543 
544 int
kobj_machdep(kobj_t ko,void * base,size_t size,bool load)545 kobj_machdep(kobj_t ko, void *base, size_t size, bool load)
546 {
547 	if (load)
548 		__asm("fence rw,rw; fence.i");
549 
550 	return 0;
551 }
552