1/*
2 * Copyright 2005, Ingo Weinhold <bonefish@cs.tu-berlin.de>.
3 * All rights reserved. Distributed under the terms of the MIT License.
4 *
5 *
6 * Copyright 2002, Travis Geiselbrecht. All rights reserved.
7 * Distributed under the terms of the NewOS License.
8 */
9
10#ifdef _BOOT_MODE
11#include <boot/arch.h>
12#endif
13
14#include <KernelExport.h>
15
16#include <elf_priv.h>
17#include <arch/elf.h>
18
19
20#define CHATTY 0
21
22#ifdef _BOOT_MODE
23status_t
24boot_arch_elf_relocate_rel(struct preloaded_elf32_image *image, Elf32_Rel *rel,
25	int rel_len)
26#else
27int
28arch_elf_relocate_rel(struct elf_image_info *image,
29	struct elf_image_info *resolve_image, Elf32_Rel *rel, int rel_len)
30#endif
31{
32	// there are no rel entries in PPC elf
33	return B_NO_ERROR;
34}
35
36
37static inline void
38write_word32(addr_t P, Elf32_Word value)
39{
40	*(Elf32_Word*)P = value;
41}
42
43
44static inline void
45write_word30(addr_t P, Elf32_Word value)
46{
47	// bits 0:29
48	*(Elf32_Word*)P = (*(Elf32_Word*)P & 0x3) | (value << 2);
49}
50
51
52static inline bool
53write_low24_check(addr_t P, Elf32_Word value)
54{
55	// bits 6:29
56	if ((value & 0x3f000000) && (~value & 0x3f800000))
57		return false;
58	*(Elf32_Word*)P = (*(Elf32_Word*)P & 0xfc000003)
59		| ((value & 0x00ffffff) << 2);
60	return true;
61}
62
63
64static inline bool
65write_low14_check(addr_t P, Elf32_Word value)
66{
67	// bits 16:29
68	if ((value & 0x3fffc000) && (~value & 0x3fffe000))
69		return false;
70	*(Elf32_Word*)P = (*(Elf32_Word*)P & 0xffff0003)
71		| ((value & 0x00003fff) << 2);
72	return true;
73}
74
75
76static inline void
77write_half16(addr_t P, Elf32_Word value)
78{
79	// bits 16:29
80	*(Elf32_Half*)P = (Elf32_Half)value;
81}
82
83
84static inline bool
85write_half16_check(addr_t P, Elf32_Word value)
86{
87	// bits 16:29
88	if ((value & 0xffff0000) && (~value & 0xffff8000))
89		return false;
90	*(Elf32_Half*)P = (Elf32_Half)value;
91	return true;
92}
93
94
95static inline Elf32_Word
96lo(Elf32_Word value)
97{
98	return (value & 0xffff);
99}
100
101
102static inline Elf32_Word
103hi(Elf32_Word value)
104{
105	return ((value >> 16) & 0xffff);
106}
107
108
109static inline Elf32_Word
110ha(Elf32_Word value)
111{
112	return (((value >> 16) + (value & 0x8000 ? 1 : 0)) & 0xffff);
113}
114
115
116#ifdef _BOOT_MODE
117status_t
118boot_arch_elf_relocate_rela(struct preloaded_elf32_image *image,
119	Elf32_Rela *rel, int rel_len)
120#else
121int
122arch_elf_relocate_rela(struct elf_image_info *image,
123	struct elf_image_info *resolve_image, Elf32_Rela *rel, int rel_len)
124#endif
125{
126	int i;
127	Elf32_Sym *sym;
128	int vlErr;
129
130	Elf32_Addr S = 0;	// symbol address
131	addr_t R = 0;		// section relative symbol address
132
133	addr_t G = 0;		// GOT address
134	addr_t L = 0;		// PLT address
135
136	#define P	((addr_t)(image->text_region.delta + rel[i].r_offset))
137	#define A	((addr_t)rel[i].r_addend)
138	#define B	(image->text_region.delta)
139
140	// TODO: Get the GOT address!
141	#define REQUIRE_GOT	\
142		if (G == 0) {	\
143			dprintf("arch_elf_relocate_rela(): Failed to get GOT address!\n"); \
144			return B_ERROR;	\
145		}
146
147	// TODO: Get the PLT address!
148	#define REQUIRE_PLT	\
149		if (L == 0) {	\
150			dprintf("arch_elf_relocate_rela(): Failed to get PLT address!\n"); \
151			return B_ERROR;	\
152		}
153
154	for (i = 0; i * (int)sizeof(Elf32_Rela) < rel_len; i++) {
155#if CHATTY
156		dprintf("looking at rel type %d, offset 0x%lx, sym 0x%lx, addend 0x%lx\n",
157			ELF32_R_TYPE(rel[i].r_info), rel[i].r_offset, ELF32_R_SYM(rel[i].r_info), rel[i].r_addend);
158#endif
159		switch (ELF32_R_TYPE(rel[i].r_info)) {
160			case R_PPC_SECTOFF:
161			case R_PPC_SECTOFF_LO:
162			case R_PPC_SECTOFF_HI:
163			case R_PPC_SECTOFF_HA:
164				dprintf("arch_elf_relocate_rela(): Getting section relative "
165					"symbol addresses not yet supported!\n");
166				return B_ERROR;
167
168			case R_PPC_ADDR32:
169			case R_PPC_ADDR24:
170			case R_PPC_ADDR16:
171			case R_PPC_ADDR16_LO:
172			case R_PPC_ADDR16_HI:
173			case R_PPC_ADDR16_HA:
174			case R_PPC_ADDR14:
175			case R_PPC_ADDR14_BRTAKEN:
176			case R_PPC_ADDR14_BRNTAKEN:
177			case R_PPC_REL24:
178			case R_PPC_REL14:
179			case R_PPC_REL14_BRTAKEN:
180			case R_PPC_REL14_BRNTAKEN:
181			case R_PPC_GLOB_DAT:
182			case R_PPC_UADDR32:
183			case R_PPC_UADDR16:
184			case R_PPC_REL32:
185			case R_PPC_SDAREL16:
186			case R_PPC_ADDR30:
187			case R_PPC_JMP_SLOT:
188				sym = SYMBOL(image, ELF32_R_SYM(rel[i].r_info));
189
190#ifdef _BOOT_MODE
191				vlErr = boot_elf_resolve_symbol(image, sym, &S);
192#else
193				vlErr = elf_resolve_symbol(image, sym, resolve_image, &S);
194#endif
195				if (vlErr < 0) {
196					dprintf("%s(): Failed to relocate "
197						"entry index %d, rel type %d, offset 0x%lx, sym 0x%lx, "
198						"addend 0x%lx\n", __FUNCTION__, i, ELF32_R_TYPE(rel[i].r_info),
199						rel[i].r_offset, ELF32_R_SYM(rel[i].r_info),
200						rel[i].r_addend);
201					return vlErr;
202				}
203				break;
204		}
205
206		switch (ELF32_R_TYPE(rel[i].r_info)) {
207			case R_PPC_NONE:
208				break;
209
210			case R_PPC_COPY:
211				// TODO: Implement!
212				dprintf("arch_elf_relocate_rela(): R_PPC_COPY not yet "
213					"supported!\n");
214				return B_ERROR;
215
216			case R_PPC_ADDR32:
217			case R_PPC_GLOB_DAT:
218			case R_PPC_UADDR32:
219				write_word32(P, S + A);
220				break;
221
222			case R_PPC_ADDR24:
223				if (write_low24_check(P, (S + A) >> 2))
224					break;
225dprintf("R_PPC_ADDR24 overflow\n");
226				return B_BAD_DATA;
227
228			case R_PPC_ADDR16:
229			case R_PPC_UADDR16:
230				if (write_half16_check(P, S + A))
231					break;
232dprintf("R_PPC_ADDR16 overflow\n");
233				return B_BAD_DATA;
234
235			case R_PPC_ADDR16_LO:
236				write_half16(P, lo(S + A));
237				break;
238
239			case R_PPC_ADDR16_HI:
240				write_half16(P, hi(S + A));
241				break;
242
243			case R_PPC_ADDR16_HA:
244				write_half16(P, ha(S + A));
245				break;
246
247			case R_PPC_ADDR14:
248			case R_PPC_ADDR14_BRTAKEN:
249			case R_PPC_ADDR14_BRNTAKEN:
250				if (write_low14_check(P, (S + A) >> 2))
251					break;
252dprintf("R_PPC_ADDR14 overflow\n");
253				return B_BAD_DATA;
254
255			case R_PPC_REL24:
256				if (write_low24_check(P, (S + A - P) >> 2))
257					break;
258dprintf("R_PPC_REL24 overflow: 0x%lx\n", (S + A - P) >> 2);
259				return B_BAD_DATA;
260
261			case R_PPC_REL14:
262			case R_PPC_REL14_BRTAKEN:
263			case R_PPC_REL14_BRNTAKEN:
264				if (write_low14_check(P, (S + A - P) >> 2))
265					break;
266dprintf("R_PPC_REL14 overflow\n");
267				return B_BAD_DATA;
268
269			case R_PPC_GOT16:
270				REQUIRE_GOT;
271				if (write_half16_check(P, G + A))
272					break;
273dprintf("R_PPC_GOT16 overflow\n");
274				return B_BAD_DATA;
275
276			case R_PPC_GOT16_LO:
277				REQUIRE_GOT;
278				write_half16(P, lo(G + A));
279				break;
280
281			case R_PPC_GOT16_HI:
282				REQUIRE_GOT;
283				write_half16(P, hi(G + A));
284				break;
285
286			case R_PPC_GOT16_HA:
287				REQUIRE_GOT;
288				write_half16(P, ha(G + A));
289				break;
290
291			case R_PPC_JMP_SLOT:
292			{
293				// If the relative offset is small enough, we fabricate a
294				// relative branch instruction ("b <addr>").
295				addr_t jumpOffset = S - P;
296				if ((jumpOffset & 0xfc000000) != 0
297					&& (~jumpOffset & 0xfe000000) != 0) {
298					// Offset > 24 bit.
299					// TODO: Implement!
300					// See System V PPC ABI supplement, p. 5-6!
301					dprintf("arch_elf_relocate_rela(): R_PPC_JMP_SLOT: "
302						"Offsets > 24 bit currently not supported!\n");
303dprintf("jumpOffset: %p\n", (void*)jumpOffset);
304					return B_ERROR;
305				} else {
306					// Offset <= 24 bit
307					// 0:5 opcode (= 18), 6:29 address, 30 AA, 31 LK
308					// "b" instruction: opcode = 18, AA = 0, LK = 0
309					// address: 24 high-order bits of 26 bit offset
310					*(uint32*)P = 0x48000000 | ((jumpOffset) & 0x03fffffc);
311				}
312				break;
313			}
314
315			case R_PPC_RELATIVE:
316				write_word32(P, B + A);
317				break;
318
319			case R_PPC_LOCAL24PC:
320// TODO: Implement!
321// low24*
322// 				if (write_low24_check(P, ?)
323// 					break;
324// 				return B_BAD_DATA;
325				dprintf("arch_elf_relocate_rela(): R_PPC_LOCAL24PC not yet "
326					"supported!\n");
327				return B_ERROR;
328
329			case R_PPC_REL32:
330				write_word32(P, S + A - P);
331				break;
332
333			case R_PPC_PLTREL24:
334				REQUIRE_PLT;
335				if (write_low24_check(P, (L + A - P) >> 2))
336					break;
337dprintf("R_PPC_PLTREL24 overflow\n");
338				return B_BAD_DATA;
339
340			case R_PPC_PLT32:
341				REQUIRE_PLT;
342				write_word32(P, L + A);
343				break;
344
345			case R_PPC_PLTREL32:
346				REQUIRE_PLT;
347				write_word32(P, L + A - P);
348				break;
349
350			case R_PPC_PLT16_LO:
351				REQUIRE_PLT;
352				write_half16(P, lo(L + A));
353				break;
354
355			case R_PPC_PLT16_HI:
356				REQUIRE_PLT;
357				write_half16(P, hi(L + A));
358				break;
359
360			case R_PPC_PLT16_HA:
361				write_half16(P, ha(L + A));
362				break;
363
364			case R_PPC_SDAREL16:
365// TODO: Implement!
366// 				if (write_half16_check(P, S + A - _SDA_BASE_))
367// 					break;
368// 				return B_BAD_DATA;
369				dprintf("arch_elf_relocate_rela(): R_PPC_SDAREL16 not yet "
370					"supported!\n");
371				return B_ERROR;
372
373			case R_PPC_SECTOFF:
374				if (write_half16_check(P, R + A))
375					break;
376dprintf("R_PPC_SECTOFF overflow\n");
377				return B_BAD_DATA;
378
379			case R_PPC_SECTOFF_LO:
380				write_half16(P, lo(R + A));
381				break;
382
383			case R_PPC_SECTOFF_HI:
384				write_half16(P, hi(R + A));
385				break;
386
387			case R_PPC_SECTOFF_HA:
388				write_half16(P, ha(R + A));
389				break;
390
391			case R_PPC_ADDR30:
392				write_word30(P, (S + A - P) >> 2);
393				break;
394
395			default:
396				dprintf("arch_elf_relocate_rela: unhandled relocation type %d\n", ELF32_R_TYPE(rel[i].r_info));
397				return B_ERROR;
398		}
399	}
400
401	return B_NO_ERROR;
402}
403
404