summaryrefslogtreecommitdiffhomepage
path: root/dev/Kernel/Sources/MP.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'dev/Kernel/Sources/MP.cxx')
-rw-r--r--dev/Kernel/Sources/MP.cxx256
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