summaryrefslogtreecommitdiff
path: root/kc/core
diff options
context:
space:
mode:
Diffstat (limited to 'kc/core')
-rw-r--r--kc/core/Makefile2
-rw-r--r--kc/core/arch_thread.c84
-rw-r--r--kc/core/arch_thread.h12
-rw-r--r--kc/core/cpu/cpu_thread.S57
-rw-r--r--kc/core/task.c122
-rw-r--r--kc/core/task.h26
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(
- &current_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);