From dbfd830695a040354f33a52c5ddcffe5d96928a7 Mon Sep 17 00:00:00 2001
From: bamsbamx <anernaiz@gmail.com>
Date: Wed, 26 Jun 2019 00:39:11 +0200
Subject: [PATCH] kernel: Let the kernel handle all page table changes when
 switching processes It will both change the page table in memory and notify
 the CPU about the change by itself. This way there is no need to call
 memory.SetCurrentPageTable() when kernel.setCurrentProcess() and the
 management is kept internally in the kernel

---
 src/core/core.cpp                      |  9 ++++-----
 src/core/core.h                        |  2 +-
 src/core/hle/kernel/kernel.cpp         | 13 ++++++++++++-
 src/core/hle/kernel/kernel.h           |  7 +++++++
 src/core/hle/kernel/thread.cpp         |  3 ---
 src/tests/core/arm/arm_test_common.cpp |  2 +-
 6 files changed, 25 insertions(+), 11 deletions(-)

diff --git a/src/core/core.cpp b/src/core/core.cpp
index 286364018..a8abf9af1 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -141,7 +141,6 @@ System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::st
             return ResultStatus::ErrorLoader;
         }
     }
-    memory->SetCurrentPageTable(&kernel->GetCurrentProcess()->vm_manager.page_table);
     cheat_engine = std::make_unique<Cheats::CheatEngine>(*this);
     status = ResultStatus::Success;
     m_emu_window = &emu_window;
@@ -179,16 +178,16 @@ System::ResultStatus System::Init(Frontend::EmuWindow& emu_window, u32 system_mo
 
     if (Settings::values.use_cpu_jit) {
 #ifdef ARCHITECTURE_x86_64
-        cpu_core = std::make_unique<ARM_Dynarmic>(this, *memory, USER32MODE);
+        cpu_core = std::make_shared<ARM_Dynarmic>(this, *memory, USER32MODE);
 #else
-        cpu_core = std::make_unique<ARM_DynCom>(this, *memory, USER32MODE);
+        cpu_core = std::make_shared<ARM_DynCom>(this, *memory, USER32MODE);
         LOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available");
 #endif
     } else {
-        cpu_core = std::make_unique<ARM_DynCom>(this, *memory, USER32MODE);
+        cpu_core = std::make_shared<ARM_DynCom>(this, *memory, USER32MODE);
     }
 
-    kernel->GetThreadManager().SetCPU(*cpu_core);
+    kernel->SetCPU(cpu_core);
 
     if (Settings::values.enable_dsp_lle) {
         dsp_core = std::make_unique<AudioCore::DspLle>(*memory,
diff --git a/src/core/core.h b/src/core/core.h
index 9105f0e5e..bcc371251 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -255,7 +255,7 @@ private:
     std::unique_ptr<Loader::AppLoader> app_loader;
 
     /// ARM11 CPU core
-    std::unique_ptr<ARM_Interface> cpu_core;
+    std::shared_ptr<ARM_Interface> cpu_core;
 
     /// DSP core
     std::unique_ptr<AudioCore::DspInterface> dsp_core;
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 61734933b..b048e863f 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -47,7 +47,18 @@ std::shared_ptr<Process> KernelSystem::GetCurrentProcess() const {
 }
 
 void KernelSystem::SetCurrentProcess(std::shared_ptr<Process> process) {
-    current_process = std::move(process);
+    current_process = process;
+    SetCurrentMemPageTable(&process->vm_manager.page_table);
+}
+
+void KernelSystem::SetCurrentMemPageTable(Memory::PageTable* page_table) {
+    memory.SetCurrentPageTable(page_table);
+    current_cpu->PageTableChanged(); // notify the CPU the page table in memory has changed
+}
+
+void KernelSystem::SetCPU(std::shared_ptr<ARM_Interface> cpu) {
+    current_cpu = cpu;
+    thread_manager->SetCPU(*cpu);
 }
 
 ThreadManager& KernelSystem::GetThreadManager() {
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index c51affac5..a9632be42 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -14,6 +14,7 @@
 #include "common/common_types.h"
 #include "core/hle/kernel/memory.h"
 #include "core/hle/result.h"
+#include "core/memory.h"
 
 namespace ConfigMem {
 class Handler;
@@ -206,6 +207,10 @@ public:
     std::shared_ptr<Process> GetCurrentProcess() const;
     void SetCurrentProcess(std::shared_ptr<Process> process);
 
+    void SetCurrentMemPageTable(Memory::PageTable* page_table);
+
+    void SetCPU(std::shared_ptr<ARM_Interface> cpu);
+
     ThreadManager& GetThreadManager();
     const ThreadManager& GetThreadManager() const;
 
@@ -233,6 +238,8 @@ public:
     /// Map of named ports managed by the kernel, which can be retrieved using the ConnectToPort
     std::unordered_map<std::string, std::shared_ptr<ClientPort>> named_ports;
 
+    std::shared_ptr<ARM_Interface> current_cpu;
+
     Memory::MemorySystem& memory;
 
     Core::Timing& timing;
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index e4b14417f..3b15ec35e 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -112,9 +112,6 @@ void ThreadManager::SwitchContext(Thread* new_thread) {
 
         if (previous_process.get() != current_thread->owner_process) {
             kernel.SetCurrentProcess(SharedFrom(current_thread->owner_process));
-            kernel.memory.SetCurrentPageTable(
-                &current_thread->owner_process->vm_manager.page_table);
-            cpu->PageTableChanged(); // notify the CPU the page table in memory has changed
         }
 
         cpu->LoadContext(new_thread->context);
diff --git a/src/tests/core/arm/arm_test_common.cpp b/src/tests/core/arm/arm_test_common.cpp
index 3c8ac9878..6cb90a48f 100644
--- a/src/tests/core/arm/arm_test_common.cpp
+++ b/src/tests/core/arm/arm_test_common.cpp
@@ -28,7 +28,7 @@ TestEnvironment::TestEnvironment(bool mutable_memory_)
     memory->MapIoRegion(*page_table, 0x00000000, 0x80000000, test_memory);
     memory->MapIoRegion(*page_table, 0x80000000, 0x80000000, test_memory);
 
-    memory->SetCurrentPageTable(page_table);
+    kernel->SetCurrentMemPageTable(page_table);
 }
 
 TestEnvironment::~TestEnvironment() {