aboutsummaryrefslogtreecommitdiff
path: root/src/kernel/user
diff options
context:
space:
mode:
Diffstat (limited to 'src/kernel/user')
-rw-r--r--src/kernel/user/elf.c21
-rw-r--r--src/kernel/user/process.c43
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;