diff options
Diffstat (limited to 'dev/Kernel/Sources/MP.cxx')
| -rw-r--r-- | dev/Kernel/Sources/MP.cxx | 256 |
1 files changed, 256 insertions, 0 deletions
diff --git a/dev/Kernel/Sources/MP.cxx b/dev/Kernel/Sources/MP.cxx new file mode 100644 index 00000000..bf35f51e --- /dev/null +++ b/dev/Kernel/Sources/MP.cxx @@ -0,0 +1,256 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies. + +------------------------------------------- */ + +#include <ArchKit/ArchKit.hxx> +#include <KernelKit/ProcessScheduler.hxx> +#include <KernelKit/MP.hxx> +#include <CFKit/Property.hxx> + +///! BUGS: 0 + +///! @file MP.cxx +///! @brief This file handles multi processing in the kernel. +///! @brief Multi processing is needed for multi-tasking operations. + +namespace Kernel +{ + STATIC Property cSMPCoreName; + + ///! A HardwareThread class takes care of it's owned hardware thread. + ///! It has a stack for it's core. + + ///! @brief C++ constructor. + HardwareThread::HardwareThread() = default; + + ///! @brief C++ destructor. + HardwareThread::~HardwareThread() = default; + + //! @brief returns the id of the thread. + const ThreadID& HardwareThread::ID() noexcept + { + return fID; + } + + //! @brief returns the kind of thread we have. + const ThreadKind& HardwareThread::Kind() noexcept + { + return fKind; + } + + //! @brief is the thread busy? + Bool HardwareThread::IsBusy() noexcept + { + return fBusy; + } + + /// @brief Get processor stack frame. + + HAL::StackFramePtr HardwareThread::StackFrame() noexcept + { + MUST_PASS(fStack); + return fStack; + } + + Void HardwareThread::Busy(const Bool busy) noexcept + { + fBusy = busy; + } + + HardwareThread::operator bool() + { + return fStack; + } + + /// @brief Wakeup the processor. + + Void HardwareThread::Wake(const bool wakeup) noexcept + { + fWakeup = wakeup; + + if (!fWakeup) + mp_hang_thread(fStack); + else + mp_wakeup_thread(fStack); + } + + EXTERN Bool rt_check_stack(HAL::StackFramePtr stackPtr); + + /// @brief Switch to hardware thread. + /// @param stack the new hardware thread. + /// @retval true stack was changed, code is running. + /// @retval false stack is invalid, previous code is running. + Bool HardwareThread::Switch(HAL::StackFramePtr stack) + { + if (!rt_check_stack(stack)) + { + /// provide 'nullptr' to free the stack frame. + if (stack == nullptr) + { + delete fStack; + fStack = nullptr; + + return true; + } + + return false; + } + + if (fStack) + { + delete fStack; + fStack = nullptr; + } + + fStack = stack; + + rt_do_context_switch(fStack); + + return true; + } + + ///! @brief Tells if processor is waked up. + bool HardwareThread::IsWakeup() noexcept + { + return fWakeup; + } + + //! @brief Constructor and destructor + + ///! @brief Default constructor. + HardwareThreadScheduler::HardwareThreadScheduler() + { + StringView strCoreName(512); + strCoreName += "\\Class\\Smp\\MPClass"; + + cSMPCoreName.GetKey() = strCoreName; + cSMPCoreName.GetValue() = (UIntPtr)this; + + kcout << "newoskrnl: initializing " << strCoreName.CData() << endl; + } + + ///! @brief Default destructor. + HardwareThreadScheduler::~HardwareThreadScheduler() = default; + + /// @brief Shared singleton function + Ref<HardwareThreadScheduler> HardwareThreadScheduler::The() + { + static HardwareThreadScheduler manager; + return {manager}; + } + + /// @brief Get Stack Frame of Core + HAL::StackFramePtr HardwareThreadScheduler::Leak() noexcept + { + if (fThreadList[fCurrentThread].Leak() && + ProcessHelper::TheCurrentPID() == + fThreadList[fCurrentThread].Leak().Leak()->fSourcePID) + return fThreadList[fCurrentThread].Leak().Leak()->fStack; + + return nullptr; + } + + /// @brief Finds and switch to a free core. + bool HardwareThreadScheduler::Switch(HAL::StackFramePtr stack) + { + if (stack == nullptr) + return false; + + for (SizeT idx = 0; idx < cMaxHWThreads; ++idx) + { + // stack != nullptr -> if core is used, then continue. + if (!fThreadList[idx].Leak() || + !fThreadList[idx].Leak().Leak()->IsWakeup() || + fThreadList[idx].Leak().Leak()->IsBusy()) + continue; + + // to avoid any null deref. + if (!fThreadList[idx].Leak().Leak()->fStack) + continue; + if (fThreadList[idx].Leak().Leak()->fStack->SP == 0) + continue; + if (fThreadList[idx].Leak().Leak()->fStack->BP == 0) + continue; + + fThreadList[idx].Leak().Leak()->Busy(true); + + fThreadList[idx].Leak().Leak()->fID = idx; + + /// I figured out this: + /// Allocate stack + /// Set APIC base to stack + /// Do stuff and relocate stack based on this code. + /// - Amlel + rt_copy_memory(stack, fThreadList[idx].Leak().Leak()->fStack, + sizeof(HAL::StackFrame)); + + fThreadList[idx].Leak().Leak()->Switch(fThreadList[idx].Leak().Leak()->fStack); + + fThreadList[idx].Leak().Leak()->fSourcePID = ProcessHelper::TheCurrentPID(); + + fThreadList[idx].Leak().Leak()->Busy(false); + + return true; + } + + return false; + } + + /** + * Index Hardware thread + * @param idx the index + * @return the reference to the hardware thread. + */ + Ref<HardwareThread*> HardwareThreadScheduler::operator[](const SizeT& idx) + { + if (idx == 0) + { + if (fThreadList[idx].Leak().Leak()->Kind() != kHartSystemReserved) + { + fThreadList[idx].Leak().Leak()->fKind = kHartBoot; + } + } + else if (idx >= cMaxHWThreads) + { + static HardwareThread* fakeThread = new HardwareThread(); + + if (!fakeThread) + { + fakeThread = new HardwareThread(); + } + + fakeThread->fKind = kInvalidHart; + + return {fakeThread}; + } + + return fThreadList[idx].Leak(); + } + + /** + * Check if thread pool isn't empty. + * @return + */ + HardwareThreadScheduler::operator bool() noexcept + { + return !fThreadList.Empty(); + } + + /** + * Reverse operator bool + * @return + */ + bool HardwareThreadScheduler::operator!() noexcept + { + return fThreadList.Empty(); + } + + /// @brief Returns the amount of core present. + /// @return the number of cores. + SizeT HardwareThreadScheduler::Count() noexcept + { + return fThreadList.Count(); + } +} // namespace Kernel |
