UnnamedOS
elf.c
Go to the documentation of this file.
1 
14 #include <common.h>
15 #include <string.h>
16 #include <tasks/elf.h>
17 #include <interrupts/isr.h>
18 
19 #define MAGIC_0 0x7F
20 #define MAGIC_1 'E'
21 #define MAGIC_2 'L'
22 #define MAGIC_3 'F'
23 #define VERSION 1
24 
25 enum elf_class { CLASS_32_BIT = 1, CLASS_64_BIT };
28 enum elf_data { DATA_LITTLE_ENDIAN = 1, DATA_BIG_ENDIAN };
30 enum elf_type { TYPE_RELOCATABLE = 1, TYPE_EXECUTABLE, TYPE_SHARED, TYPE_CORE };
32 enum elf_machine { MACHINE_X86 = 3, /*...*/ };
33 
35 typedef struct {
36  enum {
37  // we will only need PT_LOAD (load a segment into memory) for now
38  PT_NULL, PT_LOAD, PT_DYNAMIC, PT_INTERP, PT_NOTE, PT_SHLIB, PT_PHDR
39  } p_type;
40  uint32_t p_offset;
41  void* p_vaddr;
42  void* p_paddr;
43  uint32_t p_filesz;
44  uint32_t p_memsz;
45  enum {
46  PF_X = 0b1, PF_W = 0b10, PF_R = 0b100
47  } p_flags;
48  uint32_t p_align;
49 } __attribute__((packed)) elf_program_header_entry_t;
50 
56 static uint8_t elf_check(elf_t* elf) {
57  if (elf->e_ident.EI_MAG0 != MAGIC_0 || elf->e_ident.EI_MAG1 != MAGIC_1 ||
58  elf->e_ident.EI_MAG2 != MAGIC_2 || elf->e_ident.EI_MAG3 != MAGIC_3) {
59  println("%4aELF magic not found%a");
60  return 0;
61  }
62  if (elf->e_ident.EI_CLASS != CLASS_32_BIT) {
63  println("%4aELF not 32-bit%a");
64  return 0;
65  }
66  if (elf->e_ident.EI_DATA != DATA_LITTLE_ENDIAN) {
67  println("%4aELF not little endian%a");
68  return 0;
69  }
70  if (elf->e_ident.EI_VERSION != VERSION || elf->e_version != VERSION) {
71  println("%4aELF version not 1%a");
72  return 0;
73  }
74  if (elf->e_type != TYPE_EXECUTABLE) {
75  println("%4aELF not executable%a");
76  return 0;
77  }
78  if (elf->e_machine != MACHINE_X86) {
79  println("%4aELF target not x86%a");
80  return 0;
81  }
82  return 1;
83 }
84 
92  if (!elf_check(elf)) // check whether it's a suitable ELF file
93  return 0;
94  // find the program header table that contains info on how to load the file
95  elf_program_header_entry_t* program_header_table =
96  (elf_program_header_entry_t*) ((uintptr_t) elf + elf->e_phoff);
97  logln("ELF", "Program header entries:");
98  vmm_modify_page_directory(page_directory);
99  for (int i = 0; i < elf->e_phnum; i++) { // process every entry in the table
100  elf_program_header_entry_t* entry = program_header_table + i;
101  logln("ELF", "[%d] type=%d offset=%08x vaddr=%08x paddr=%08x "
102  "filesz=%08x memsz=%08x flags=%03b align=%08x", i,
103  entry->p_type, entry->p_offset, entry->p_vaddr, entry->p_paddr,
104  entry->p_filesz, entry->p_memsz, entry->p_flags, entry->p_align);
105  if (entry->p_type == PT_LOAD) { // we only process LOAD segments for now
106  // claim the memory so that we can write to it
107  vmm_use_virtual_memory(entry->p_vaddr, entry->p_memsz,
108  entry->p_flags & PF_W ? VMM_USER | VMM_WRITABLE : VMM_USER);
109  // Fill the complete segment with zeroes. (There are cases when the
110  // segment's p_memsz is bigger than p_filesz, for example for BSS
111  // sections which need to be initialized with zeroes.)
112  memset(entry->p_vaddr, 0, entry->p_memsz);
113  // Now copy the actual segment's data from the file to memory.
114  memcpy(entry->p_vaddr, (void*) ((uintptr_t) elf + entry->p_offset),
115  entry->p_filesz);
116  }
117  }
119  return elf->e_entry;
120 }
121 
128  if (!elf_check(elf))
129  return;
130  elf_program_header_entry_t* program_header_table =
131  (elf_program_header_entry_t*) ((uintptr_t) elf + elf->e_phoff);
132  vmm_modify_page_directory(page_directory);
133  for (int i = 0; i < elf->e_phnum; i++) {
134  elf_program_header_entry_t* entry = program_header_table + i;
135  if (entry->p_type == PT_LOAD)
136  vmm_free(entry->p_vaddr, entry->p_memsz);
137  }
139 }
140 
148 task_pid_t elf_create_task(elf_t* elf, size_t kernel_stack_len,
149  size_t user_stack_len) {
150  if (!elf) {
151  println("%4aELF not found%a");
152  return 0;
153  }
156  task_pid_t pid = task_create_user(elf_load(elf, dir), dir,
157  kernel_stack_len, user_stack_len, elf);
158  isr_enable_interrupts(old_interrupts);
159  return pid;
160 }
161 
169  task_destroy(pid);
170  isr_enable_interrupts(old_interrupts);
171 }
172 
page_directory_t * vmm_create_page_directory()
Creates an empty page directory.
Definition: vmm.c:72
uint8_t isr_enable_interrupts(uint8_t enable)
Enables or disables interrupts.
Definition: isr.c:42
void * vmm_use_virtual_memory(void *vaddr, size_t len, vmm_flags_t flags)
Marks some page(s) as used and maps them into memory.
Definition: vmm.c:496
void * e_entry
entry point
Definition: elf.h:31
#define VERSION
only ELF version 1 is supported (the current version)
Definition: elf.c:23
uint32_t p_offset
where the segment starts in the file
Definition: elf.c:40
void * p_vaddr
where the segment is located in virtual memory
Definition: elf.c:41
elf_data
little or big endian
Definition: elf.c:28
static page_directory_t * page_directory
the current page directory
Definition: vmm.c:44
void vmm_modified_page_directory()
Ends a page directory modification.
Definition: vmm.c:164
uint32_t p_memsz
the segment&#39;s length in memory
Definition: elf.c:44
uint32_t e_phoff
program header table (important for executables)
Definition: elf.h:32
#define MAGIC_1
magic value expected at the beginning of an ELF file
Definition: elf.c:20
task_pid_t task_create_user(void *entry_point, page_directory_t *page_directory, size_t kernel_stack_len, size_t user_stack_len, void *elf)
Creates a user task.
Definition: task.c:143
void elf_destroy_task(task_pid_t pid)
Destroys a user task running the code of an ELF file.
Definition: elf.c:166
#define MAGIC_3
magic value expected at the beginning of an ELF file
Definition: elf.c:22
void * p_paddr
same for physical memory (only on systems without MMU)
Definition: elf.c:42
static uint8_t old_interrupts
for temporary modifications
Definition: vmm.c:46
task_pid_t elf_create_task(elf_t *elf, size_t kernel_stack_len, size_t user_stack_len)
Creates a user task running the code of an ELF file.
Definition: elf.c:148
elf_type
object type
Definition: elf.c:30
uint32_t p_filesz
the segment&#39;s length in the file
Definition: elf.c:43
uint32_t task_pid_t
unique process ID
Definition: task.h:17
#define MAGIC_2
magic value expected at the beginning of an ELF file
Definition: elf.c:21
static uint8_t elf_check(elf_t *elf)
Checks whether a pointer points to a valid ELF file for this OS.
Definition: elf.c:56
void vmm_free(void *vaddr, size_t len)
Frees the given page(s) and unmaps them from memory.
Definition: vmm.c:528
void * elf_load(elf_t *elf, page_directory_t *page_directory)
Loads the segments of an ELF file into memory.
Definition: elf.c:91
An entry in a page directory.
Definition: vmm.h:25
program header entries tell us how to load executables
Definition: elf.c:35
elf_machine
targeted ISA, we are only interested in x86
Definition: elf.c:32
elf_class
32 or 64 bit
Definition: elf.c:26
void vmm_modify_page_directory(page_directory_t *new_directory)
Loads a page directory for temporary modification.
Definition: vmm.c:149
enum elf_program_header_entry_t::@13 p_flags
whether the segment should be executable, writable or readable
uint16_t e_phnum
number of program header entries
Definition: elf.h:37
page_directory_t * task_get_page_directory(task_pid_t pid)
Returns a task&#39;s page directory.
Definition: task.c:258
void elf_unload(elf_t *elf, page_directory_t *page_directory)
Frees the segments of an ELF file in memory.
Definition: elf.c:127
void * task_get_elf(task_pid_t pid)
Returns a task&#39;s ELF file.
Definition: task.c:276
void task_destroy(task_pid_t pid)
Destroys a task.
Definition: task.c:161
uint32_t p_align
how this segment is aligned
Definition: elf.c:48
The ELF header at the start of every ELF file.
Definition: elf.h:15
enum elf_program_header_entry_t::@12 p_type
program header type
#define MAGIC_0
magic value expected at the beginning of an ELF file
Definition: elf.c:19