aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/kernel/Makefile2
-rw-r--r--src/kernel/core/idt.c13
-rw-r--r--src/kernel/core/paging.c4
-rw-r--r--src/kernel/core/thread.c2
-rw-r--r--src/kernel/include/thread.h2
-rw-r--r--src/kernel/user/process.c182
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 :*/