Use uintptr_t, not intptr_t, for memory addresses!
[marionette.git] / kernel / loadelf.c
blob8b18471fb58444e54b2bef59a7c7f727d1df5ee0
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 "mm/region.h"
31 #include "thread.h"
32 #include "console.h"
33 #include "extlib.h"
34 #include "trace.h"
36 extern char stack[];
38 int load_elf_module(void *vaddr, uintptr_t paddr, size_t size)
40 struct Elf32_Ehdr *ehdr = vaddr;
41 struct Elf32_Phdr *phdr;
42 struct addr_space *aspace;
43 int i;
44 struct vm_region *vmr;
45 struct thread *module_thread;
47 // verify magic bytes
48 if (ehdr->e_ident[EI_MAG0] == ELFMAG0
49 && ehdr->e_ident[EI_MAG1] == ELFMAG1
50 && ehdr->e_ident[EI_MAG2] == ELFMAG2
51 && ehdr->e_ident[EI_MAG3] == ELFMAG3){
52 // ok
53 } else {
54 TRACE("Not an ELF file.");
55 return 1;
57 if (ehdr->e_ident[EI_CLASS] != ELFCLASS32){
58 TRACE("invalid or unsupported ELF class");
59 return 1;
61 if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB){
62 TRACE("invalid or unsupported ELF data encoding");
63 return 1;
65 if (ehdr->e_type != ET_EXEC){
66 TRACE("ELF file is not an executable. I can't, erm, execute it.");
67 return 1;
69 if (ehdr->e_machine != EM_386){
70 TRACE("ELF file is not for a 386. I can't execute it.");
71 return 1;
73 // map program segments into the correct places
74 aspace = addr_space_new();
75 if (!aspace){
76 TRACE("Cannot create addr_space for ELF module");
77 return 1;
79 phdr = (struct Elf32_Phdr *) ((char *) vaddr + ehdr->e_phoff);
80 for (i=0; i<ehdr->e_phnum; ++i){
81 if (phdr->p_type == PT_DYNAMIC){
82 TRACE("ELF file requires dynamic linking, and I haven't written a dynamic linker yet.");
83 addr_space_delete(aspace);
84 return 1;
85 } else if (phdr->p_type == PT_PHDR){
86 TRACE("ELF file has a PT_PHDR segment; not implemented yet.");
87 addr_space_delete(aspace);
88 return 1;
89 } else if (phdr->p_type == PT_LOAD){
90 if (phdr->p_vaddr > 0xC0000000){
91 TRACE("ELF file wants to load above 0xC0000000");
92 addr_space_delete(aspace);
93 return 1;
94 } else if (phdr->p_vaddr < 0x1000){
95 TRACE("ELF file wants to load in NULL page.");
96 addr_space_delete(aspace);
97 return 1;
98 } else {
99 // TODO: load bss segments: phdr->p_filesz == 0
100 unsigned int map_flags = 0;
101 if (phdr->p_flags & PF_W){
102 map_flags |= VM_R_WRITABLE;
104 vmr = vm_region_new_physical_fixed(aspace,
105 phdr->p_vaddr,
106 uldivru(phdr->p_memsz, PAGE_SIZE),
107 paddr + phdr->p_offset);
108 if (!vmr){
109 TRACE("pagedir_add_region() failed - cannot map ELF segment");
112 } else {
113 TRACE("Unknown segment type: %d!", phdr->p_type);
115 phdr = (struct Elf32_Phdr *) ((char *) phdr + ehdr->e_phentsize);
118 // create a task to run the module in
119 module_thread = thread_new();
120 thread_set_aspace(module_thread, aspace);
121 thread_set_eip(module_thread, ehdr->e_entry);
122 // XXX: Guessing stack size, blah blah == bad
123 thread_set_esp(module_thread, (uint32_t) stack + 0x4000);
124 thread_set_userspace(module_thread, 1);
125 thread_resume(module_thread);
126 return 0;