Updated PCI IDs to latest snapshot.
[tangerine.git] / arch / x86_64-pc / bootstrap / elfloader.c
blobb2c447ec7f2222c48d815d0ced9218a809095eba
1 /*
2 Copyright (C) 2006 The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: ELF64 loader extracted from our internal_load_seg_elf in dos.library.
6 Lang: English
7 */
9 //#define DEBUG
10 #define BOOTSTRAP
12 #include "../include/aros/kernel.h"
13 #include "elfloader.h"
14 #include "screen.h"
15 #include "bootstrap.h"
16 #include "support.h"
19 * This two pointers are used by the ELF loader to claim for memory ranges for both
20 * the RW sections (.data, .bss and such) and RO sections (.text, .rodata....) of executable.
21 * Keeping both areas of memory separate reduces the memory waste when more modules are
22 * loaded. Moreover, the whole RO range may be marked for MMU as read-only at once.
24 char *ptr_ro = (char*)KERNEL_TARGET_ADDRESS;
25 char *ptr_rw = (char*)KERNEL_TARGET_ADDRESS;
26 struct _bss_tracker {
27 unsigned long long addr;
28 unsigned long long len;
29 } *bss_tracker;
31 void *kernel_lowest()
33 return ptr_rw;
36 void *kernel_highest()
38 return ptr_ro;
41 void set_base_address(void *ptr, void *tracker)
43 ptr_ro = ptr_rw = ptr;
44 bss_tracker = (struct _bss_tracker *)tracker;
48 * read_block function copies the range of memory within ELF file to any specified location.
50 static int read_block(void *file, long offset, void *dest, long length)
52 __bs_memcpy(dest, (void *)((long)file + offset), length);
53 return 1;
57 * load_block returns a pointer to the memory location within ELF file.
59 static void *load_block(void *file, long offset, long length)
61 return (void*)((long)file + offset);
65 * Test for correct ELF header here
67 static int check_header(struct elfheader *eh)
71 eh->ident[0] != 0x7f ||
72 eh->ident[1] != 'E' ||
73 eh->ident[2] != 'L' ||
74 eh->ident[3] != 'F'
77 kprintf("[ELF Loader] Not an ELF object\n");
78 return 0;
81 if (eh->type != ET_REL || eh->machine != EM_X86_64)
83 kprintf("[ELF Loader] Wrong object type or wrong architecture\n");
84 return 0;
86 return 1;
90 * Get the memory for chunk and load it
92 static int load_hunk(void *file, struct sheader *sh)
94 void *ptr=(void*)0;
96 /* empty chunk? Who cares :) */
97 if (!sh->size)
98 return 1;
100 /* Allocate a chunk with write access - take aligned memory beneath the RO kernel */
101 if (sh->flags & SHF_WRITE)
103 D(kprintf("[ELF Loader] RW chunk (%d bytes, align=%d) @ ", (unsigned int)sh->size, (unsigned int)sh->addralign));
104 ptr = (void*)(((unsigned long)ptr_rw - (unsigned long)sh->size - (unsigned long)sh->addralign + 1) & ~((unsigned long)sh->addralign-1));
105 ptr_rw = ptr;
107 else
109 /* Read-Only mode? Get the memory from the kernel space, align it accorting to the demand */
110 D(kprintf("[ELF Loader] RO chunk (%d bytes, align=%d) @ ", (unsigned int)sh->size, (unsigned int)sh->addralign));
111 ptr_ro = (char *)(((unsigned long)ptr_ro + (unsigned long)sh->addralign - 1) & ~((unsigned long)sh->addralign-1));
112 ptr = ptr_ro;
113 ptr_ro = ptr_ro + sh->size;
115 D(kprintf("%p\n", (unsigned int)ptr));
117 sh->addr = (long)ptr;
119 /* copy block of memory from ELF file if it exists */
120 if (sh->type != SHT_NOBITS)
121 return read_block(file, sh->offset, (void *)((unsigned long)sh->addr), sh->size);
122 else
124 __bs_bzero(ptr, sh->size);
125 bss_tracker->addr = KERNEL_OFFSET | (unsigned long long)ptr;
126 bss_tracker->len = sh->size;
127 bss_tracker++;
128 bss_tracker->addr = NULL;
129 bss_tracker->len = 0;
132 return 1;
135 /* Perform relocations of given section */
136 static int relocate(struct elfheader *eh, struct sheader *sh, long shrel_idx, unsigned long long virt)
138 struct sheader *shrel = &sh[shrel_idx];
139 struct sheader *shsymtab = &sh[shrel->link];
140 struct sheader *toreloc = &sh[shrel->info];
142 struct symbol *symtab = (struct symbol *)((unsigned long)shsymtab->addr);
143 struct relo *rel = (struct relo *)((unsigned long)shrel->addr);
144 char *section = (char *)((unsigned long)toreloc->addr);
146 unsigned int numrel = (unsigned long)shrel->size / (unsigned long)shrel->entsize;
147 unsigned int i;
149 struct symbol *SysBase_sym = (void*)0;
151 D(kprintf("[ELF Loader] performing %d relocations, target address %p%p\n",
152 numrel, (unsigned long)(virt >> 32), (unsigned long)virt));
154 for (i=0; i<numrel; i++, rel++)
156 struct symbol *sym = &symtab[ELF64_R_SYM(rel->info)];
157 unsigned long *p = (unsigned long *)&section[rel->offset];
158 unsigned long long s;
160 switch (sym->shindex)
162 case SHN_UNDEF:
163 D(kprintf("[ELF Loader] Undefined symbol '%s' while relocating the section '%s'\n",
164 (char *)((unsigned long)sh[shsymtab->link].addr) + sym->name,
165 (char *)((unsigned long)sh[eh->shstrndx].addr) + toreloc->name));
166 return 0;
168 case SHN_COMMON:
169 D(kprintf("[ELF Loader] COMMON symbol '%s' while relocating the section '%s'\n",
170 (char *)((unsigned long)sh[shsymtab->link].addr) + sym->name,
171 (char *)((unsigned long)sh[eh->shstrndx].addr) + toreloc->name));
173 return 0;
175 case SHN_ABS:
176 if (SysBase_sym == (void*)0)
178 if (__bs_strncmp((char *)((unsigned long)sh[shsymtab->link].addr) + sym->name, "SysBase", 8) == 0)
180 SysBase_sym = sym;
181 goto SysBase_yes;
183 else
184 goto SysBase_no;
186 else
187 if (SysBase_sym == sym)
189 SysBase_yes: s = (unsigned long long)4ULL;
191 else
192 SysBase_no: s = sym->value;
193 break;
195 default:
196 s = (unsigned long long)sh[sym->shindex].addr + virt + sym->value;
199 //s+=virt;
201 switch (ELF64_R_TYPE(rel->info))
203 case R_X86_64_64: /* 64bit direct/absolute */
204 *(unsigned long long *)p = s + rel->addend;// + virt;
205 break;
207 case R_X86_64_PC32: /* PC relative 32 bit signed */
208 *p = s + rel->addend - (unsigned long)((unsigned long long)p + virt);
209 break;
211 case R_X86_64_32:
212 *(unsigned long *)p = (unsigned long long)s + (unsigned long long)rel->addend;// + virt;
213 break;
215 case R_X86_64_32S:
216 *(signed long *)p = (signed long long)s + (signed long long)rel->addend;// + virt;
217 break;
219 case R_X86_64_NONE: /* No reloc */
220 break;
222 default:
223 kprintf("[ELF Loader] Unrecognized relocation type %d %d\n", i, (unsigned int)ELF64_R_TYPE(rel->info));
224 return 0;
227 return 1;
230 void load_elf_file(void *file, unsigned long long virt)
232 struct elfheader eh;
233 struct sheader *sh;
234 long i;
235 int addr_displayed = 0;
237 D(kprintf("[ELF Loader] Loading ELF module from address %p\n", (unsigned int)file));
239 /* Check the header of ELF file */
242 !read_block(file, 0, &eh, sizeof(eh)) ||
243 !check_header(&eh) ||
244 !(sh = load_block(file, eh.shoff, eh.shnum * eh.shentsize))
247 kprintf("[ELF Loader] Wrong module header, aborting.\n");
248 return;
251 /* Iterate over the section header in order to prepare memory and eventually load some hunks */
252 for (i=0; i < eh.shnum; i++)
254 /* Load the symbol and string tables */
255 if (sh[i].type == SHT_SYMTAB || sh[i].type == SHT_STRTAB)
257 sh[i].addr = (unsigned long)load_block(file, sh[i].offset, sh[i].size);
259 /* Does the section require memoy allcation? */
260 else if (sh[i].flags & SHF_ALLOC)
262 /* Yup, it does. Load the hunk */
263 if (!load_hunk(file, &sh[i]))
265 kprintf("[ELF Loader] Error at loading of the hunk!\n");
267 else if (!addr_displayed)
269 kprintf("%p", sh[i].addr);
270 addr_displayed = 1;
275 /* For every loaded section perform the relocations */
276 for (i=0; i < eh.shnum; i++)
278 if (sh[i].type == SHT_RELA && sh[sh[i].info].addr)
280 sh[i].addr = (unsigned long)load_block(file, sh[i].offset, sh[i].size);
281 if (!sh[i].addr || !relocate(&eh, sh, i, virt))
283 kprintf("[ELF Loader] Relocation error!\n");