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