diff --git a/kernel/boot/kmain.c b/kernel/boot/kmain.c index c31875f..68556b3 100644 --- a/kernel/boot/kmain.c +++ b/kernel/boot/kmain.c @@ -6,12 +6,14 @@ #include #include #include +#include void thread_function() { + int i = 0; while(1) { - ; + i++; } } @@ -30,10 +32,18 @@ int kmain(uint64_t multiboot_magic, void *multiboot_data) pit_init(); process_t *p1 = process_spawn(0); - thread_t *t1 = new_thread(thread_function); - process_attach(p1, t1); + uint64_t addr = 0x200000; + thread_t *th = new_thread((void *)addr, 1); - scheduler_insert(t1); + 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); + + process_attach(p1, th); + scheduler_insert(th); asm("sti"); debug_info("BOOT COMPLETE\n"); diff --git a/kernel/include/int.h b/kernel/include/int.h index f342362..36c65a0 100644 --- a/kernel/include/int.h +++ b/kernel/include/int.h @@ -66,6 +66,14 @@ #define INT_APIC_ERROR 0x45 #define INT_APIC_SPUR 0xFF + +#define RFLAGS_IOPL (3<<12) +#define RFLAGS_IOPL1 (1<<12) +#define RFLAGS_IOPL2 (2<<12) +#define RFLAGS_IOPL3 (3<<12) +#define RFLAGS_INT (1<<9) +#define REG_OFFSET_RFLAGS 152 + #ifndef __ASSEMBLER__ #include #include @@ -116,13 +124,13 @@ typedef struct registers_st uint64_t r14; uint64_t r15; - uint64_t int_no; - uint64_t err_code; - uint64_t rip; - uint64_t cs; - uint64_t rflags; - uint64_t rsp; - uint64_t ss; + uint64_t int_no; //120 + uint64_t err_code; //128 + uint64_t rip; //136 + uint64_t cs; //144 + uint64_t rflags; //152 + uint64_t rsp; //160 + uint64_t ss; //168 }registers_t; typedef registers_t *(*int_handler_t)(registers_t *); diff --git a/kernel/include/mem.h b/kernel/include/mem.h index 7ca2084..da8fbf6 100644 --- a/kernel/include/mem.h +++ b/kernel/include/mem.h @@ -1,5 +1,6 @@ #pragma once +#define USERSPACE_TOP 0x0000800000000000 #define KERNEL_OFFSET 0xFFFFFF8000000000 #define KERNEL_HEAP_S 0xFFFFFFC000000000 diff --git a/kernel/include/thread.h b/kernel/include/thread.h index db8f593..f1451ad 100644 --- a/kernel/include/thread.h +++ b/kernel/include/thread.h @@ -44,7 +44,7 @@ typedef struct thread_stack_st #define get_current_thread() (get_cpu()->current_thread) #define set_current_thread(new) (get_cpu()->current_thread = (new)) -thread_t *new_thread(void (*func)(void)); +thread_t *new_thread(void (*func)(void), int user); void switch_thread(thread_t *old, thread_t *new); void free_thread(thread_t *th); diff --git a/kernel/interrupts/isr_common.S b/kernel/interrupts/isr_common.S index 9a2d1fa..6817713 100644 --- a/kernel/interrupts/isr_common.S +++ b/kernel/interrupts/isr_common.S @@ -1,3 +1,4 @@ +#include .intel_syntax noprefix .extern int_handler @@ -21,13 +22,33 @@ isr_common: push rcx push rbx push rax + + # Clear RFLAGS + pushq 0 + popf + + # Check stored RFLAGS to see if we came here from user mode + mov rax, [rsp + REG_OFFSET_RFLAGS] + and rax, RFLAGS_IOPL + jz .kernel_mode + swapgs + +.kernel_mode: mov rdi, rsp call int_handler mov rdi, rax isr_return: - // Return and restore stack mov rsp, rdi + + # Check stored RFLAGS to see if we are going into user mode + mov rax, [rsp + REG_OFFSET_RFLAGS] + and rax, RFLAGS_IOPL + jz .kernel_return + swapgs + +.kernel_return: + // Return and restore stack pop rax pop rbx pop rcx diff --git a/kernel/proc/scheduler.c b/kernel/proc/scheduler.c index f404316..5f6388a 100644 --- a/kernel/proc/scheduler.c +++ b/kernel/proc/scheduler.c @@ -105,5 +105,5 @@ void scheduler_init() LIST_HEAD_INIT(ready_queue); scheduler_started = 1; } - get_cpu()->scheduler = new_thread(scheduler); + get_cpu()->scheduler = new_thread(scheduler, 0); } diff --git a/kernel/proc/thread.c b/kernel/proc/thread.c index 0fe1635..37256a6 100644 --- a/kernel/proc/thread.c +++ b/kernel/proc/thread.c @@ -8,21 +8,30 @@ uint64_t tid = 1; -thread_t *new_thread(void (*func)(void)) +thread_t *new_thread(void (*func)(void), int user) { // Set up original stack of thread thread_stack_t *stack = kcalloc(1, sizeof(thread_stack_t)); thread_t *th = &stack->tcb; stack->thread = (uint64_t)th; - stack->function_address = (uint64_t)isr_return; stack->RBP = (uint64_t)&stack->zero_frame; - th->r.rip = (uint64_t)func; th->r.rflags = RFLAGS_IF; - th->r.cs = 0x8; - th->r.ss = 0x10; - th->r.rsp = (uint64_t)&th->stack_pointer; + if(user) + { + stack->function_address = (uint64_t)isr_return; + th->r.rip = (uint64_t)func; + th->r.cs = SEG_UCODE|3; + th->r.ss = SEG_UDATA|3; + th->r.rflags |= RFLAGS_IOPL3; + th->r.rsp = USERSPACE_TOP; + } else { + stack->function_address = (uint64_t)func; + th->r.cs = SEG_KCODE; + th->r.ss = SEG_KDATA; + th->r.rsp = (uint64_t)&th->stack_pointer; + } th->tid = tid++; th->state = THREAD_STATE_READY; @@ -37,6 +46,8 @@ thread_t *new_thread(void (*func)(void)) void switch_thread(thread_t *old, thread_t *new) { set_current_thread(new); + get_cpu()->tss.rsp0 = (uint64_t)&new->stack_pointer; + get_cpu()->kernel_stack = &new->stack_pointer; uint64_t *old_stack = (old)?&old->stack_pointer:0; swtch(old_stack, &new->stack_pointer);