aboutsummaryrefslogtreecommitdiff
path: root/src/kernel/user
diff options
context:
space:
mode:
authorAlex Auvolat <alex.auvolat@ens.fr>2015-02-13 21:52:48 +0100
committerAlex Auvolat <alex.auvolat@ens.fr>2015-02-13 21:52:48 +0100
commit47e6cd42f0744f6c04b8347093f6549339a856c9 (patch)
treec91fc43178d136c2aa0f093087ba8cfb4e90bdae /src/kernel/user
parentcf0b8a52287ee7c747b1d5a7d77abdef1fb46f94 (diff)
downloadkogata-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.c70
-rw-r--r--src/kernel/user/process.c8
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;