From a33a72915e9fe0e198618a40efae5b32380072ea Mon Sep 17 00:00:00 2001 From: apio Date: Thu, 5 Jan 2023 21:52:26 +0100 Subject: [PATCH] Scheduler: Creation, destruction and switching of userspace tasks :)) From a TarStream. Not optimal, but OK for the moment. --- kernel/src/thread/Scheduler.cpp | 93 +++++++++++++++++++++++++++++++-- kernel/src/thread/Scheduler.h | 3 ++ 2 files changed, 91 insertions(+), 5 deletions(-) diff --git a/kernel/src/thread/Scheduler.cpp b/kernel/src/thread/Scheduler.cpp index 8b498cd0..11b8366a 100644 --- a/kernel/src/thread/Scheduler.cpp +++ b/kernel/src/thread/Scheduler.cpp @@ -1,4 +1,5 @@ #include "thread/Scheduler.h" +#include "ELF.h" #include "Log.h" #include "arch/CPU.h" #include "arch/MMU.h" @@ -19,6 +20,7 @@ namespace Scheduler g_idle.init_regs_kernel(); g_idle.set_ip((u64)CPU::idle_loop); g_idle.state = ThreadState::Idle; + g_idle.is_kernel = true; g_idle.ticks_left = 1; @@ -60,6 +62,8 @@ namespace Scheduler thread->stack = thread_stack; + thread->is_kernel = true; + g_threads.append(thread); kinfoln("CREATED THREAD: id %lu with ip %lx and sp %lx", thread->id, thread->ip(), thread->sp()); @@ -95,13 +99,84 @@ namespace Scheduler return new_kernel_thread_impl(thread); } + static Result create_stacks(Stack& user_stack, Stack& kernel_stack) + { + const u64 THREAD_STACK_BASE = 0x10000; + + TRY(MemoryManager::alloc_at(THREAD_STACK_BASE, 4, MMU::ReadWrite | MMU::NoExecute | MMU::User)); + + auto guard = make_scope_guard([&] { MemoryManager::unmap_owned(THREAD_STACK_BASE, 4); }); + + u64 kernel_stack_base = TRY(MemoryManager::alloc_for_kernel(4, MMU::ReadWrite | MMU::NoExecute)); + + guard.deactivate(); + + user_stack = { THREAD_STACK_BASE, 4 * ARCH_PAGE_SIZE }; + kernel_stack = { kernel_stack_base, 4 * ARCH_PAGE_SIZE }; + + return {}; + } + + Result new_userspace_thread(const TarStream::Entry& entry, const TarStream& stream) + { + Thread* thread = TRY(new_thread()); + + thread->is_kernel = false; + + auto guard = make_scope_guard([&] { delete thread; }); + + auto directory = TRY(MMU::create_page_directory_for_userspace()); + + auto directory_guard = make_scope_guard([&] { + MMU::switch_page_directory(MMU::kernel_page_directory()); + MemoryManager::free_frame((u64)directory); + }); + + MMU::switch_page_directory(directory); + + thread->init_regs_user(); + + auto data = TRY(ELFLoader::load(entry, stream)); + + thread->set_ip(data.entry); + + TRY(create_stacks(thread->stack, thread->kernel_stack)); + thread->set_sp(thread->stack.top()); + + thread->directory = directory; + + guard.deactivate(); + directory_guard.deactivate(); + + kinfoln("CREATED USERSPACE THREAD: id %lu with ip %lx and sp %lx (ksp %lx)", thread->id, thread->ip(), + thread->sp(), thread->kernel_stack.top()); + + g_threads.append(thread); + + return {}; + } + void reap_thread(Thread* thread) { kinfoln("reap: reaping thread with id %zu", thread->id); - auto stack = thread->stack; - kinfoln("deleting thread stack @ %#lx, has %zu bytes of stack", stack.bottom(), stack.bytes()); - // FIXME: Propagate errors I guess? - MemoryManager::unmap_owned_and_free_vm(stack.bottom(), stack.bytes() / ARCH_PAGE_SIZE).release_value(); + + if (thread->is_kernel) + { + auto stack = thread->stack; + // FIXME: Propagate errors I guess? + kinfoln("deleting stack @ %#lx", stack.bottom()); + MemoryManager::unmap_owned_and_free_vm(stack.bottom(), stack.bytes() / ARCH_PAGE_SIZE).release_value(); + } + else + { + auto stack = thread->kernel_stack; + kinfoln("deleting kstack @ %#lx", stack.bottom()); + // FIXME: Propagate errors I guess? + MemoryManager::unmap_owned_and_free_vm(stack.bottom(), stack.bytes() / ARCH_PAGE_SIZE).release_value(); + } + + if (!thread->is_kernel) MMU::delete_userspace_page_directory(thread->directory); + delete thread; } @@ -138,7 +213,15 @@ namespace Scheduler void generic_switch_context(Thread* old_thread, Thread* new_thread, Registers* regs) { - if (old_thread != new_thread) switch_context(old_thread, new_thread, regs); + if (old_thread != new_thread) + { + switch_context(old_thread, new_thread, regs); + if (!new_thread->is_kernel) + { + MMU::switch_page_directory(new_thread->directory); + CPU::switch_kernel_stack(new_thread->kernel_stack.top()); + } + } if (new_thread->is_idle()) { diff --git a/kernel/src/thread/Scheduler.h b/kernel/src/thread/Scheduler.h index f818c731..c2dd4cfc 100644 --- a/kernel/src/thread/Scheduler.h +++ b/kernel/src/thread/Scheduler.h @@ -1,5 +1,6 @@ #pragma once #include "thread/Thread.h" +#include namespace Scheduler { @@ -12,6 +13,8 @@ namespace Scheduler Result new_kernel_thread(void (*func)(void)); Result new_kernel_thread(void (*func)(void*), void* arg); + Result new_userspace_thread(const TarStream::Entry& entry, const TarStream& stream); + Thread* pick_task(); void reap_thread(Thread* thread);