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
45struct hi20 {
46	void *where;
47	long addend;
48	bool local;
49} last_hi20;
50
51static int
52kobj_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
121int
122kobj_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
544int
545kobj_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