diff --git a/kernel/boot/kmain.c b/kernel/boot/kmain.c index 68556b3..dcd3765 100644 --- a/kernel/boot/kmain.c +++ b/kernel/boot/kmain.c @@ -35,12 +35,12 @@ int kmain(uint64_t multiboot_magic, void *multiboot_data) uint64_t addr = 0x200000; thread_t *th = new_thread((void *)addr, 1); - uintptr_t page = pmm_alloc(); // Write thread code to address - vmm_set_page(p1->P4, addr, page, PAGE_PRESENT | PAGE_WRITE | PAGE_USER); - memcpy(P2V(page), thread_function, PAGE_SIZE); - // Map a user stack space - vmm_set_page(p1->P4, USERSPACE_TOP-PAGE_SIZE, pmm_alloc(), PAGE_PRESENT | PAGE_WRITE | PAGE_USER); + procmm_map(p1->mmap, addr, addr+PAGE_SIZE, 0); + vmm_p4_memcpy(p1->mmap->P4, (void *)addr, 0, thread_function, PAGE_SIZE); + procmm_setup(p1); + + procmm_print_map(p1->mmap); process_attach(p1, th); scheduler_insert(th); diff --git a/kernel/include/process.h b/kernel/include/process.h index a6ef285..a4636ed 100644 --- a/kernel/include/process.h +++ b/kernel/include/process.h @@ -5,7 +5,9 @@ typedef struct process_st process_t; #include #include #include +#include +struct procmm_mmap_st; typedef struct process_st { uint64_t pid; @@ -13,7 +15,7 @@ typedef struct process_st uint64_t status; lock_t lock; struct process_st *parent; - page_table *P4; + struct procmm_mmap_st *mmap; LIST(struct process_st, children); LIST(struct process_st, siblings); LIST(thread_t, threads); @@ -29,8 +31,34 @@ typedef struct process_st #define get_current_process() (get_cpu()->current_process) #define set_current_process(proc) (get_cpu()->current_process = (proc)) +typedef struct procmm_area_st +{ + uintptr_t start; + uintptr_t end; + uint64_t flags; + struct procmm_mmap_st *map; + LIST(struct procmm_area_st, areas); +} procmm_area_t; + +typedef struct procmm_mmap_st +{ + process_t *proc; + page_table *P4; + LIST(struct procmm_area_st, areas); + procmm_area_t *brk; + procmm_area_t *stack; +} procmm_mmap_t; + + process_t *process_spawn(process_t *parent); void process_attach(process_t *proc, thread_t *th); void switch_process(process_t *proc); void process_exit(process_t *proc, uint64_t status); void process_free(process_t *proc); + +procmm_mmap_t *procmm_new_map(process_t *proc, procmm_mmap_t *src); +void procmm_free_map(process_t *proc); +void procmm_print_map(procmm_mmap_t *map); +procmm_area_t *procmm_map(procmm_mmap_t *map, uintptr_t start, uintptr_t end, uint64_t flags); +void procmm_unmap(procmm_area_t *a); +uintptr_t procmm_setup(process_t *proc); diff --git a/kernel/proc/process.c b/kernel/proc/process.c index 94d8071..8c4239e 100644 --- a/kernel/proc/process.c +++ b/kernel/proc/process.c @@ -12,7 +12,6 @@ process_t *process_spawn(process_t *parent) process_t *proc = kcalloc(1, sizeof(process_t)); proc->pid = pid++; proc->parent = parent; - proc->P4 = vmm_new_P4(); proc->state = PROC_STATE_READY; LIST_INIT(proc, children); @@ -23,7 +22,10 @@ process_t *process_spawn(process_t *parent) { spin_lock(&parent->lock); LIST_APPEND(parent->children, proc, siblings); + proc->mmap = procmm_new_map(proc, parent->mmap); spin_unlock(&parent->lock); + } else { + proc->mmap = procmm_new_map(proc, 0); } if(proc->pid == 1) @@ -55,7 +57,7 @@ void switch_process(process_t *proc) if(proc) { proc->state = PROC_STATE_RUNNING; - vmm_set_P4(proc->P4); + vmm_set_P4(proc->mmap->P4); } else { @@ -91,8 +93,8 @@ void process_free(process_t *proc) free_thread(th); } LIST_REMOVE(proc->parent->children, proc, siblings); - // Free page directory - vmm_free_P4(proc->P4); + // Free memory mappings + procmm_free_map(proc); // Free process structure kfree(proc); } diff --git a/kernel/proc/procmm.c b/kernel/proc/procmm.c new file mode 100644 index 0000000..625e086 --- /dev/null +++ b/kernel/proc/procmm.c @@ -0,0 +1,114 @@ +#include +#include +#include + +procmm_mmap_t *procmm_new_map(process_t *proc, procmm_mmap_t *src) +{ + procmm_mmap_t *map = kcalloc(1, sizeof(procmm_mmap_t)); + map->proc = proc; + map->P4 = vmm_new_P4(); + LIST_INIT(map, areas); + + if(src) + { + LIST_FOREACH(src->areas, procmm_area_t, o, areas) + { + procmm_map(map, o->start, o->end, o->flags); + vmm_p4_memcpy(map->P4, (void *)o->start, src->P4, (void *)o->start, o->end-o->start); + } + } + + return map; +} + +void procmm_free_map(process_t *proc) +{ + procmm_mmap_t *map = proc->mmap; + procmm_area_t *o = map->areas.next; + while(o) + { + procmm_area_t *next = o->areas.next; + procmm_unmap(o); + o = next; + } + map->brk = 0; + map->stack = 0; + vmm_free_P4(map->P4); + kfree(map); +} + +void procmm_print_map(procmm_mmap_t *map) +{ + debug_info("Procmm map (process:%d)\n", map->proc->pid); + LIST_FOREACH(map->areas, procmm_area_t, o, areas) + { + debug(" %x->%x (%x)", o->start, o->end, o->flags); + if(o == map->brk) + debug(" BRK"); + if(o == map->stack) + debug(" STACK"); + debug("\n"); + } +} + +procmm_area_t *procmm_map(procmm_mmap_t *map, uintptr_t start, uintptr_t end, uint64_t flags) +{ + procmm_area_t *a = kcalloc(1, sizeof(procmm_area_t)); + a->start = start; + a->end = end; + a->flags = flags; + a->map = map; + LIST_INIT(a, areas); + + LIST_FOREACH(map->areas, procmm_area_t, o, areas) + { + if(!((o->end < start) || (o->start > a->end))) + { + // Overlapping areas + debug_error("PROCMM - Overlapping areas (unsupported for now)\n"); + kfree(a); + return 0; + } + if(o->start > a->end) + { + LIST_INSERT_BEFORE(map->areas, a, areas, o); + } + } + if(LIST_EMPTY(a->areas)) + LIST_APPEND(map->areas, a, areas); + + uintptr_t p = a->start; + while(p < a->end) + { + vmm_set_page(map->P4, p, pmm_alloc(), PAGE_PRESENT | PAGE_WRITE | PAGE_USER); + p += PAGE_SIZE; + } + + return a; +} +void procmm_unmap(procmm_area_t *a) +{ + uintptr_t p = a->start; + while(p < a->end) + { + uintptr_t ph = vmm_get_page(a->map->P4, p); + pmm_free(ph); + vmm_set_page(a->map->P4, p, 0, 0); + p += PAGE_SIZE; + } + LIST_REMOVE(a->map->areas, a, areas); + kfree(a); +} + +uintptr_t procmm_setup(process_t *proc) +{ + procmm_mmap_t *map = proc->mmap; + procmm_area_t *last_a = map->areas.prev; + + uintptr_t brk_start = (last_a->end + PAGE_SIZE) & ~(PAGE_SIZE-1); + map->brk = procmm_map(map, brk_start, brk_start, 0); + + map->stack = procmm_map(map, USERSPACE_TOP, USERSPACE_TOP, 0); + + return brk_start; +}