]> git.dujemihanovic.xyz Git - nameless-os.git/blob - boot/x86/stage3/elf.c
Load ELF kernel instead of flat binary
[nameless-os.git] / boot / x86 / stage3 / elf.c
1 /* Code for parsing ELF binaries (the kernel) */
2
3 #include <elf.h>
4 #include <paging.h>
5 #include <stdint.h>
6
7 int check_elf_header(struct elf_header *header)
8 {
9 if (header->magic != ELF_MAGIC)
10 return ELF_HEADER_INVALID;
11 if (header->bits != ELF_32BIT)
12 return MISMATCHED_SYSTEM;
13 if (header->endianness != ELF_LITTLE_ENDIAN)
14 return MISMATCHED_SYSTEM;
15 if (header->header_ver != 1)
16 return ELF_HEADER_INVALID;
17 if (header->os_abi != ELF_SYSV_ABI)
18 return MISMATCHED_SYSTEM;
19 if (header->type != ELF_TYPE_EXECUTABLE)
20 return NOT_EXECUTABLE;
21 if (header->machine != ELF_X86_ISA)
22 return MISMATCHED_SYSTEM;
23 if (header->elf_ver != 1)
24 return ELF_HEADER_INVALID;
25
26 return 0;
27 }
28
29 int setup_elf_executable(struct elf_header *header)
30 {
31 /* Check the header. */
32 int header_valid = check_elf_header(header);
33 if (header_valid)
34 return header_valid;
35
36 /* Get the program header. The casting is necessary because without it
37 * the code will add some multiple of the program header offset rather
38 * than the actual offset. */
39 struct program_header *prog_hdr = (struct program_header *) ((uint32_t) header+header->program_hdr);
40 for (int i=0; i<header->ph_entry_count; i++) {
41 /* We're only interested in loadable segments. */
42 if (prog_hdr[i].seg_type != ELF_PT_LOAD)
43 continue;
44
45 /* Calculate the memory range. */
46 void *phys_start, *phys_end, *virt_end;
47 int flags;
48 phys_start = (void *) header + prog_hdr[i].file_offset;
49 if (prog_hdr[i].memsz & 0xfff) { /* Align if needed. */
50 phys_end = phys_start+((prog_hdr[i].memsz+0x1000) & ~0xfff);
51 virt_end = prog_hdr[i].vaddr+((prog_hdr[i].memsz+0x1000) & ~0xfff);
52 }
53 else {
54 phys_end = phys_start+prog_hdr[i].memsz;
55 virt_end = prog_hdr[i].vaddr+prog_hdr[i].memsz;
56 }
57
58 flags = prog_hdr[i].flags & ELF_FLAG_WRITABLE;
59
60 /* Map the range. */
61 int ret = map_range(phys_start, phys_end, prog_hdr[i].vaddr, virt_end, flags);
62 if (ret)
63 return ret;
64 }
65
66 return 0;
67 }
68
69 int execute_elf(struct elf_header *header, void *arg1, int arg2)
70 {
71 /* Check the header and map all needed memory ranges. */
72 int ret = setup_elf_executable(header);
73 if (ret)
74 return ret;
75
76 /* Execute the kernel. */
77 header->entry(arg1, arg2);
78 }