alsa.audio: build the bridge link lib only for linux architecture
[AROS.git] / arch / ppc-sam440 / boot / parthenope / src / elf.c
blobe1a3da172ea65c4226b7b6225ab4bc73f686abe8
1 /*
2 * $Id$
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of
7 * the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
17 * MA 02111-1307 USA
20 #define DEBUG 1
21 #include "elf.h"
22 #include "support.h"
24 extern list_t *debug_info;
26 static char *ptr_ro = (char *)KERNEL_PHYS_BASE;
27 static char *ptr_rw = (char *)KERNEL_PHYS_BASE;
29 char *get_ptr_ro()
31 return ptr_ro;
34 char *get_ptr_rw()
36 return ptr_rw;
39 struct bss_tracker tracker[MAX_BSS_SECTIONS];
40 static struct bss_tracker *bss_tracker = &tracker[0];
43 * read_block function copies the range of memory within ELF file to any specified location.
45 static inline void read_block(void *file, long offset, void *dest, long length)
47 memcpy(dest, (void *)((unsigned long)file + offset), length);
51 * Test for correct ELF header here
53 static int check_header(struct elfheader *eh)
55 if (eh->ident[0] != 0x7f ||
56 eh->ident[1] != 'E' || eh->ident[2] != 'L' || eh->ident[3] != 'F') {
57 return 0;
60 if (eh->type != ET_REL || eh->machine != EM_PPC) {
61 return 0;
63 return 1;
67 * Get the memory for chunk and load it
69 static int load_hunk(void *file, struct sheader *sh)
71 void *ptr = (void *)0;
73 /* empty chunk? Who cares :) */
74 if (!sh->size)
75 return 1;
77 /* Allocate a chunk with write access - take aligned memory beneath the RO kernel */
78 if (sh->flags & SHF_WRITE) {
79 ptr = (void *)(((unsigned long)ptr_rw - (unsigned long)sh->size
80 - (unsigned long)sh->addralign + 1)
81 & ~((unsigned long)sh->addralign - 1));
82 ptr_rw = ptr;
83 } else {
84 /* Read-Only mode? Get the memory from the kernel space, align it accorting to the demand */
85 ptr_ro = (char *)(((unsigned long)ptr_ro
86 + (unsigned long)sh->addralign - 1)
87 & ~((unsigned long)sh->addralign - 1));
88 ptr = ptr_ro;
89 ptr_ro = ptr_ro + sh->size;
92 sh->addr = (long)ptr;
94 /* copy block of memory from ELF file if it exists */
95 if (sh->type != SHT_NOBITS) {
96 read_block(file, sh->offset, (void *)((unsigned long)sh->addr),
97 sh->size);
98 } else {
99 bzero(ptr, sh->size);
100 bss_tracker->addr =
101 (void *)((unsigned long)ptr + KERNEL_VIRT_BASE -
102 KERNEL_PHYS_BASE);
103 bss_tracker->length = sh->size;
104 bss_tracker++;
107 return 1;
110 /* Perform relocations of given section */
111 static int relocate(struct elfheader *eh, struct sheader *sh, long shrel_idx,
112 uint32_t virt)
114 struct sheader *shrel = &sh[shrel_idx];
115 struct sheader *shsymtab = &sh[shrel->link];
116 struct sheader *toreloc = &sh[shrel->info];
118 struct symbol *symtab =
119 (struct symbol *)((unsigned long)shsymtab->addr);
120 struct relo *rel = (struct relo *)((unsigned long)shrel->addr);
121 char *section = (char *)((unsigned long)toreloc->addr);
123 unsigned int numrel = (unsigned long)shrel->size
124 / (unsigned long)shrel->entsize;
125 unsigned int i;
127 uint32_t virtoffset;
129 struct symbol *SysBase_sym = (void *)0;
131 for (i = 0; i < numrel; i++, rel++) {
132 struct symbol *sym = &symtab[ELF32_R_SYM(rel->info)];
133 uint32_t *p = (uint32_t *) & section[rel->offset];
134 uint32_t s;
135 virtoffset = virt;
137 switch (sym->shindex) {
138 case SHN_UNDEF:
139 printf
140 ("[ELF Loader] Undefined symbol '%s' in section '%s'\n",
141 (char *)((uint32_t) sh[shsymtab->link].addr) +
142 sym->name,
143 (char *)((uint32_t) sh[eh->shstrndx].addr) +
144 toreloc->name);
145 return 0;
147 case SHN_COMMON:
148 printf
149 ("[ELF Loader] COMMON symbol '%s' in section '%s'\n",
150 (char *)((uint32_t) sh[shsymtab->link].addr) +
151 sym->name,
152 (char *)((uint32_t) sh[eh->shstrndx].addr) +
153 toreloc->name);
155 return 0;
157 case SHN_ABS:
158 if (SysBase_sym == (void *)0) {
159 if (strncmp
160 ((char *)((uint32_t) sh[shsymtab->link].
161 addr) + sym->name, "SysBase",
162 8) == 0) {
163 SysBase_sym = sym;
164 goto SysBase_yes;
165 } else
166 goto SysBase_no;
167 } else if (SysBase_sym == sym) {
168 SysBase_yes: s = (uint32_t) 4UL;
169 virtoffset = 0;
170 } else
171 SysBase_no: s = sym->value;
172 break;
173 default:
174 s = (uint32_t) sh[sym->shindex].addr + sym->value;
177 switch (ELF32_R_TYPE(rel->info)) {
178 case R_PPC_ADDR32:
179 *p = s + rel->addend + virtoffset;
180 break;
182 case R_PPC_ADDR16_LO:
184 unsigned short *c = (unsigned short *)p;
185 *c = (s + rel->addend + virtoffset) & 0xffff;
187 break;
189 case R_PPC_ADDR16_HA:
191 unsigned short *c = (unsigned short *)p;
192 uint32_t temp = s + rel->addend + virtoffset;
193 *c = temp >> 16;
194 if ((temp & 0x8000) != 0)
195 (*c)++;
197 break;
199 case R_PPC_REL24:
200 *p &= ~0x3fffffc;
201 *p |= (s + rel->addend - (uint32_t) p) & 0x3fffffc;
202 break;
204 case R_PPC_REL32:
205 *p = s + rel->addend - (uint32_t) p;
206 break;
208 case R_PPC_NONE:
209 break;
211 default:
212 printf("[BOOT] Unknown relocation %d in ELF file\n",
213 ELF32_R_TYPE(rel->info));
214 return 0;
217 return 1;
220 int load_elf_file(const char *name, void *file)
222 struct elfheader *eh;
223 struct sheader *sh;
224 long i;
225 int shown = 0;
227 module_t *mod;
229 eh = file;
231 /* Check the header of ELF file */
232 if (!check_header(eh)) {
233 printf("[BOOT] ELF header invalid\n");
234 return 0;
237 sh = (struct sheader *)((unsigned long)file + eh->shoff);
239 /* Iterate over the section header in order to prepare memory and eventually load some hunks */
240 for (i = 0; i < eh->shnum; i++) {
241 /* Load the symbol and string tables */
242 if (sh[i].type == SHT_SYMTAB || sh[i].type == SHT_STRTAB) {
243 sh[i].addr = (unsigned long)file + sh[i].offset;
245 /* Does the section require memoy allcation? */
246 else if (sh[i].flags & SHF_ALLOC) {
247 /* Yup, it does. Load the hunk */
248 if (!load_hunk(file, &sh[i])) {
249 return 0;
250 } else {
251 if (sh[i].size && !shown) {
252 printf
253 ("[BOOT] ELF: section loaded at %p (Virtual addr: %p)\n",
254 sh[i].addr,
255 sh[i].addr + KERNEL_VIRT_BASE -
256 KERNEL_PHYS_BASE);
257 shown = 1;
263 /* For every loaded section perform the relocations */
264 for (i = 0; i < eh->shnum; i++) {
265 if (sh[i].type == SHT_RELA && sh[sh[i].info].addr) {
266 sh[i].addr = (uint32_t) file + sh[i].offset;
267 if (!sh[i].addr
268 || !relocate(eh, sh, i,
269 KERNEL_VIRT_BASE - KERNEL_PHYS_BASE)) {
270 return 0;
275 /* Register the module */
276 mod = malloc(sizeof(module_t));
277 (printf("[BOOT] module=%p\n", mod));
279 if (mod)
281 int i,j;
283 new_list(&mod->m_symbols);
285 mod->m_name = malloc(strlen(name)+1);
286 mod->m_lowest = 0xffffffff;
287 mod->m_highest = 0x00000000;
288 mod->m_str = NULL;
290 if (mod->m_name)
292 memcpy(mod->m_name, name, strlen(name)+1);
294 (printf("[BOOT] name=%s\n", mod->m_name));
296 for (i=0; i < eh->shnum; i++)
298 /* If we have string table, copy it */
299 if (sh[i].type == SHT_STRTAB && i != eh->shstrndx)
301 if (!mod->m_str)
303 mod->m_str = malloc(sh[i].size);
304 memcpy(mod->m_str, (void *)sh[i].addr, sh[i].size);
306 (printf("[BOOT] symbol table copied from %p to %p\n", sh[i].addr, mod->m_str));
310 if ((sh[i].flags & (SHF_ALLOC | SHF_EXECINSTR)) == (SHF_ALLOC | SHF_EXECINSTR))
312 if (sh[i].addr)
314 unsigned long virt = sh[i].addr + KERNEL_VIRT_BASE - KERNEL_PHYS_BASE;
316 if (virt < mod->m_lowest)
317 mod->m_lowest = virt;
318 if (virt + sh[i].size > mod->m_highest)
319 mod->m_highest = virt + sh[i].size;
324 (printf("[BOOT] m_lowest=%p, m_highest=%p\n", mod->m_lowest, mod->m_highest));
325 for (i=0; i < eh->shnum; i++)
327 if (sh[i].addr && sh[i].type == SHT_SYMTAB)
329 struct symbol *st = (struct symbol *)sh[i].addr;
331 for (j=0; j < (sh[i].size / sizeof(struct symbol)); j++)
333 if (sh[st[j].shindex].addr && (sh[st[j].shindex].flags & (SHF_ALLOC | SHF_EXECINSTR)) == (SHF_ALLOC | SHF_EXECINSTR))
335 symbol_t *sym = malloc(sizeof(symbol_t));
336 sym->s_name = &mod->m_str[st[j].name];
337 sym->s_lowest = sh[st[j].shindex].addr + st[j].value + KERNEL_VIRT_BASE - KERNEL_PHYS_BASE;
338 sym->s_highest = sym->s_lowest + st[j].size;
340 add_head(&mod->m_symbols, &sym->s_node);
344 break;
348 add_head(debug_info, &mod->m_node);
352 return 1;