2 * Copyright (c) 2009 Joshua Phillips. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
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
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.
31 #include "mm/paging.h"
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
);
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
;
67 static void *get_section_data(struct elf_file
*restrict e
, struct Elf32_Shdr
70 if (shdr
->sh_type
== SHT_NOBITS
){
71 // section isn't actually allocated in the file
72 return (char *) shdr
->sh_addr
;
74 return (char *) e
->addr
+ shdr
->sh_offset
;
78 static struct Elf32_Sym
*symtab_get_sym(struct elf_file
*restrict e
, struct Elf32_Shdr
81 int offset
; // offset into section
82 offset
= n
* symtab
->sh_entsize
;
83 if (offset
>= symtab
->sh_size
){
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
92 if (offset
<= 0 || offset
>= strtab
->sh_size
){
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
);
104 TRACE("symbol table has no string table");
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
;
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");
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
));
135 TRACE("invalid symbol in relocation (%d)", ELF32_R_SYM(rel
->r_info
));
137 } else if (sym
->st_shndx
== SHN_UNDEF
){
139 // let's try to find it in the kernel's symbol table
140 sym_name
= sym_get_name(e
, symtab_shdr
, sym
);
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/
147 TRACE("undefined symbol: %s", sym_name
);
151 TRACE("undefined, nameless symbol!");
155 // find the raw symbol address
156 if (sym
->st_shndx
== SHN_ABS
){
157 value
= sym
->st_value
;
159 struct Elf32_Shdr
*rel_shdr
= get_shdr(e
, sym
->st_shndx
);
161 TRACE("relocation points to invalid section (%d)", sym
->st_shndx
);
164 value
= rel_shdr
->sh_addr
+ sym
->st_value
;
167 // apply the relocation in the appropriate manner
168 switch (ELF32_R_TYPE(rel
->r_info
)){
170 *(uint32_t *) ((char *) get_section_data(e
, apply_shdr
)
175 *(int32_t *) ((char *) get_section_data(e
, apply_shdr
)
177 += value
- (apply_shdr
->sh_addr
+
181 TRACE("invalid relocation type: %d",
182 ELF32_R_TYPE(rel
->r_info
));
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
;
197 shdr
= get_shdr(e
, 1);
198 for (i
=1; i
<e
->ehdr
->e_shnum
; ++i
){
199 if (shdr
->sh_type
== SHT_SYMTAB
){
202 sym
= (struct Elf32_Sym
*) get_section_data(e
, symtab
);
203 sym_end
= (struct Elf32_Sym
*) ((char *) get_section_data(e
, symtab
)
205 while (sym
< sym_end
){
206 if ((retval
= func(e
, symtab
, sym
, tag
))){
209 sym
= (struct Elf32_Sym
*) ((char *) sym
+ symtab
->sh_entsize
);
212 shdr
= (struct Elf32_Shdr
*) ((char *) shdr
+ e
->ehdr
->e_shentsize
);
217 // Find a global symbol by name
219 struct find_sym_struct
{
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
)){
240 static struct Elf32_Sym
*find_sym(struct elf_file
*restrict e
, const char *name
)
242 struct find_sym_struct s
;
245 foreach_sym(e
, find_sym_func
, &s
);
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
;
258 static int set_section_addresses(struct elf_file
*restrict e
)
260 struct Elf32_Shdr
*shdr
;
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
);
278 TRACE("could not allocate data (%d bytes) for SHT_NOBITS section", shdr
->sh_size
);
281 shdr
->sh_addr
= (Elf32_Addr
) nobits_data
;
283 shdr
= (struct Elf32_Shdr
*) ((char *) shdr
+ e
->ehdr
->e_shentsize
);
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
;
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
;
306 uintptr_t entry_addr
;
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
){
318 TRACE("Not an ELF file.");
321 if (ehdr
->e_ident
[EI_CLASS
] != ELFCLASS32
){
322 TRACE("invalid or unsupported ELF class");
325 if (ehdr
->e_ident
[EI_DATA
] != ELFDATA2LSB
){
326 TRACE("invalid or unsupported ELF data encoding");
329 if (ehdr
->e_type
!= ET_REL
){
330 TRACE("ELF file is not a relocatable. It's not a valid kernel module.");
333 if (ehdr
->e_machine
!= EM_386
){
334 TRACE("ELF file is not for a 386. I can't execute it.");
338 // preliminary pass to find out how much memory we need for COMMON symbols
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
);
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.
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){
363 } else if (shdr
->sh_type
== SHT_RELA
){
364 panic("SHT_RELA not supported!");
366 shdr
= (struct Elf32_Shdr
*) ((char *) shdr
+ ehdr
->e_shentsize
);
370 entry_sym
= find_sym(e
, "_start");
372 TRACE("kernel module has no symbol _start");
375 if (entry_sym
->st_shndx
== SHN_UNDEF
){
376 TRACE("_start is undefined!");
378 } else if (entry_sym
->st_shndx
== SHN_ABS
){
379 entry_addr
= entry_sym
->st_value
;
381 shdr
= get_shdr(e
, entry_sym
->st_shndx
);
383 TRACE("_start is in an invalid section");
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
)();
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
;
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
){
409 TRACE("Not an ELF file.");
412 if (ehdr
->e_ident
[EI_CLASS
] != ELFCLASS32
){
413 TRACE("invalid or unsupported ELF class");
416 if (ehdr
->e_ident
[EI_DATA
] != ELFDATA2LSB
){
417 TRACE("invalid or unsupported ELF data encoding");
420 if (ehdr
->e_type
!= ET_EXEC
){
421 TRACE("ELF file is not an executable. I can't, erm, execute it.");
424 if (ehdr
->e_machine
!= EM_386
){
425 TRACE("ELF file is not for a 386. I can't execute it.");
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.");
434 } else if (phdr
->p_type
== PT_PHDR
){
435 TRACE("ELF file has a PT_PHDR segment; not implemented yet.");
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");
442 } else if (phdr
->p_vaddr
< 0x1000){
443 TRACE("ELF file wants to load in NULL page.");
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
456 TRACE("map_mem() failed - cannot map ELF segment");
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
);