aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Auvolat <alex.auvolat@ens.fr>2015-02-13 18:53:36 +0100
committerAlex Auvolat <alex.auvolat@ens.fr>2015-02-13 18:53:36 +0100
commit0ea68568372b7b7b20bca6985ae4b36e8c99c0e9 (patch)
tree832f7f4ac8e2537cf5aee531634d01499bb4a318
parent7aafc22a01de5cabb99aed76782f6c0999b7de05 (diff)
downloadkogata-0ea68568372b7b7b20bca6985ae4b36e8c99c0e9.tar.gz
kogata-0ea68568372b7b7b20bca6985ae4b36e8c99c0e9.zip
Implement switching to usermode.
-rw-r--r--src/kernel/core/gdt.c23
-rw-r--r--src/kernel/core/thread.c3
-rw-r--r--src/kernel/include/gdt.h2
-rw-r--r--src/kernel/include/process.h3
-rw-r--r--src/kernel/user/process.c46
-rw-r--r--src/rules.make2
6 files changed, 72 insertions, 7 deletions
diff --git a/src/kernel/core/gdt.c b/src/kernel/core/gdt.c
index eadde5f..97e6661 100644
--- a/src/kernel/core/gdt.c
+++ b/src/kernel/core/gdt.c
@@ -60,6 +60,7 @@ typedef struct tss_entry tss_entry_t;
static gdt_entry_t gdt_entries[GDT_ENTRIES];
static gdt_ptr_t gdt_ptr;
+static tss_entry_t tss_entry;
/* For internal use only. Writes one entry of the GDT with given parameters. */
static void gdt_set_gate(int num, uint32_t base, uint32_t limit, uint8_t access, uint8_t gran) {
@@ -84,7 +85,27 @@ void gdt_init() {
gdt_set_gate(3, 0, 0xFFFFFFFF, 0xFA, 0xCF); //User code segment 0x18
gdt_set_gate(4, 0, 0xFFFFFFFF, 0xF2, 0xCF); //User data segment 0x20
- asm volatile ("lgdt %0"::"m"(gdt_ptr):"memory");
+ // Write TSS
+ memset(&tss_entry, 0, sizeof(tss_entry));
+
+ tss_entry.ss0 = 0x10;
+ tss_entry.esp0 = 0;
+
+ tss_entry.cs = 0x0b;
+ tss_entry.ss = tss_entry.ds = tss_entry.es = tss_entry.fs = tss_entry.gs = 0x13;
+
+ uint32_t tss_base = (uint32_t)&tss_entry;
+ uint32_t tss_limit = tss_base + sizeof(tss_entry_t);
+
+ gdt_set_gate(5, tss_base, tss_limit, 0xE9, 0x00);
+
+ asm volatile("lgdt %0"::"m"(gdt_ptr):"memory");
+
+ asm volatile("movw $0x2b, %%ax; ltr %%ax":::"%eax");
+}
+
+void set_kernel_stack(void* addr) {
+ tss_entry.esp0 = (uint32_t)addr;
}
/* vim: set ts=4 sw=4 tw=0 noet :*/
diff --git a/src/kernel/core/thread.c b/src/kernel/core/thread.c
index 9d11da2..519ba41 100644
--- a/src/kernel/core/thread.c
+++ b/src/kernel/core/thread.c
@@ -2,6 +2,7 @@
#include <malloc.h>
#include <dbglog.h>
#include <idt.h>
+#include <gdt.h>
#include <frame.h>
#include <paging.h>
@@ -88,6 +89,7 @@ void run_scheduler() {
current_thread = dequeue_thread();
if (current_thread != 0) {
+ set_kernel_stack(current_thread->stack_region->addr + current_thread->stack_region->size);
resume_context(&current_thread->ctx);
} else {
// Wait for an IRQ
@@ -146,7 +148,6 @@ thread_t *new_thread(entry_t entry, void* data) {
// used by user processes
t->proc = 0;
- t->usermem_pf_handler = 0;
t->kmem_violation_handler = 0;
return t;
diff --git a/src/kernel/include/gdt.h b/src/kernel/include/gdt.h
index a62d0db..048accd 100644
--- a/src/kernel/include/gdt.h
+++ b/src/kernel/include/gdt.h
@@ -9,6 +9,8 @@
void gdt_init();
+void set_kernel_stack(void* addr);
+
#define K_CODE_SEGMENT 0x08
#define K_DATA_SEGMENT 0x10
#define U_CODE_SEGMENT 0x18
diff --git a/src/kernel/include/process.h b/src/kernel/include/process.h
index 30e24db..d67ede6 100644
--- a/src/kernel/include/process.h
+++ b/src/kernel/include/process.h
@@ -21,6 +21,9 @@
#define MM_WRITE (0x02)
#define MM_EXEC (0x04)
+#define USERSTACK_ADDR 0xB8000000
+#define USERSTACK_SIZE 0x00020000 // 32 KB
+
struct process;
typedef struct process process_t;
diff --git a/src/kernel/user/process.c b/src/kernel/user/process.c
index 7b51370..9f3e2b1 100644
--- a/src/kernel/user/process.c
+++ b/src/kernel/user/process.c
@@ -66,12 +66,50 @@ process_t *new_process(process_t *parent) {
return proc;
}
-static void run_user_code(void* data) {
- // TODO
- exit();
+static void run_user_code(void* entry) {
+ process_t *proc = current_thread->proc;
+ ASSERT(proc != 0);
+
+ switch_pagedir(proc->pd);
+
+ 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
+ "::"b"(esp),"c"(entry));
}
bool start_process(process_t *p, void* entry) {
- // TODO
+ bool stack_ok = mmap(p, (void*)USERSTACK_ADDR, USERSTACK_SIZE, MM_READ | MM_WRITE);
+ if (!stack_ok) return false;
+
+ thread_t *th = new_thread(run_user_code, entry);
+ if (th == 0) {
+ munmap(p, (void*)USERSTACK_ADDR);
+ return false;
+ }
+
+ th->proc = p;
+ th->kmem_violation_handler = proc_kmem_violation;
+
+ resume_thread(th, false);
+
+ return true;
}
// ================================== //
diff --git a/src/rules.make b/src/rules.make
index acd1c62..6c02313 100644
--- a/src/rules.make
+++ b/src/rules.make
@@ -28,7 +28,7 @@ all: $(OUT)
# $(CXX) -c $< -o $@ $(CXFLAGS)
clean:
- rm */*.o || true
+ rm *.o */*.o || true
mrproper: clean
rm $(OUT) || true