summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar Lioncash2019-04-09 13:25:54 -0400
committerGravatar Lioncash2019-04-11 22:11:40 -0400
commitf2331a804a2fa300d9a7dc0d012e3242b7accdaf (patch)
treed7f61aa201effed9e37fc07c626218759fc75288 /src
parentMerge pull request #2235 from ReinUsesLisp/spirv-decompiler (diff)
downloadyuzu-f2331a804a2fa300d9a7dc0d012e3242b7accdaf.tar.gz
yuzu-f2331a804a2fa300d9a7dc0d012e3242b7accdaf.tar.xz
yuzu-f2331a804a2fa300d9a7dc0d012e3242b7accdaf.zip
core/cpu_core_manager: Create threads separately from initialization.
Our initialization process is a little wonky than one would expect when it comes to code flow. We initialize the CPU last, as opposed to hardware, where the CPU obviously needs to be first, otherwise nothing else would work, and we have code that adds checks to get around this. For example, in the page table setting code, we check to see if the system is turned on before we even notify the CPU instances of a page table switch. This results in dead code (at the moment), because the only time a page table switch will occur is when the system is *not* running, preventing the emulated CPU instances from being notified of a page table switch in a convenient manner (technically the code path could be taken, but we don't emulate the process creation svc handlers yet). This moves the threads creation into its own member function of the core manager and restores a little order (and predictability) to our initialization process. Previously, in the multi-threaded cases, we'd kick off several threads before even the main kernel process was created and ready to execute (gross!). Now the initialization process is like so: Initialization: 1. Timers 2. CPU 3. Kernel 4. Filesystem stuff (kind of gross, but can be amended trivially) 5. Applet stuff (ditto in terms of being kind of gross) 6. Main process (will be moved into the loading step in a following change) 7. Telemetry (this should be initialized last in the future). 8. Services (4 and 5 should ideally be alongside this). 9. GDB (gross. Uses namespace scope state. Needs to be refactored into a class or booted altogether). 10. Renderer 11. GPU (will also have its threads created in a separate step in a following change). Which... isn't *ideal* per-se, however getting rid of the wonky intertwining of CPU state initialization out of this mix gets rid of most of the footguns when it comes to our initialization process.
Diffstat (limited to 'src')
-rw-r--r--src/core/arm/arm_interface.h14
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic.cpp23
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic.h6
-rw-r--r--src/core/arm/unicorn/arm_unicorn.h2
-rw-r--r--src/core/core.cpp9
-rw-r--r--src/core/cpu_core_manager.cpp6
-rw-r--r--src/core/cpu_core_manager.h7
-rw-r--r--src/core/hle/kernel/kernel.cpp7
-rw-r--r--src/core/hle/kernel/process.cpp2
-rw-r--r--src/core/memory.cpp16
-rw-r--r--src/core/memory.h5
11 files changed, 58 insertions, 39 deletions
diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h
index 4dfd41b43..978b1518f 100644
--- a/src/core/arm/arm_interface.h
+++ b/src/core/arm/arm_interface.h
@@ -7,6 +7,10 @@
7#include <array> 7#include <array>
8#include "common/common_types.h" 8#include "common/common_types.h"
9 9
10namespace Common {
11struct PageTable;
12}
13
10namespace Kernel { 14namespace Kernel {
11enum class VMAPermission : u8; 15enum class VMAPermission : u8;
12} 16}
@@ -49,8 +53,14 @@ public:
49 /// Clear all instruction cache 53 /// Clear all instruction cache
50 virtual void ClearInstructionCache() = 0; 54 virtual void ClearInstructionCache() = 0;
51 55
52 /// Notify CPU emulation that page tables have changed 56 /// Notifies CPU emulation that the current page table has changed.
53 virtual void PageTableChanged() = 0; 57 ///
58 /// @param new_page_table The new page table.
59 /// @param new_address_space_size_in_bits The new usable size of the address space in bits.
60 /// This can be either 32, 36, or 39 on official software.
61 ///
62 virtual void PageTableChanged(Common::PageTable& new_page_table,
63 std::size_t new_address_space_size_in_bits) = 0;
54 64
55 /** 65 /**
56 * Set the Program Counter to an address 66 * Set the Program Counter to an address
diff --git a/src/core/arm/dynarmic/arm_dynarmic.cpp b/src/core/arm/dynarmic/arm_dynarmic.cpp
index dc96e35d5..44307fa19 100644
--- a/src/core/arm/dynarmic/arm_dynarmic.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic.cpp
@@ -14,7 +14,6 @@
14#include "core/core_timing.h" 14#include "core/core_timing.h"
15#include "core/core_timing_util.h" 15#include "core/core_timing_util.h"
16#include "core/gdbstub/gdbstub.h" 16#include "core/gdbstub/gdbstub.h"
17#include "core/hle/kernel/kernel.h"
18#include "core/hle/kernel/process.h" 17#include "core/hle/kernel/process.h"
19#include "core/hle/kernel/svc.h" 18#include "core/hle/kernel/svc.h"
20#include "core/hle/kernel/vm_manager.h" 19#include "core/hle/kernel/vm_manager.h"
@@ -129,18 +128,16 @@ public:
129 u64 tpidr_el0 = 0; 128 u64 tpidr_el0 = 0;
130}; 129};
131 130
132std::unique_ptr<Dynarmic::A64::Jit> ARM_Dynarmic::MakeJit() const { 131std::unique_ptr<Dynarmic::A64::Jit> ARM_Dynarmic::MakeJit(Common::PageTable& page_table,
133 auto* current_process = system.Kernel().CurrentProcess(); 132 std::size_t address_space_bits) const {
134 auto** const page_table = current_process->VMManager().page_table.pointers.data();
135
136 Dynarmic::A64::UserConfig config; 133 Dynarmic::A64::UserConfig config;
137 134
138 // Callbacks 135 // Callbacks
139 config.callbacks = cb.get(); 136 config.callbacks = cb.get();
140 137
141 // Memory 138 // Memory
142 config.page_table = reinterpret_cast<void**>(page_table); 139 config.page_table = reinterpret_cast<void**>(page_table.pointers.data());
143 config.page_table_address_space_bits = current_process->VMManager().GetAddressSpaceWidth(); 140 config.page_table_address_space_bits = address_space_bits;
144 config.silently_mirror_page_table = false; 141 config.silently_mirror_page_table = false;
145 142
146 // Multi-process state 143 // Multi-process state
@@ -176,12 +173,7 @@ ARM_Dynarmic::ARM_Dynarmic(System& system, ExclusiveMonitor& exclusive_monitor,
176 std::size_t core_index) 173 std::size_t core_index)
177 : cb(std::make_unique<ARM_Dynarmic_Callbacks>(*this)), inner_unicorn{system}, 174 : cb(std::make_unique<ARM_Dynarmic_Callbacks>(*this)), inner_unicorn{system},
178 core_index{core_index}, system{system}, 175 core_index{core_index}, system{system},
179 exclusive_monitor{dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor)} { 176 exclusive_monitor{dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor)} {}
180 ThreadContext ctx{};
181 inner_unicorn.SaveContext(ctx);
182 PageTableChanged();
183 LoadContext(ctx);
184}
185 177
186ARM_Dynarmic::~ARM_Dynarmic() = default; 178ARM_Dynarmic::~ARM_Dynarmic() = default;
187 179
@@ -276,8 +268,9 @@ void ARM_Dynarmic::ClearExclusiveState() {
276 jit->ClearExclusiveState(); 268 jit->ClearExclusiveState();
277} 269}
278 270
279void ARM_Dynarmic::PageTableChanged() { 271void ARM_Dynarmic::PageTableChanged(Common::PageTable& page_table,
280 jit = MakeJit(); 272 std::size_t new_address_space_size_in_bits) {
273 jit = MakeJit(page_table, new_address_space_size_in_bits);
281} 274}
282 275
283DynarmicExclusiveMonitor::DynarmicExclusiveMonitor(std::size_t core_count) : monitor(core_count) {} 276DynarmicExclusiveMonitor::DynarmicExclusiveMonitor(std::size_t core_count) : monitor(core_count) {}
diff --git a/src/core/arm/dynarmic/arm_dynarmic.h b/src/core/arm/dynarmic/arm_dynarmic.h
index c1db254e8..b701e97a3 100644
--- a/src/core/arm/dynarmic/arm_dynarmic.h
+++ b/src/core/arm/dynarmic/arm_dynarmic.h
@@ -48,10 +48,12 @@ public:
48 void ClearExclusiveState() override; 48 void ClearExclusiveState() override;
49 49
50 void ClearInstructionCache() override; 50 void ClearInstructionCache() override;
51 void PageTableChanged() override; 51 void PageTableChanged(Common::PageTable& new_page_table,
52 std::size_t new_address_space_size_in_bits) override;
52 53
53private: 54private:
54 std::unique_ptr<Dynarmic::A64::Jit> MakeJit() const; 55 std::unique_ptr<Dynarmic::A64::Jit> MakeJit(Common::PageTable& page_table,
56 std::size_t address_space_bits) const;
55 57
56 friend class ARM_Dynarmic_Callbacks; 58 friend class ARM_Dynarmic_Callbacks;
57 std::unique_ptr<ARM_Dynarmic_Callbacks> cb; 59 std::unique_ptr<ARM_Dynarmic_Callbacks> cb;
diff --git a/src/core/arm/unicorn/arm_unicorn.h b/src/core/arm/unicorn/arm_unicorn.h
index 209fc16ad..34e974b4d 100644
--- a/src/core/arm/unicorn/arm_unicorn.h
+++ b/src/core/arm/unicorn/arm_unicorn.h
@@ -41,7 +41,7 @@ public:
41 void Run() override; 41 void Run() override;
42 void Step() override; 42 void Step() override;
43 void ClearInstructionCache() override; 43 void ClearInstructionCache() override;
44 void PageTableChanged() override{}; 44 void PageTableChanged(Common::PageTable&, std::size_t) override {}
45 void RecordBreak(GDBStub::BreakpointAddress bkpt); 45 void RecordBreak(GDBStub::BreakpointAddress bkpt);
46 46
47private: 47private:
diff --git a/src/core/core.cpp b/src/core/core.cpp
index bc9e887b6..2b8ec3ca7 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -81,7 +81,7 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs,
81 return vfs->OpenFile(path, FileSys::Mode::Read); 81 return vfs->OpenFile(path, FileSys::Mode::Read);
82} 82}
83struct System::Impl { 83struct System::Impl {
84 explicit Impl(System& system) : kernel{system} {} 84 explicit Impl(System& system) : kernel{system}, cpu_core_manager{system} {}
85 85
86 Cpu& CurrentCpuCore() { 86 Cpu& CurrentCpuCore() {
87 return cpu_core_manager.GetCurrentCore(); 87 return cpu_core_manager.GetCurrentCore();
@@ -99,6 +99,7 @@ struct System::Impl {
99 LOG_DEBUG(HW_Memory, "initialized OK"); 99 LOG_DEBUG(HW_Memory, "initialized OK");
100 100
101 core_timing.Initialize(); 101 core_timing.Initialize();
102 cpu_core_manager.Initialize();
102 kernel.Initialize(); 103 kernel.Initialize();
103 104
104 const auto current_time = std::chrono::duration_cast<std::chrono::seconds>( 105 const auto current_time = std::chrono::duration_cast<std::chrono::seconds>(
@@ -142,8 +143,6 @@ struct System::Impl {
142 gpu_core = std::make_unique<VideoCommon::GPUSynch>(system, *renderer); 143 gpu_core = std::make_unique<VideoCommon::GPUSynch>(system, *renderer);
143 } 144 }
144 145
145 cpu_core_manager.Initialize(system);
146
147 LOG_DEBUG(Core, "Initialized OK"); 146 LOG_DEBUG(Core, "Initialized OK");
148 147
149 // Reset counters and set time origin to current frame 148 // Reset counters and set time origin to current frame
@@ -188,6 +187,10 @@ struct System::Impl {
188 static_cast<u32>(load_result)); 187 static_cast<u32>(load_result));
189 } 188 }
190 189
190 // Main process has been loaded and been made current.
191 // Begin CPU execution.
192 cpu_core_manager.StartThreads();
193
191 status = ResultStatus::Success; 194 status = ResultStatus::Success;
192 return status; 195 return status;
193 } 196 }
diff --git a/src/core/cpu_core_manager.cpp b/src/core/cpu_core_manager.cpp
index 93bc5619c..8fcb4eeb1 100644
--- a/src/core/cpu_core_manager.cpp
+++ b/src/core/cpu_core_manager.cpp
@@ -19,17 +19,19 @@ void RunCpuCore(const System& system, Cpu& cpu_state) {
19} 19}
20} // Anonymous namespace 20} // Anonymous namespace
21 21
22CpuCoreManager::CpuCoreManager() = default; 22CpuCoreManager::CpuCoreManager(System& system) : system{system} {}
23CpuCoreManager::~CpuCoreManager() = default; 23CpuCoreManager::~CpuCoreManager() = default;
24 24
25void CpuCoreManager::Initialize(System& system) { 25void CpuCoreManager::Initialize() {
26 barrier = std::make_unique<CpuBarrier>(); 26 barrier = std::make_unique<CpuBarrier>();
27 exclusive_monitor = Cpu::MakeExclusiveMonitor(cores.size()); 27 exclusive_monitor = Cpu::MakeExclusiveMonitor(cores.size());
28 28
29 for (std::size_t index = 0; index < cores.size(); ++index) { 29 for (std::size_t index = 0; index < cores.size(); ++index) {
30 cores[index] = std::make_unique<Cpu>(system, *exclusive_monitor, *barrier, index); 30 cores[index] = std::make_unique<Cpu>(system, *exclusive_monitor, *barrier, index);
31 } 31 }
32}
32 33
34void CpuCoreManager::StartThreads() {
33 // Create threads for CPU cores 1-3, and build thread_to_cpu map 35 // Create threads for CPU cores 1-3, and build thread_to_cpu map
34 // CPU core 0 is run on the main thread 36 // CPU core 0 is run on the main thread
35 thread_to_cpu[std::this_thread::get_id()] = cores[0].get(); 37 thread_to_cpu[std::this_thread::get_id()] = cores[0].get();
diff --git a/src/core/cpu_core_manager.h b/src/core/cpu_core_manager.h
index a4d70ec56..2cbbf8216 100644
--- a/src/core/cpu_core_manager.h
+++ b/src/core/cpu_core_manager.h
@@ -18,7 +18,7 @@ class System;
18 18
19class CpuCoreManager { 19class CpuCoreManager {
20public: 20public:
21 CpuCoreManager(); 21 explicit CpuCoreManager(System& system);
22 CpuCoreManager(const CpuCoreManager&) = delete; 22 CpuCoreManager(const CpuCoreManager&) = delete;
23 CpuCoreManager(CpuCoreManager&&) = delete; 23 CpuCoreManager(CpuCoreManager&&) = delete;
24 24
@@ -27,7 +27,8 @@ public:
27 CpuCoreManager& operator=(const CpuCoreManager&) = delete; 27 CpuCoreManager& operator=(const CpuCoreManager&) = delete;
28 CpuCoreManager& operator=(CpuCoreManager&&) = delete; 28 CpuCoreManager& operator=(CpuCoreManager&&) = delete;
29 29
30 void Initialize(System& system); 30 void Initialize();
31 void StartThreads();
31 void Shutdown(); 32 void Shutdown();
32 33
33 Cpu& GetCore(std::size_t index); 34 Cpu& GetCore(std::size_t index);
@@ -54,6 +55,8 @@ private:
54 55
55 /// Map of guest threads to CPU cores 56 /// Map of guest threads to CPU cores
56 std::map<std::thread::id, Cpu*> thread_to_cpu; 57 std::map<std::thread::id, Cpu*> thread_to_cpu;
58
59 System& system;
57}; 60};
58 61
59} // namespace Core 62} // namespace Core
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 4d58e7c69..8539fabe4 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -182,7 +182,12 @@ void KernelCore::AppendNewProcess(SharedPtr<Process> process) {
182 182
183void KernelCore::MakeCurrentProcess(Process* process) { 183void KernelCore::MakeCurrentProcess(Process* process) {
184 impl->current_process = process; 184 impl->current_process = process;
185 Memory::SetCurrentPageTable(&process->VMManager().page_table); 185
186 if (process == nullptr) {
187 return;
188 }
189
190 Memory::SetCurrentPageTable(*process);
186} 191}
187 192
188Process* KernelCore::CurrentProcess() { 193Process* KernelCore::CurrentProcess() {
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp
index 4e94048da..94d196e5c 100644
--- a/src/core/hle/kernel/process.cpp
+++ b/src/core/hle/kernel/process.cpp
@@ -107,7 +107,7 @@ ResultCode Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata) {
107 107
108 vm_manager.Reset(metadata.GetAddressSpaceType()); 108 vm_manager.Reset(metadata.GetAddressSpaceType());
109 // Ensure that the potentially resized page table is seen by CPU backends. 109 // Ensure that the potentially resized page table is seen by CPU backends.
110 Memory::SetCurrentPageTable(&vm_manager.page_table); 110 Memory::SetCurrentPageTable(*this);
111 111
112 const auto& caps = metadata.GetKernelCapabilities(); 112 const auto& caps = metadata.GetKernelCapabilities();
113 const auto capability_init_result = 113 const auto capability_init_result =
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index 4e0538bc2..f18f6226b 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -26,16 +26,16 @@ namespace Memory {
26 26
27static Common::PageTable* current_page_table = nullptr; 27static Common::PageTable* current_page_table = nullptr;
28 28
29void SetCurrentPageTable(Common::PageTable* page_table) { 29void SetCurrentPageTable(Kernel::Process& process) {
30 current_page_table = page_table; 30 current_page_table = &process.VMManager().page_table;
31
32 const std::size_t address_space_width = process.VMManager().GetAddressSpaceWidth();
31 33
32 auto& system = Core::System::GetInstance(); 34 auto& system = Core::System::GetInstance();
33 if (system.IsPoweredOn()) { 35 system.ArmInterface(0).PageTableChanged(*current_page_table, address_space_width);
34 system.ArmInterface(0).PageTableChanged(); 36 system.ArmInterface(1).PageTableChanged(*current_page_table, address_space_width);
35 system.ArmInterface(1).PageTableChanged(); 37 system.ArmInterface(2).PageTableChanged(*current_page_table, address_space_width);
36 system.ArmInterface(2).PageTableChanged(); 38 system.ArmInterface(3).PageTableChanged(*current_page_table, address_space_width);
37 system.ArmInterface(3).PageTableChanged();
38 }
39} 39}
40 40
41static void MapPages(Common::PageTable& page_table, VAddr base, u64 size, u8* memory, 41static void MapPages(Common::PageTable& page_table, VAddr base, u64 size, u8* memory,
diff --git a/src/core/memory.h b/src/core/memory.h
index 6845f5fe1..b9fa18b1d 100644
--- a/src/core/memory.h
+++ b/src/core/memory.h
@@ -40,8 +40,9 @@ enum : VAddr {
40 KERNEL_REGION_END = KERNEL_REGION_VADDR + KERNEL_REGION_SIZE, 40 KERNEL_REGION_END = KERNEL_REGION_VADDR + KERNEL_REGION_SIZE,
41}; 41};
42 42
43/// Changes the currently active page table. 43/// Changes the currently active page table to that of
44void SetCurrentPageTable(Common::PageTable* page_table); 44/// the given process instance.
45void SetCurrentPageTable(Kernel::Process& process);
45 46
46/// Determines if the given VAddr is valid for the specified process. 47/// Determines if the given VAddr is valid for the specified process.
47bool IsValidVirtualAddress(const Kernel::Process& process, VAddr vaddr); 48bool IsValidVirtualAddress(const Kernel::Process& process, VAddr vaddr);