diff --git a/src/core/core_cpu.cpp b/src/core/core_cpu.cpp
index 54aa21a3ae1d5004a6582d9240be765f2658e23a..1eefed6d0749d90688fb56c8f23831400e765417 100644
--- a/src/core/core_cpu.cpp
+++ b/src/core/core_cpu.cpp
@@ -11,6 +11,7 @@
 #endif
 #include "core/arm/exclusive_monitor.h"
 #include "core/arm/unicorn/arm_unicorn.h"
+#include "core/core.h"
 #include "core/core_cpu.h"
 #include "core/core_timing.h"
 #include "core/hle/kernel/scheduler.h"
@@ -49,9 +50,9 @@ bool CpuBarrier::Rendezvous() {
     return false;
 }
 
-Cpu::Cpu(Timing::CoreTiming& core_timing, ExclusiveMonitor& exclusive_monitor,
-         CpuBarrier& cpu_barrier, std::size_t core_index)
-    : cpu_barrier{cpu_barrier}, core_timing{core_timing}, core_index{core_index} {
+Cpu::Cpu(System& system, ExclusiveMonitor& exclusive_monitor, CpuBarrier& cpu_barrier,
+         std::size_t core_index)
+    : cpu_barrier{cpu_barrier}, core_timing{system.CoreTiming()}, core_index{core_index} {
     if (Settings::values.use_cpu_jit) {
 #ifdef ARCHITECTURE_x86_64
         arm_interface = std::make_unique<ARM_Dynarmic>(core_timing, exclusive_monitor, core_index);
@@ -63,7 +64,7 @@ Cpu::Cpu(Timing::CoreTiming& core_timing, ExclusiveMonitor& exclusive_monitor,
         arm_interface = std::make_unique<ARM_Unicorn>(core_timing);
     }
 
-    scheduler = std::make_unique<Kernel::Scheduler>(*arm_interface);
+    scheduler = std::make_unique<Kernel::Scheduler>(system, *arm_interface);
 }
 
 Cpu::~Cpu() = default;
diff --git a/src/core/core_cpu.h b/src/core/core_cpu.h
index e2204c6b01154c90de4f09b6ac799dc1b4a703b2..7589beb8c8b2124648958a0f1c2127bc56f17447 100644
--- a/src/core/core_cpu.h
+++ b/src/core/core_cpu.h
@@ -15,6 +15,10 @@ namespace Kernel {
 class Scheduler;
 }
 
+namespace Core {
+class System;
+}
+
 namespace Core::Timing {
 class CoreTiming;
 }
@@ -45,8 +49,8 @@ private:
 
 class Cpu {
 public:
-    Cpu(Timing::CoreTiming& core_timing, ExclusiveMonitor& exclusive_monitor,
-        CpuBarrier& cpu_barrier, std::size_t core_index);
+    Cpu(System& system, ExclusiveMonitor& exclusive_monitor, CpuBarrier& cpu_barrier,
+        std::size_t core_index);
     ~Cpu();
 
     void RunLoop(bool tight_loop = true);
diff --git a/src/core/cpu_core_manager.cpp b/src/core/cpu_core_manager.cpp
index 2ddb3610d24cc7ae551a0f3172e219e8f3f4d2c6..93bc5619c8d30402076c5d82d05416552d10ec78 100644
--- a/src/core/cpu_core_manager.cpp
+++ b/src/core/cpu_core_manager.cpp
@@ -27,8 +27,7 @@ void CpuCoreManager::Initialize(System& system) {
     exclusive_monitor = Cpu::MakeExclusiveMonitor(cores.size());
 
     for (std::size_t index = 0; index < cores.size(); ++index) {
-        cores[index] =
-            std::make_unique<Cpu>(system.CoreTiming(), *exclusive_monitor, *barrier, index);
+        cores[index] = std::make_unique<Cpu>(system, *exclusive_monitor, *barrier, index);
     }
 
     // Create threads for CPU cores 1-3, and build thread_to_cpu map
diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp
index 44f30d07047dffc484dc435a204c33e9eccb1de3..5fccfd9f477f3a7b516a2a453be2c7d62e5a9a49 100644
--- a/src/core/hle/kernel/scheduler.cpp
+++ b/src/core/hle/kernel/scheduler.cpp
@@ -19,7 +19,8 @@ namespace Kernel {
 
 std::mutex Scheduler::scheduler_mutex;
 
-Scheduler::Scheduler(Core::ARM_Interface& cpu_core) : cpu_core(cpu_core) {}
+Scheduler::Scheduler(Core::System& system, Core::ARM_Interface& cpu_core)
+    : cpu_core{cpu_core}, system{system} {}
 
 Scheduler::~Scheduler() {
     for (auto& thread : thread_list) {
@@ -61,7 +62,7 @@ Thread* Scheduler::PopNextReadyThread() {
 
 void Scheduler::SwitchContext(Thread* new_thread) {
     Thread* const previous_thread = GetCurrentThread();
-    Process* const previous_process = Core::CurrentProcess();
+    Process* const previous_process = system.Kernel().CurrentProcess();
 
     UpdateLastContextSwitchTime(previous_thread, previous_process);
 
@@ -94,8 +95,8 @@ void Scheduler::SwitchContext(Thread* new_thread) {
 
         auto* const thread_owner_process = current_thread->GetOwnerProcess();
         if (previous_process != thread_owner_process) {
-            Core::System::GetInstance().Kernel().MakeCurrentProcess(thread_owner_process);
-            SetCurrentPageTable(&Core::CurrentProcess()->VMManager().page_table);
+            system.Kernel().MakeCurrentProcess(thread_owner_process);
+            SetCurrentPageTable(&thread_owner_process->VMManager().page_table);
         }
 
         cpu_core.LoadContext(new_thread->GetContext());
@@ -111,7 +112,7 @@ void Scheduler::SwitchContext(Thread* new_thread) {
 
 void Scheduler::UpdateLastContextSwitchTime(Thread* thread, Process* process) {
     const u64 prev_switch_ticks = last_context_switch_time;
-    const u64 most_recent_switch_ticks = Core::System::GetInstance().CoreTiming().GetTicks();
+    const u64 most_recent_switch_ticks = system.CoreTiming().GetTicks();
     const u64 update_ticks = most_recent_switch_ticks - prev_switch_ticks;
 
     if (thread != nullptr) {
@@ -223,8 +224,7 @@ void Scheduler::YieldWithLoadBalancing(Thread* thread) {
     // Take the first non-nullptr one
     for (unsigned cur_core = 0; cur_core < Core::NUM_CPU_CORES; ++cur_core) {
         const auto res =
-            Core::System::GetInstance().CpuCore(cur_core).Scheduler().GetNextSuggestedThread(
-                core, priority);
+            system.CpuCore(cur_core).Scheduler().GetNextSuggestedThread(core, priority);
 
         // If scheduler provides a suggested thread
         if (res != nullptr) {
diff --git a/src/core/hle/kernel/scheduler.h b/src/core/hle/kernel/scheduler.h
index 97ced4dfc3691b34af0484c1e0adf0c0ccac7ca7..1c5bf57d9ce3d96f3c4673a08568802d605d838d 100644
--- a/src/core/hle/kernel/scheduler.h
+++ b/src/core/hle/kernel/scheduler.h
@@ -13,7 +13,8 @@
 
 namespace Core {
 class ARM_Interface;
-}
+class System;
+} // namespace Core
 
 namespace Kernel {
 
@@ -21,7 +22,7 @@ class Process;
 
 class Scheduler final {
 public:
-    explicit Scheduler(Core::ARM_Interface& cpu_core);
+    explicit Scheduler(Core::System& system, Core::ARM_Interface& cpu_core);
     ~Scheduler();
 
     /// Returns whether there are any threads that are ready to run.
@@ -162,6 +163,7 @@ private:
     Core::ARM_Interface& cpu_core;
     u64 last_context_switch_time = 0;
 
+    Core::System& system;
     static std::mutex scheduler_mutex;
 };