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