Removed excessive traces in loadelf.c
[marionette.git] / kernel / loadelf.c
blob62b2eb4e73e8783b7a00b1c6b90da6b888f42582
1 /*
2 * Copyright (c) 2009 Joshua Phillips. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in
12 * the documentation and/or other materials provided with the
13 * distribution.
15 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
16 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 * DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
19 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
21 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
23 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
25 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 #include "loadelf.h"
29 #include "elf.h"
30 #include "archinf.h"
31 #include "mm/paging.h"
32 #include "thread.h"
33 #include "console.h"
34 #include "stdlib.h"
35 #include "extlib.h"
36 #include "string.h"
37 #include "symtab.h"
38 #include "trace.h"
39 #include "assert.h"
40 #include "panic.h"
42 extern char stack[];
44 struct elf_file {
45 void *addr; // base address of ELF file in memory
46 struct Elf32_Ehdr *ehdr;
47 struct Elf32_Shdr *common_shdr; // NOBITS section for putting COMMON symbols
48 int common_size; // size of all the COMMON symbols
49 int common_pos; // allocation position for COMMON symbols
52 static struct Elf32_Shdr *get_shdr(struct elf_file *restrict e, int n)
54 if (n >= 1 && n < e->ehdr->e_shnum){
55 return (struct Elf32_Shdr *) ((char *) e->addr + e->ehdr->e_shoff + n * e->ehdr->e_shentsize);
56 } else {
57 return NULL;
61 static int get_shndx(struct elf_file *restrict e, struct Elf32_Shdr *shdr)
63 int n = ((char *) shdr - ((char *) e->addr + e->ehdr->e_shoff)) / e->ehdr->e_shentsize;
64 return n;
67 static void *get_section_data(struct elf_file *restrict e, struct Elf32_Shdr
68 *shdr)
70 if (shdr->sh_type == SHT_NOBITS){
71 // section isn't actually allocated in the file
72 return (char *) shdr->sh_addr;
73 } else {
74 return (char *) e->addr + shdr->sh_offset;
78 static struct Elf32_Sym *symtab_get_sym(struct elf_file *restrict e, struct Elf32_Shdr
79 *symtab, int n)
81 int offset; // offset into section
82 offset = n * symtab->sh_entsize;
83 if (offset >= symtab->sh_size){
84 return NULL;
86 return (struct Elf32_Sym *) ((char *) get_section_data(e, symtab) + offset);
89 static const char *get_string(struct elf_file *restrict e, struct Elf32_Shdr
90 *strtab, int offset)
92 if (offset <= 0 || offset >= strtab->sh_size){
93 return NULL;
94 } else {
95 return (const char *) get_section_data(e, strtab) + offset;
99 static const char *sym_get_name(struct elf_file *restrict e, struct Elf32_Shdr
100 *symtab, struct Elf32_Sym *sym)
102 struct Elf32_Shdr *strtab = get_shdr(e, symtab->sh_link);
103 if (!strtab){
104 TRACE("symbol table has no string table");
105 return NULL;
107 return get_string(e, strtab, sym->st_name);
110 static int do_relocs(struct elf_file *restrict e, struct Elf32_Shdr *rel_shdr)
112 struct Elf32_Shdr *symtab_shdr, *apply_shdr;
113 struct Elf32_Rel *rel, *rel_end;
114 struct Elf32_Sym *sym;
115 const char *sym_name;
116 uintptr_t value_from_symtab;
117 Elf32_Addr value;
119 symtab_shdr = get_shdr(e, rel_shdr->sh_link);
120 apply_shdr = get_shdr(e, rel_shdr->sh_info);
121 if (!symtab_shdr || !apply_shdr){
122 TRACE("invalid sh_link/sh_info in relocation section");
123 return 1;
126 // loop through all the relocations
127 rel = get_section_data(e, rel_shdr);
128 rel_end = (struct Elf32_Rel *) ((char *) rel + rel_shdr->sh_size);
129 for (; rel < rel_end;
130 rel = (struct Elf32_Rel *) ((char *) rel + (rel_shdr->sh_entsize))){
132 // get the symbol that the relocation points to
133 sym = symtab_get_sym(e, symtab_shdr, ELF32_R_SYM(rel->r_info));
134 if (!sym){
135 TRACE("invalid symbol in relocation (%d)", ELF32_R_SYM(rel->r_info));
136 return 1;
137 } else if (sym->st_shndx == SHN_UNDEF){
138 // undefined symbol
139 // let's try to find it in the kernel's symbol table
140 sym_name = sym_get_name(e, symtab_shdr, sym);
141 if (sym_name){
142 value_from_symtab = symtab_lookup(sym_name);
143 if (value_from_symtab){
144 value = value_from_symtab;
145 goto got_value; // http://xkcd.com/292/
146 } else {
147 TRACE("undefined symbol: %s", sym_name);
148 return 1;
150 } else {
151 TRACE("undefined, nameless symbol!");
152 return 1;
154 } else {
155 // find the raw symbol address
156 if (sym->st_shndx == SHN_ABS){
157 value = sym->st_value;
158 } else {
159 struct Elf32_Shdr *rel_shdr = get_shdr(e, sym->st_shndx);
160 if (!rel_shdr){
161 TRACE("relocation points to invalid section (%d)", sym->st_shndx);
162 return 1;
164 value = rel_shdr->sh_addr + sym->st_value;
166 got_value:
167 // apply the relocation in the appropriate manner
168 switch (ELF32_R_TYPE(rel->r_info)){
169 case R_386_32:
170 *(uint32_t *) ((char *) get_section_data(e, apply_shdr)
171 + rel->r_offset)
172 += value;
173 break;
174 case R_386_PC32:
175 *(int32_t *) ((char *) get_section_data(e, apply_shdr)
176 + rel->r_offset)
177 += value - (apply_shdr->sh_addr +
178 rel->r_offset);
179 break;
180 default:
181 TRACE("invalid relocation type: %d",
182 ELF32_R_TYPE(rel->r_info));
183 return 1;
187 return 0;
190 // Call a function for every symbol
191 static int foreach_sym(struct elf_file *restrict e, int (* func)(struct elf_file *restrict e, struct Elf32_Shdr *symtab, struct Elf32_Sym *sym, void *tag), void *tag)
193 struct Elf32_Shdr *shdr, *symtab;
194 struct Elf32_Sym *sym, *sym_end;
195 int i, retval;
197 shdr = get_shdr(e, 1);
198 for (i=1; i<e->ehdr->e_shnum; ++i){
199 if (shdr->sh_type == SHT_SYMTAB){
200 symtab = shdr;
202 sym = (struct Elf32_Sym *) get_section_data(e, symtab);
203 sym_end = (struct Elf32_Sym *) ((char *) get_section_data(e, symtab)
204 + symtab->sh_size);
205 while (sym < sym_end){
206 if ((retval = func(e, symtab, sym, tag))){
207 return retval;
209 sym = (struct Elf32_Sym *) ((char *) sym + symtab->sh_entsize);
212 shdr = (struct Elf32_Shdr *) ((char *) shdr + e->ehdr->e_shentsize);
214 return 0;
217 // Find a global symbol by name
219 struct find_sym_struct {
220 const char *name;
221 struct Elf32_Sym *sym;
224 static int find_sym_func(struct elf_file *restrict e, struct Elf32_Shdr *symtab, struct Elf32_Sym *sym, void *tag)
226 struct find_sym_struct *restrict s = tag;
228 if (ELF32_ST_BIND(sym->st_info) == STB_GLOBAL){
229 const char *sym_name;
231 sym_name = sym_get_name(e, symtab, sym);
232 if (sym_name && !strcmp(sym_name, s->name)){
233 s->sym = sym;
234 return 1;
237 return 0;
240 static struct Elf32_Sym *find_sym(struct elf_file *restrict e, const char *name)
242 struct find_sym_struct s;
243 s.name = name;
244 s.sym = NULL;
245 foreach_sym(e, find_sym_func, &s);
246 return s.sym;
249 static int count_common_size(struct elf_file *restrict e, struct Elf32_Shdr *symtab, struct Elf32_Sym *sym, void *tag)
251 int *p_common_size = tag;
252 if (sym->st_shndx == SHN_COMMON){
253 *p_common_size += sym->st_size;
255 return 0;
258 static int set_section_addresses(struct elf_file *restrict e)
260 struct Elf32_Shdr *shdr;
261 int i;
263 // set the section addresses
264 shdr = get_shdr(e, 1);
265 for (i=1; i<e->ehdr->e_shnum; ++i){
266 if (shdr->sh_type == SHT_PROGBITS){
267 shdr->sh_addr = (Elf32_Addr) e->addr + shdr->sh_offset;
268 } else if (shdr->sh_type == SHT_NOBITS){
269 // we have to allocate our own memory for this section
270 if (e->common_shdr == NULL){
271 // we have to include the common symbols, too
272 e->common_shdr = shdr;
273 e->common_pos = shdr->sh_size;
274 shdr->sh_size += e->common_size;
276 void *nobits_data = malloc(shdr->sh_size);
277 if (!nobits_data){
278 TRACE("could not allocate data (%d bytes) for SHT_NOBITS section", shdr->sh_size);
279 return 1;
281 shdr->sh_addr = (Elf32_Addr) nobits_data;
283 shdr = (struct Elf32_Shdr *) ((char *) shdr + e->ehdr->e_shentsize);
285 return 0;
288 static int allocate_common_symbols(struct elf_file *restrict e, struct Elf32_Shdr *symtab, struct Elf32_Sym *sym, void *tag)
290 if (sym->st_shndx == SHN_COMMON){
291 assert(e->common_shdr);
292 sym->st_shndx = get_shndx(e, e->common_shdr);
293 sym->st_value = e->common_pos;
294 e->common_pos += sym->st_size;
296 return 0;
299 int load_elf_kernel_module(void *vaddr, uintptr_t paddr, size_t size)
301 struct elf_file _e, *e = &_e;
302 struct Elf32_Ehdr *ehdr = vaddr;
303 struct Elf32_Sym *entry_sym;
304 struct Elf32_Shdr *shdr;
305 int i;
306 uintptr_t entry_addr;
308 e->addr = vaddr;
309 e->ehdr = ehdr;
311 // verify magic bytes
312 if (ehdr->e_ident[EI_MAG0] == ELFMAG0
313 && ehdr->e_ident[EI_MAG1] == ELFMAG1
314 && ehdr->e_ident[EI_MAG2] == ELFMAG2
315 && ehdr->e_ident[EI_MAG3] == ELFMAG3){
316 // ok
317 } else {
318 TRACE("Not an ELF file.");
319 return 1;
321 if (ehdr->e_ident[EI_CLASS] != ELFCLASS32){
322 TRACE("invalid or unsupported ELF class");
323 return 1;
325 if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB){
326 TRACE("invalid or unsupported ELF data encoding");
327 return 1;
329 if (ehdr->e_type != ET_REL){
330 TRACE("ELF file is not a relocatable. It's not a valid kernel module.");
331 return 1;
333 if (ehdr->e_machine != EM_386){
334 TRACE("ELF file is not for a 386. I can't execute it.");
335 return 1;
338 // preliminary pass to find out how much memory we need for COMMON symbols
339 e->common_size = 0;
340 foreach_sym(e, count_common_size, &e->common_size);
341 e->common_shdr = NULL;
343 // set the section addresses and allocate NOBITS sections
344 int ret = set_section_addresses(e);
345 if (ret){
346 return ret;
349 // allocate COMMON symbols
350 foreach_sym(e, allocate_common_symbols, NULL);
351 assert(e->common_size == e->common_pos);
353 // TODO: we really need to do some more clearing up on failure
354 // and, of course, when the module is unloaded.
356 // Do relocations
357 shdr = get_shdr(e, 1);
358 for (i=1; i<ehdr->e_shnum; ++i){
359 if (shdr->sh_type == SHT_REL){
360 if (do_relocs(e, shdr) != 0){
361 return 1;
363 } else if (shdr->sh_type == SHT_RELA){
364 panic("SHT_RELA not supported!");
366 shdr = (struct Elf32_Shdr *) ((char *) shdr + ehdr->e_shentsize);
369 // Run _start
370 entry_sym = find_sym(e, "_start");
371 if (!entry_sym){
372 TRACE("kernel module has no symbol _start");
373 return 1;
374 } else {
375 if (entry_sym->st_shndx == SHN_UNDEF){
376 TRACE("_start is undefined!");
377 return 1;
378 } else if (entry_sym->st_shndx == SHN_ABS){
379 entry_addr = entry_sym->st_value;
380 } else {
381 shdr = get_shdr(e, entry_sym->st_shndx);
382 if (!shdr){
383 TRACE("_start is in an invalid section");
384 return 1;
386 entry_addr = (uintptr_t) get_section_data(e, shdr) + entry_sym->st_value;
388 typedef void (* voidfunc_t)(void);
389 ((voidfunc_t) entry_addr)();
392 return 0;
395 int load_elf_module(struct pagedir *target_pd, void *vaddr, uintptr_t paddr, size_t size)
397 struct Elf32_Ehdr *ehdr = vaddr;
398 struct Elf32_Phdr *phdr;
399 int i;
400 struct thread *module_thread;
402 // verify magic bytes
403 if (ehdr->e_ident[EI_MAG0] == ELFMAG0
404 && ehdr->e_ident[EI_MAG1] == ELFMAG1
405 && ehdr->e_ident[EI_MAG2] == ELFMAG2
406 && ehdr->e_ident[EI_MAG3] == ELFMAG3){
407 // ok
408 } else {
409 TRACE("Not an ELF file.");
410 return 1;
412 if (ehdr->e_ident[EI_CLASS] != ELFCLASS32){
413 TRACE("invalid or unsupported ELF class");
414 return 1;
416 if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB){
417 TRACE("invalid or unsupported ELF data encoding");
418 return 1;
420 if (ehdr->e_type != ET_EXEC){
421 TRACE("ELF file is not an executable. I can't, erm, execute it.");
422 return 1;
424 if (ehdr->e_machine != EM_386){
425 TRACE("ELF file is not for a 386. I can't execute it.");
426 return 1;
428 // map program segments into the correct places
429 phdr = (struct Elf32_Phdr *) ((char *) vaddr + ehdr->e_phoff);
430 for (i=0; i<ehdr->e_phnum; ++i){
431 if (phdr->p_type == PT_DYNAMIC){
432 TRACE("ELF file requires dynamic linking, and I haven't written a dynamic linker yet.");
433 return 1;
434 } else if (phdr->p_type == PT_PHDR){
435 TRACE("ELF file has a PT_PHDR segment; not implemented yet.");
436 return 1;
437 } else if (phdr->p_type == PT_LOAD){
438 // TODO: don't hard-code, please
439 if (phdr->p_vaddr > 0xC0000000){
440 TRACE("ELF file wants to load above 0xC0000000");
441 return 1;
442 } else if (phdr->p_vaddr < 0x1000){
443 TRACE("ELF file wants to load in NULL page.");
444 return 1;
445 } else {
446 // TODO: load bss segments: phdr->p_filesz == 0
447 unsigned int map_flags = PTE_PRESENT | PTE_USER;
448 if (phdr->p_flags & PF_W){
449 map_flags |= PTE_WRITABLE;
451 if (map_mem(target_pd,
452 paddr + phdr->p_offset, // physical
453 phdr->p_vaddr, // virtual
454 uldivru(phdr->p_memsz, PAGE_SIZE), // n_pages
455 map_flags) != 0){
456 TRACE("map_mem() failed - cannot map ELF segment");
459 } else {
460 TRACE("Unknown segment type: %d!", phdr->p_type);
462 phdr = (struct Elf32_Phdr *) ((char *) phdr + ehdr->e_phentsize);
465 // create a task to run the module in
466 module_thread = thread_new();
467 thread_set_pagedir(module_thread, target_pd);
468 thread_set_eip(module_thread, ehdr->e_entry);
469 // XXX: Guessing stack size, blah blah == bad
470 thread_set_esp(module_thread, (uint32_t) stack + 0x4000);
471 thread_set_userspace(module_thread, 1);
472 thread_resume(module_thread);
473 return 0;