diff options
author | Alex Auvolat <alex.auvolat@ens.fr> | 2015-02-13 21:52:48 +0100 |
---|---|---|
committer | Alex Auvolat <alex.auvolat@ens.fr> | 2015-02-13 21:52:48 +0100 |
commit | 47e6cd42f0744f6c04b8347093f6549339a856c9 (patch) | |
tree | c91fc43178d136c2aa0f093087ba8cfb4e90bdae /src/kernel/user | |
parent | cf0b8a52287ee7c747b1d5a7d77abdef1fb46f94 (diff) | |
download | kogata-47e6cd42f0744f6c04b8347093f6549339a856c9.tar.gz kogata-47e6cd42f0744f6c04b8347093f6549339a856c9.zip |
Implement ELF loading ; arrange so that user processes run.
Diffstat (limited to 'src/kernel/user')
-rw-r--r-- | src/kernel/user/elf.c | 70 | ||||
-rw-r--r-- | src/kernel/user/process.c | 8 |
2 files changed, 78 insertions, 0 deletions
diff --git a/src/kernel/user/elf.c b/src/kernel/user/elf.c new file mode 100644 index 0000000..905577d --- /dev/null +++ b/src/kernel/user/elf.c @@ -0,0 +1,70 @@ +#include <string.h> + +#include <elf.h> + + +bool is_elf(fs_handle_t *f) { + elf_ehdr_t h; + if (file_read(f, 0, sizeof(elf_ehdr_t), (char*)&h) != sizeof(elf_ehdr_t)) return false; + + return (h.e_ident[0] == 0x7F && h.e_ident[1] == 'E' + && h.e_ident[2] == 'L' && h.e_ident[3] == 'F'); +} + +proc_entry_t elf_load(fs_handle_t *f, process_t* process) { + if (!is_elf(f)) return 0; + + elf_ehdr_t ehdr; + if (file_read(f, 0, sizeof(elf_ehdr_t), (char*)&ehdr) != sizeof(elf_ehdr_t)) return 0; + + elf_phdr_t phdr; + int i; + + pagedir_t *r = get_current_pagedir(); + switch_pagedir(proc_pagedir(process)); + + // TODO : when we fail, free ressources ? + + for (i = 0; i < ehdr.e_phnum; i++) { + size_t read_phdr_r = + file_read(f, + ehdr.e_phoff + i * sizeof(elf_phdr_t), + sizeof(elf_phdr_t), + (char*)&phdr); + if (read_phdr_r != sizeof(elf_phdr_t)) goto error; + + if (phdr.p_type == PT_LOAD) { + if (phdr.p_flags & PF_W) { + mmap(process, (void*)phdr.p_vaddr, phdr.p_memsz, + ((phdr.p_flags & PF_R) ? MM_READ : 0) | MM_WRITE); + + size_t read_r = file_read(f, phdr.p_offset, phdr.p_filesz, (char*)phdr.p_vaddr); + if (read_r != phdr.p_filesz) goto error; + + if (phdr.p_memsz > phdr.p_filesz) { + memset((char*)phdr.p_vaddr + phdr.p_filesz, 0, phdr.p_memsz - phdr.p_filesz); + } + } else { + if (phdr.p_filesz != phdr.p_memsz) { + dbg_printf("Strange ELF file...\n"); + goto error; + } + + mmap_file(process, + f, phdr.p_offset, + (void*)phdr.p_vaddr, phdr.p_memsz, + ((phdr.p_flags & PF_R) ? MM_READ : 0) | ((phdr.p_flags & PF_X) ? MM_EXEC : 0)); + } + } + } + + switch_pagedir(r); + + return (proc_entry_t)ehdr.e_entry; + +error: + switch_pagedir(r); + return 0; +} + +/* vim: set ts=4 sw=4 tw=0 noet :*/ diff --git a/src/kernel/user/process.c b/src/kernel/user/process.c index b8b0c23..0f4892d 100644 --- a/src/kernel/user/process.c +++ b/src/kernel/user/process.c @@ -114,6 +114,10 @@ bool start_process(process_t *p, void* entry) { return true; } +pagedir_t *proc_pagedir(process_t *p) { + return p->pd; +} + // ================================== // // MANAGING FILESYSTEMS FOR PROCESSES // // ================================== // @@ -224,6 +228,10 @@ bool munmap(process_t *proc, void* addr) { } } + // TODO : write modified pages back to file! + + if (r->file != 0) unref_file(r->file); + free(r); return true; |