diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/kernel/Makefile | 2 | ||||
-rw-r--r-- | src/kernel/core/idt.c | 13 | ||||
-rw-r--r-- | src/kernel/core/paging.c | 4 | ||||
-rw-r--r-- | src/kernel/core/thread.c | 2 | ||||
-rw-r--r-- | src/kernel/include/thread.h | 2 | ||||
-rw-r--r-- | src/kernel/user/process.c | 182 |
6 files changed, 159 insertions, 46 deletions
diff --git a/src/kernel/Makefile b/src/kernel/Makefile index e847827..bca1765 100644 --- a/src/kernel/Makefile +++ b/src/kernel/Makefile @@ -2,7 +2,7 @@ OBJ = core/loader.o core/kmain.o core/dbglog.o core/sys.o \ core/gdt.o core/idt.o core/interrupt.o core/context_switch.o core/thread.o \ core/frame.o core/paging.o core/region.o core/kmalloc.o \ - user/vfs.o user/nullfs.o + user/vfs.o user/nullfs.o user/process.o LIB = ../common/common.lib diff --git a/src/kernel/core/idt.c b/src/kernel/core/idt.c index cb02bf9..e1862c9 100644 --- a/src/kernel/core/idt.c +++ b/src/kernel/core/idt.c @@ -3,6 +3,7 @@ #include <sys.h> #include <string.h> #include <dbglog.h> +#include <thread.h> struct idt_entry { uint16_t base_lo; //Low part of address to jump to @@ -92,10 +93,14 @@ void idt_exHandler(registers_t *regs) { if (ex_handlers[regs->int_no] != 0) { ex_handlers[regs->int_no](regs); } else { - //TODO: make sure all exceptions happenning in userspace do not cause kernel panic... - dbg_printf("Unhandled exception: %i\n", regs->int_no); - dbg_dump_registers(regs); - PANIC("Unhandled exception"); + if (regs->eip >= K_HIGHHALF_ADDR) { + dbg_printf("Unhandled exception in kernel code: %i\n", regs->int_no); + dbg_dump_registers(regs); + PANIC("Unhandled exception"); + } else { + ASSERT(current_thread != 0 && current_thread->user_ex_handler != 0); + current_thread->user_ex_handler(regs); + } } } diff --git a/src/kernel/core/paging.c b/src/kernel/core/paging.c index e39a872..74331c0 100644 --- a/src/kernel/core/paging.c +++ b/src/kernel/core/paging.c @@ -65,8 +65,8 @@ void page_fault_handler(registers_t *regs) { // remark : sti should always be executed, it is stupid to run user code with interrupts disabled if ((size_t)vaddr >= K_HIGHHALF_ADDR) { - ASSERT(current_thread->kmem_violation_handler != 0); - current_thread->kmem_violation_handler(regs); + ASSERT(current_thread->user_ex_handler != 0); + current_thread->user_ex_handler(regs); } else { ASSERT(pd->user_pfh != 0); pd->user_pfh(pd->user_pfh_data, regs, vaddr); diff --git a/src/kernel/core/thread.c b/src/kernel/core/thread.c index 519ba41..4ca3f63 100644 --- a/src/kernel/core/thread.c +++ b/src/kernel/core/thread.c @@ -148,7 +148,7 @@ thread_t *new_thread(entry_t entry, void* data) { // used by user processes t->proc = 0; - t->kmem_violation_handler = 0; + t->user_ex_handler = 0; return t; } diff --git a/src/kernel/include/thread.h b/src/kernel/include/thread.h index 74499c6..c8072c9 100644 --- a/src/kernel/include/thread.h +++ b/src/kernel/include/thread.h @@ -28,7 +28,7 @@ typedef struct thread { region_info_t *stack_region; struct process *proc; - isr_handler_t kmem_violation_handler; // page fault in kernel memory accessed by user code (violation) + isr_handler_t user_ex_handler; // page fault in kernel memory accessed by user code (violation) struct thread *next_in_queue; } thread_t; diff --git a/src/kernel/user/process.c b/src/kernel/user/process.c index 9f3e2b1..b8b0c23 100644 --- a/src/kernel/user/process.c +++ b/src/kernel/user/process.c @@ -1,6 +1,8 @@ #include <mutex.h> #include <hashtbl.h> +#include <string.h> +#include <frame.h> #include <process.h> typedef struct user_region { @@ -29,8 +31,8 @@ typedef struct process { static int next_pid = 1; -static void proc_kmem_violation(registers_t *regs); -static void proc_user_pf(void* proc, registers_t *regs, void* addr); +static void proc_user_exception(registers_t *regs); +static void proc_usermem_pf(void* proc, registers_t *regs, void* addr); process_t *current_process() { if (current_thread) return current_thread->proc; @@ -42,7 +44,7 @@ process_t *current_process() { // ============================== // process_t *new_process(process_t *parent) { - process_t *proc = (proces_t*)malloc(sizeof(process_t)); + process_t *proc = (process_t*)malloc(sizeof(process_t)); if (proc == 0) return 0; proc->filesystems = create_hashtbl(str_key_eq_fun, str_hash_fun, free, 0); @@ -51,7 +53,7 @@ process_t *new_process(process_t *parent) { return 0; } - proc->pd = pagedir_create(proc_user_pf, proc); + proc->pd = create_pagedir(proc_usermem_pf, proc); if (proc->pd == 0) { delete_hashtbl(proc->filesystems, 0); free(proc); @@ -74,24 +76,24 @@ static void run_user_code(void* entry) { void* esp = (void*)USERSTACK_ADDR + USERSTACK_SIZE; - asm volatile(" - cli; - - mov $0x23, %%ax; - mov %%ax, %%ds; - mov %%ax, %%es; - mov %%ax, %%fs; - mov %%ax, %%gs; - - pushl $0x23; - pushl %%ebx; - pushf; - pop %%eax; - or $0x200, %%eax; - pushl %%eax; - pushl $0x1B; - pushl %%ecx; - iret + asm volatile(" \ + cli; \ + \ + mov $0x23, %%ax; \ + mov %%ax, %%ds; \ + mov %%ax, %%es; \ + mov %%ax, %%fs; \ + mov %%ax, %%gs; \ + \ + pushl $0x23; \ + pushl %%ebx; \ + pushf; \ + pop %%eax; \ + or $0x200, %%eax; \ + pushl %%eax; \ + pushl $0x1B; \ + pushl %%ecx; \ + iret \ "::"b"(esp),"c"(entry)); } bool start_process(process_t *p, void* entry) { @@ -105,7 +107,7 @@ bool start_process(process_t *p, void* entry) { } th->proc = p; - th->kmem_violation_handler = proc_kmem_violation; + th->user_ex_handler = proc_user_exception; resume_thread(th, false); @@ -137,38 +139,144 @@ fs_t *proc_find_fs(process_t *p, const char* name) { // USER MEMORY REGION MANAGEMENT // // ============================= // +static user_region_t *find_user_region(process_t *proc, void* addr) { + for (user_region_t *it = proc->regions; it != 0; it = it->next) { + if (addr >= it->addr && addr < it->addr + it->size) return it; + } + return 0; +} + bool mmap(process_t *proc, void* addr, size_t size, int mode) { - //TODO - return false; + if (find_user_region(proc, addr) != 0) return false; + + if ((uint32_t)addr & (~PAGE_MASK)) return false; + + user_region_t *r = (user_region_t*)malloc(sizeof(user_region_t)); + if (r == 0) return false; + + r->addr = addr; + r->size = PAGE_ALIGN_UP(size); + + if (r->addr >= (void*)K_HIGHHALF_ADDR || r->addr + r->size > (void*)K_HIGHHALF_ADDR || r->size == 0) { + free(r); + return false; + } + + r->mode = mode; + r->file = 0; + r->file_offset = 0; + + r->next = proc->regions; + proc->regions = r; + + return true; } bool mmap_file(process_t *proc, fs_handle_t *h, size_t offset, void* addr, size_t size, int mode) { - //TODO - return false; + if (find_user_region(proc, addr) != 0) return false; + + if ((uint32_t)addr & (~PAGE_MASK)) return false; + + user_region_t *r = (user_region_t*)malloc(sizeof(user_region_t)); + if (r == 0) return false; + + r->addr = addr; + r->size = PAGE_ALIGN_UP(size); + + if (r->addr >= (void*)K_HIGHHALF_ADDR || r->addr + r->size > (void*)K_HIGHHALF_ADDR || r->size == 0) { + free(r); + return false; + } + + ref_file(h); + + r->mode = mode; + r->file = h; + r->file_offset = offset; + + r->next = proc->regions; + proc->regions = r; + + return true; } bool mchmap(process_t *proc, void* addr, int mode) { - //TODO - return false; + user_region_t *r = find_user_region(proc, addr); + + if (r == 0) return false; + + r->mode = mode; + return true; } bool munmap(process_t *proc, void* addr) { - //TODO - return false; + user_region_t *r = find_user_region(proc, addr); + if (r == 0) return false; + + if (proc->regions == r) { + proc->regions = r->next; + } else { + for (user_region_t *it = proc->regions; it != 0; it = it->next) { + if (it->next == r) { + it->next = r->next; + break; + } + } + } + + free(r); + + return true; } // =============================== // // USER MEMORY PAGE FAULT HANDLERS // // =============================== // -static void proc_kmem_violation(registers_t *regs) { - //TODO - dbg_printf("Kernel memory violation in user process : exiting.\n"); +static void proc_user_exception(registers_t *regs) { + dbg_printf("Usermode exception in user process : exiting.\n"); + dbg_dump_registers(regs); exit(); } -static void proc_user_pf(void* proc, registers_t *regs, void* addr) { - //TODO - PANIC("TODO"); +static void proc_usermem_pf(void* p, registers_t *regs, void* addr) { + process_t *proc = (process_t*)p; + + user_region_t *r = find_user_region(proc, addr); + if (r == 0) { + dbg_printf("Segmentation fault in process %d (0x%p : not mapped) : exiting.\n", proc->pid, addr); + exit(); + } + + bool wr = ((regs->err_code & PF_WRITE_BIT) != 0); + if (wr && !(r->mode & MM_WRITE)) { + dbg_printf("Segmentation fault in process %d (0x%p : not allowed to write) : exiting.\n", proc->pid, addr); + exit(); + } + + bool pr = ((regs->err_code & PF_PRESENT_BIT) != 0); + ASSERT(!pr); + + addr = (void*)((uint32_t)addr & PAGE_MASK); + + uint32_t frame; + do { + frame = frame_alloc(1); + if (frame == 0) { + dbg_printf("OOM for process %d ; yielding and waiting for someone to free some RAM.\n", proc->pid); + yield(); + } + } while (frame == 0); + + while(!pd_map_page(addr, frame, (r->mode & MM_WRITE) != 0)) { + dbg_printf("OOM(2) for process %d ; yielding and waiting for someone to free some RAM.\n", proc->pid); + yield(); + } + + memset(addr, 0, PAGE_SIZE); // zero out + + if (r->file != 0) { + file_read(r->file, addr - r->addr + r->file_offset, PAGE_SIZE, addr); + } } /* vim: set ts=4 sw=4 tw=0 noet :*/ |