diff options
author | Alex Auvolat <alex.auvolat@ens.fr> | 2015-02-14 22:37:35 +0100 |
---|---|---|
committer | Alex Auvolat <alex.auvolat@ens.fr> | 2015-02-14 22:37:35 +0100 |
commit | 73cf3eddd480f2bd7e987c58da82c243861a5314 (patch) | |
tree | b6cf499e261cd2e4d87bd08b499ebdf1b97adf90 /src/kernel/user | |
parent | fcc321d0ef1771edff61a986df62d2cda2d7485e (diff) | |
download | kogata-73cf3eddd480f2bd7e987c58da82c243861a5314.tar.gz kogata-73cf3eddd480f2bd7e987c58da82c243861a5314.zip |
Many things :
- fix context switching (it actually worked only because of optimizations!)
- complete mchmap implementation
- adjust elf parser to load binaries correctly even without FM_MMAP
Diffstat (limited to 'src/kernel/user')
-rw-r--r-- | src/kernel/user/elf.c | 21 | ||||
-rw-r--r-- | src/kernel/user/process.c | 43 |
2 files changed, 54 insertions, 10 deletions
diff --git a/src/kernel/user/elf.c b/src/kernel/user/elf.c index 00b3c54..a3dada7 100644 --- a/src/kernel/user/elf.c +++ b/src/kernel/user/elf.c @@ -34,9 +34,10 @@ proc_entry_t elf_load(fs_handle_t *f, process_t* process) { 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, + if ((phdr.p_flags & PF_W) || !(file_get_mode(f) & FM_MMAP)) { + bool mmap_ok = mmap(process, (void*)phdr.p_vaddr, phdr.p_memsz, ((phdr.p_flags & PF_R) ? MM_READ : 0) | MM_WRITE); + if (!mmap_ok) goto error; 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; @@ -44,16 +45,22 @@ proc_entry_t elf_load(fs_handle_t *f, process_t* process) { if (phdr.p_memsz > phdr.p_filesz) { memset((char*)phdr.p_vaddr + phdr.p_filesz, 0, phdr.p_memsz - phdr.p_filesz); } + + if (!(phdr.p_flags & PF_W)) { + bool mchmap_ok = mchmap(process, (void*)phdr.p_vaddr, + ((phdr.p_flags & PF_R) ? MM_READ : 0)); + if (!mchmap_ok) goto error; + } } 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)); + bool mmap_ok = 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)); + if (!mmap_ok) goto error; } } } diff --git a/src/kernel/user/process.c b/src/kernel/user/process.c index a4383f7..72042d9 100644 --- a/src/kernel/user/process.c +++ b/src/kernel/user/process.c @@ -177,6 +177,10 @@ bool mmap_file(process_t *proc, fs_handle_t *h, size_t offset, void* addr, size_ if ((uint32_t)addr & (~PAGE_MASK)) return false; + int fmode = file_get_mode(h); + if (!(fmode & FM_MMAP) || !(fmode & FM_READ)) return false; + if ((mode & MM_WRITE) && !(fmode & FM_WRITE)) return false; + user_region_t *r = (user_region_t*)malloc(sizeof(user_region_t)); if (r == 0) return false; @@ -212,6 +216,24 @@ bool mchmap(process_t *proc, void* addr, int mode) { if (r == 0) return false; r->mode = mode; + + // change mode on already mapped pages + pagedir_t *save_pd = get_current_pagedir(); + switch_pagedir(proc->pd); + for (void* it = r->addr; it < r->addr + r->size; r += PAGE_SIZE) { + uint32_t ent = pd_get_entry(it); + uint32_t frame = pd_get_frame(it); + + if (ent & PTE_PRESENT) { + bool can_w = (ent & PTE_RW) != 0; + bool should_w = (mode & MM_WRITE) != 0; + if (can_w != should_w) { + pd_map_page(it, frame, should_w); + } + } + } + switch_pagedir(save_pd); + return true; } @@ -230,12 +252,27 @@ bool munmap(process_t *proc, void* addr) { } } - // TODO : write modified pages back to file! - // TODO : unmap mapped page for region... + btree_remove_v(proc->regions_idx, r->addr, r); + + // Unmap that stuff + pagedir_t *save_pd = get_current_pagedir(); + switch_pagedir(proc->pd); + for (void* it = r->addr; it < r->addr + r->size; r += PAGE_SIZE) { + uint32_t ent = pd_get_entry(it); + uint32_t frame = pd_get_frame(it); + + if (ent & PTE_PRESENT) { + if ((ent & PTE_DIRTY) && (r->mode & MM_WRITE) && r->file != 0) { + file_write(r->file, it - r->addr + r->file_offset, PAGE_SIZE, it); + } + pd_unmap_page(it); + frame_free(frame, 1); + } + } + switch_pagedir(save_pd); if (r->file != 0) unref_file(r->file); - btree_remove_v(proc->regions_idx, r->addr, r); free(r); return true; |