1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
|
#include <assert.h>
#include <crypto/SHA1/sha1.h>
#include <elf.h>
#include <fcntl.h>
#include <sched/scheduler.h>
#include <stddef.h>
#include <typedefs.h>
void *load_elf_file(const char *f, u32 *ds) {
ELFHeader header;
int fd = vfs_open(f, O_RDONLY, 0);
if (fd < 0) {
return NULL;
}
if (sizeof(header) != vfs_pread(fd, &header, sizeof(header), 0)) {
return NULL;
}
if (0 != memcmp(header.e_ident, "\x7F\x45\x4C\x46" /* "\x7FELF" */, 4)) {
return NULL;
}
Elf32_Phdr program_header;
assert(sizeof(program_header) == header.e_phentsize);
u32 header_offset = header.e_phoff;
uintptr_t end_of_code = 0;
for (int i = 0; i < header.e_phnum;
i++, header_offset += header.e_phentsize) {
if (0 >=
vfs_pread(fd, &program_header, sizeof(program_header), header_offset)) {
return NULL;
}
// FIXME: Only one type is supported, which is 1(load). More should be
// added.
assert(1 == program_header.p_type);
// 1. Clear p_memsz bytes at p_vaddr to 0.(We also allocate frames for
// that range)
u32 p_memsz = program_header.p_memsz;
u32 p_vaddr = program_header.p_vaddr;
u32 pages_to_allocate = (u32)align_page((void *)(p_vaddr + p_memsz));
pages_to_allocate -= p_vaddr - (p_vaddr % 0x1000);
pages_to_allocate /= 0x1000;
if (!mmu_allocate_region((void *)p_vaddr, pages_to_allocate * 0x1000,
MMU_FLAG_RW, NULL)) {
return NULL;
}
uintptr_t e = program_header.p_vaddr + program_header.p_memsz;
if (e > end_of_code) {
end_of_code = e;
}
memset((void *)program_header.p_vaddr, 0, program_header.p_memsz);
// 2. Copy p_filesz bytes from p_offset to p_vaddr
int rc = vfs_pread(fd, (void *)program_header.p_vaddr,
program_header.p_filesz, program_header.p_offset);
assert(rc == (int)program_header.p_filesz);
}
*ds = end_of_code;
vfs_close(fd);
return (void *)header.e_entry;
}
|