diff options
Diffstat (limited to 'kc')
| -rw-r--r-- | kc/core/Makefile | 2 | ||||
| -rw-r--r-- | kc/core/arch_thread.c | 84 | ||||
| -rw-r--r-- | kc/core/arch_thread.h | 12 | ||||
| -rw-r--r-- | kc/core/cpu/cpu_thread.S | 57 | ||||
| -rw-r--r-- | kc/core/task.c | 122 | ||||
| -rw-r--r-- | kc/core/task.h | 26 |
6 files changed, 210 insertions, 93 deletions
diff --git a/kc/core/Makefile b/kc/core/Makefile index f56fc7c..4b31853 100644 --- a/kc/core/Makefile +++ b/kc/core/Makefile @@ -10,7 +10,7 @@ CPPFLAGS += -I../../api -I../api -I../../lib -I. CFLAGS += -mcmodel=small -Wno-unused-const-variable -Wno-unused-function -fvisibility=hidden -g AOBJS := entry_x86_64.o reloc_x86_64.o dynamic_x86_64.o -COBJS := mmu.o cpu_task.o irq.o exceptions.o cpu.o msr.o mmu.o port.o +COBJS := mmu.o cpu_task.o cpu_thread.o irq.o exceptions.o cpu.o msr.o mmu.o port.o arch_thread.o POBJS := pic8259.o pic8259_isr.o pit8253.o i8042.o GOBJS := serial.o kc_main.o memory.o vm_tree.o panic.o task.o \ kcc_memory.o page_early.o page_stack.o video.o diff --git a/kc/core/arch_thread.c b/kc/core/arch_thread.c new file mode 100644 index 0000000..8f5f8d3 --- /dev/null +++ b/kc/core/arch_thread.c @@ -0,0 +1,84 @@ +#include <stdint.h> +#include <stddef.h> +#include <stdnoreturn.h> +#include "task.h" +#include <lib/kstdio.h> + +struct arch_register_context +{ + uint64_t + r15, + r14, + r13, + r12, + r11, + r10, + r9, + r8, + rsi, + rdi, + rdx, + rcx, + rbx, + rax, + rbp, + rsp; +}; + +extern uint64_t *get_tss_rsp0(void); + +struct arch_thread_context +{ + struct arch_register_context register_context; + void *return_address; +}; + +extern void arch_swap_thread_stack( + void * volatile *outgoing_stack, + void *incoming_stack); + +extern void arch_begin_thread( + void *(func)(void *), + void *params); + +void arch_create_thread( + struct kc_thread *thread, + void *(*func)(void *), + void *params) +{ + uintptr_t stack_pointer = (uintptr_t)thread->kernel_stack_pointer; + struct arch_thread_context *context = (struct arch_thread_context *) + (stack_pointer -= sizeof(*context)); + thread->kernel_stack_pointer = (void *)stack_pointer; + + context->return_address = (void *)arch_begin_thread; + context->register_context.rdi = (uint64_t)func; + context->register_context.rsi = (uint64_t)params; + context->register_context.rdx = (uint64_t)thread; + context->register_context.rsp = (uint64_t)&context->return_address; +} + +void arch_swap_thread( + struct kc_thread *outgoing, + struct kc_thread *incoming) +{ + kprintf("swapping thread...\n"); + kprintf("stack pointer %p\n", incoming->kernel_stack_pointer); + arch_swap_thread_stack(&outgoing->kernel_stack_pointer, incoming->kernel_stack_pointer); +} + +void *arch_idle_loop(void *) +{ + for (;;) __asm__ ("hlt"); + return nullptr; +} + +noreturn void arch_terminate_thread(void *result, struct kc_thread *thread) +{ + thread->result = (union kc_thread_result){ .pointer = result }; + thread->status = TERMINATED; + thread->kernel_stack_pointer = thread->kernel_stack_head; + task_schedule(); + for (;;) __asm__ ("hlt"); +} + diff --git a/kc/core/arch_thread.h b/kc/core/arch_thread.h new file mode 100644 index 0000000..2b8d0fb --- /dev/null +++ b/kc/core/arch_thread.h @@ -0,0 +1,12 @@ +#pragma once + +void * arch_idle_loop(void *); + +void arch_create_thread( + struct kc_thread *thread, + void *(kc_thread_func)(void *), + void *params); + +void arch_swap_thread( + struct kc_thread *outgoing, + struct kc_thread *incoming); diff --git a/kc/core/cpu/cpu_thread.S b/kc/core/cpu/cpu_thread.S new file mode 100644 index 0000000..c4d04e1 --- /dev/null +++ b/kc/core/cpu/cpu_thread.S @@ -0,0 +1,57 @@ +.section .text + +.extern arch_terminate_thread + +.global arch_begin_thread +arch_begin_thread: + movq %rdi, %rax + movq %rsi, %rdi + pushq %rdx + pushq %rbp + movq %rsp, %rbp + andq $-16, %rsp + callq *%rax + movq %rax, %rdi + movq 8(%rbp), %rsi + callq arch_terminate_thread + +.global arch_swap_thread_stack +arch_swap_thread_stack: + pushq %rsp + pushq %rbp + pushq %rax + pushq %rbx + pushq %rcx + pushq %rdx + pushq %rdi + pushq %rsi + pushq %r8 + pushq %r9 + pushq %r10 + pushq %r11 + pushq %r12 + pushq %r13 + pushq %r14 + pushq %r15 + movq %rsp, (%rdi) + .Lenter_thread: + movq %rsi, %rsp + popq %r15 + popq %r14 + popq %r13 + popq %r12 + popq %r11 + popq %r10 + popq %r9 + popq %r8 + popq %rsi + popq %rdi + popq %rdx + popq %rcx + popq %rbx + popq %rax + popq %rbp + popq %rsp + retq + + diff --git a/kc/core/task.c b/kc/core/task.c index 3e0288d..aa5d179 100644 --- a/kc/core/task.c +++ b/kc/core/task.c @@ -14,9 +14,7 @@ #include <lib/elf.h> #include <lib/kstdio.h> -static const size_t INTERRUPT_STACK_SIZE = 4096; -static const size_t THREAD_SIZE = 16834; -static const enum vm_alloc_flags ALLOC_FLAGS = VM_ALLOC_ANY|VM_ALLOC_ANONYMOUS; +#include "arch_thread.h" extern uint64_t *get_tss_rsp0(void); @@ -27,7 +25,7 @@ static void unlock_preempt(void); static void update_time(void); -static struct kc_thread *create_thread(void (*thread_entry)(void)); +static struct kc_thread *create_thread(void *(*thread_f)(void *), void *p); static void destroy_thread(struct kc_thread *thread); static void set_thread(struct kc_thread *thread); static void block_thread(enum kc_thread_status reason); @@ -57,24 +55,26 @@ static struct kc_thread *sleeping_threads; static volatile atomic_uint_fast64_t preempt_switch_count = 0; static volatile atomic_bool preempt_switch_flag = false; -static void idle_thread_entry(void) +static void *idle_thread_entry(void *) { kprintf("idle thread started\n"); - unlock_scheduler(); - - __asm__ ("sti"); + __asm__ ("sti"); + + while (true) { __asm__ ("hlt;"); } + + return nullptr; } #define PS2INPUT 0x60 #define PS2STATUS 0x64 #define PS2STATUS_IBF 0x1 -static void keyboard_input_loop(void) +static void keyboard_input_loop() { bool has_bytes = true; while (has_bytes) @@ -91,7 +91,7 @@ static void keyboard_input_loop(void) } } -static void sleepy_thread_entry(void) +static void *sleepy_thread_entry(void *) { int thread_slept_count = 0; @@ -99,22 +99,21 @@ static void sleepy_thread_entry(void) { sleep_thread(1000000000); thread_slept_count++; - //keyboard_input_loop(); + keyboard_input_loop(); } (void)thread_slept_count; + return nullptr; } -static void create_interrupt_stack(size_t size) -{ - char *rsp0 = vm_alloc(size, ALLOC_FLAGS); - memset(rsp0, 0, size); - *get_tss_rsp0() = (uintptr_t)rsp0 + size; -} +static uint64_t scheduler_flags; noreturn void task_init(void) { - lock_scheduler(); + struct kc_thread boot_thread; + boot_thread.status = RUNNING; + current_thread = &boot_thread; + timesource = &pit8253_timer_source; timesource->append_callback(sleeping_thread_callback); timesource->start(); @@ -122,21 +121,14 @@ noreturn void task_init(void) "starting task management, timesource delta %luns\n", timesource->nanoseconds_delta()); - // XXX: unfuck this mess at some point - // XXX: make this also not demand-allocated or it's gonna fail - create_interrupt_stack(INTERRUPT_STACK_SIZE); - - // initalize static threads - idle_thread = create_thread(idle_thread_entry); - struct kc_thread *sleepy_thread = create_thread(sleepy_thread_entry); - - current_thread = idle_thread; - ready_thread_push_back(sleepy_thread); - - idle_thread->status = RUNNING; - cpu_set_thread(&idle_thread->state, NULL, get_tss_rsp0()); - + idle_thread = create_thread(idle_thread_entry, nullptr); + struct kc_thread *sleepy_thread = create_thread(sleepy_thread_entry, nullptr); + ready_thread_push(sleepy_thread); + __asm__ volatile ("movq %%rsp, %0" : "=g"(boot_thread.kernel_stack_pointer) :); + ready_thread_push(idle_thread); + block_thread(BLOCKED); // shouldn't ever get here + kprintf("the idle thread exited somehow. we're back in the boot thread. this is not good.\n"); PANIC(DEAD_END); } @@ -173,7 +165,6 @@ void task_schedule(void) } } -static uint64_t scheduler_flags; static void lock_scheduler(void) { @@ -220,42 +211,21 @@ void update_time(void) } } -static struct kc_thread *create_thread(void (*thread_f)(void)) -{ - char *task_bottom = vm_alloc(16384, ALLOC_FLAGS); - struct kc_thread *thread = - (struct kc_thread *)(task_bottom + 16384 - sizeof(*thread)); - - thread->next = NULL; - - thread->time_elapsed = 0; - thread->sleep_expiration = 0; - - thread->state.stack = (uintptr_t)thread; - thread->state.stack_top = *get_tss_rsp0(); - thread->state.page_map = mmu_get_map(); +#define KC_THREAD_SIZE 0x3000 - // set up the expected stack values for the state - struct task_register_state - { - uint64_t rbp; - uint64_t r15; - uint64_t r14; - uint64_t r13; - uint64_t r12; - uint64_t rbx; - uint64_t rip; - } - *register_state = - (struct task_register_state *) - (thread->state.stack -= sizeof(*register_state)); +static struct kc_thread *create_thread(void *(*thread_f)(void *), void *p) +{ + void *buffer = vm_alloc(KC_THREAD_SIZE, VM_ALLOC_ANONYMOUS|VM_ALLOC_ANY); + memset(buffer, 0, KC_THREAD_SIZE); - memset(register_state, 0, sizeof(*register_state)); + uintptr_t stack_head = (uintptr_t)buffer + KC_THREAD_SIZE; + struct kc_thread *thread = (struct kc_thread *)(stack_head -= sizeof(*thread)); - register_state->rip = (uint64_t)thread_f; - register_state->rbp = thread->state.stack; + thread->kernel_stack_head = (void *)stack_head; + thread->kernel_stack_pointer = (void *)stack_head; + thread->status = READY; - thread->status = READY; + arch_create_thread(thread, thread_f, p); return thread; } @@ -282,12 +252,9 @@ static void set_thread(struct kc_thread *thread) ready_thread_push(previous_thread); } - cpu_set_thread( - ¤t_thread->state, - &previous_thread->state, - get_tss_rsp0()); - current_thread->status = RUNNING; + arch_swap_thread(previous_thread, current_thread); + } static void block_thread(enum kc_thread_status reason) @@ -332,8 +299,8 @@ static void sleep_thread_until(uint64_t nanoseconds) return; } -// kprintf("time elapsed is now %ld\r\n", timesource->nanoseconds_elapsed()); -// kprintf("thread will now sleep until %ld\r\n", nanoseconds); + //kprintf("time elapsed is now %ld\r\n", timesource->nanoseconds_elapsed()); + //kprintf("thread will now sleep until %ld\r\n", nanoseconds); current_thread->sleep_expiration = nanoseconds; current_thread->next = sleeping_threads; sleeping_threads = current_thread; @@ -398,7 +365,7 @@ static int sleeping_thread_callback(uint64_t nanoseconds) if (this_thread->sleep_expiration <= nanoseconds) { - //kprintf("thread awakened: %p\n", this_thread); + kprintf("thread awakened: %p\n", this_thread); this_thread->sleep_expiration = 0; unblock_thread(this_thread); } @@ -409,11 +376,10 @@ static int sleeping_thread_callback(uint64_t nanoseconds) } } - unlock_preempt(); - - lock_scheduler(); - task_schedule(); - unlock_scheduler(); + unlock_preempt(); + lock_scheduler(); + task_schedule(); + unlock_scheduler(); return 0; } diff --git a/kc/core/task.h b/kc/core/task.h index bea4756..e5e9d92 100644 --- a/kc/core/task.h +++ b/kc/core/task.h @@ -4,6 +4,8 @@ enum kc_thread_status { + AVAILABLE, + CREATED, READY, RUNNING, SLEEPING, @@ -11,27 +13,23 @@ enum kc_thread_status TERMINATED }; -struct kc_thread_state +union kc_thread_result { - uint64_t stack; - uint64_t stack_top; - uint64_t page_map; + uint64_t scalar; + void *pointer; }; struct kc_thread { - struct kc_thread *next; - uint64_t time_elapsed; - uint64_t sleep_expiration; - enum kc_thread_status status; - struct kc_thread_state state; + void *kernel_stack_head; + void *kernel_stack_pointer; + uint64_t time_elapsed; + union kc_thread_result result; + enum kc_thread_status status; + struct kc_thread *next; + uint64_t sleep_expiration; }; -extern void cpu_set_thread( - struct kc_thread_state *current, - struct kc_thread_state *next, - uint64_t *cpu_tss_rsp0); - void task_init(void); void task_schedule(void); |
