diff --git a/kernel/arch/core_ring.cc b/kernel/arch/core_ring.cc index 99b141b..fb4a9b5 100644 --- a/kernel/arch/core_ring.cc +++ b/kernel/arch/core_ring.cc @@ -11,6 +11,30 @@ void switchToUsermode(void *stackpointer, void *kickoff, (void)stackpointer; (void)kickoff; (void)kickoff_parameter; + + // Segment Selectors for Ring 3 + constexpr uint16_t user_cs = 3 << 3 | 3; + constexpr uint16_t user_ds = 4 << 3 | 3; + + asm volatile ( \ + "pushq %[user_data] \n" \ + "pushq %[user_stack] \n" \ + "pushq %[user_eflags] \n" \ + "pushq %[user_code] \n" \ + "pushq %[user_function] \n" \ + "mov %[user_parameter], %%rdi\n" \ + "iretq \n" \ + : \ + : [user_data] "r"((uint64_t)user_ds), + [user_code] "r"((uint64_t)user_cs), + [user_stack] "r"((uint64_t)stackpointer), + [user_eflags] "r"((uint64_t)1<<9 | 2), // Interrupt Enable Flag + [user_function] "r"((uint64_t)kickoff), + [user_parameter] "r"((uint64_t)kickoff_parameter) + \ + : "memory", "rdi"\ + ); + __builtin_unreachable(); } } // namespace Ring diff --git a/kernel/thread/thread.cc b/kernel/thread/thread.cc index b9a56fb..23a352b 100644 --- a/kernel/thread/thread.cc +++ b/kernel/thread/thread.cc @@ -1,6 +1,7 @@ // vim: set noet ts=4 sw=4: #include "thread.h" +#include "../arch/core_ring.h" #include "../debug/kernelpanic.h" #include "../interrupt/guard.h" @@ -17,11 +18,26 @@ void Thread::kickoff(uintptr_t param1, uintptr_t param2, uintptr_t param3) { // The core must have entered level 1/2 to cause a thread to be scheduled. Guard::leave(); - thread->action(); + if(!thread->isKernel) + Core::Ring::switchToUsermode(thread->StackPointer.user, reinterpret_cast(kickoffUsermode), thread); + else + if(thread->start == nullptr) + thread->action(); + else + ((void(*)())thread->start)(); + } void Thread::kickoffUsermode (Thread *object){ - (void) object; + if(object->start == nullptr) + object->action(); + else + ((void(*)())object->start)(); +} + +Thread::Thread (bool kernel, void * start): queue_link(nullptr), isKernel(kernel), start(start), id(idCounter++), kill_flag(false){ + void *tos = reinterpret_cast(reserved_stack_space_isr + STACK_SIZE); + prepareContext(tos, context, kickoff, reinterpret_cast(this), 0, 0); } Thread::Thread() : queue_link(nullptr), id(idCounter++), kill_flag(false) { diff --git a/kernel/thread/thread.h b/kernel/thread/thread.h index 8b3e465..7cfa557 100644 --- a/kernel/thread/thread.h +++ b/kernel/thread/thread.h @@ -28,12 +28,15 @@ class Thread { /*! \brief pointer to the next element of the readylist */ Thread* queue_link; + bool isKernel; + void* start; friend class Queue; friend class Semaphore; /*! \brief Memory reserved for this threads stack */ - alignas(16) char reserved_stack_space[STACK_SIZE]; + alignas(16) char reserved_stack_space_user[STACK_SIZE]; + alignas(16) char reserved_stack_space_isr[STACK_SIZE]; struct{ void* user; @@ -80,6 +83,7 @@ class Thread { * */ explicit Thread(); + explicit Thread(bool kernel, void * start = nullptr); /*! \brief Activates the first thread on this CPU. *