aboutsummaryrefslogtreecommitdiff
path: root/src/kernel/core/gdt.c
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 /src/kernel/core/gdt.c
parent7aafc22a01de5cabb99aed76782f6c0999b7de05 (diff)
downloadkogata-0ea68568372b7b7b20bca6985ae4b36e8c99c0e9.tar.gz
kogata-0ea68568372b7b7b20bca6985ae4b36e8c99c0e9.zip
Implement switching to usermode.
Diffstat (limited to 'src/kernel/core/gdt.c')
-rw-r--r--src/kernel/core/gdt.c23
1 files changed, 22 insertions, 1 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 :*/