summaryrefslogtreecommitdiff
path: root/src/core/cpu_manager.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/cpu_manager.cpp')
-rw-r--r--src/core/cpu_manager.cpp129
1 files changed, 63 insertions, 66 deletions
diff --git a/src/core/cpu_manager.cpp b/src/core/cpu_manager.cpp
index 37d3d83b9..9b1565ae1 100644
--- a/src/core/cpu_manager.cpp
+++ b/src/core/cpu_manager.cpp
@@ -8,6 +8,7 @@
8#include "core/core.h" 8#include "core/core.h"
9#include "core/core_timing.h" 9#include "core/core_timing.h"
10#include "core/cpu_manager.h" 10#include "core/cpu_manager.h"
11#include "core/hle/kernel/k_interrupt_manager.h"
11#include "core/hle/kernel/k_scheduler.h" 12#include "core/hle/kernel/k_scheduler.h"
12#include "core/hle/kernel/k_thread.h" 13#include "core/hle/kernel/k_thread.h"
13#include "core/hle/kernel/kernel.h" 14#include "core/hle/kernel/kernel.h"
@@ -49,14 +50,6 @@ void CpuManager::GuestThreadFunction() {
49 } 50 }
50} 51}
51 52
52void CpuManager::GuestRewindFunction() {
53 if (is_multicore) {
54 MultiCoreRunGuestLoop();
55 } else {
56 SingleCoreRunGuestLoop();
57 }
58}
59
60void CpuManager::IdleThreadFunction() { 53void CpuManager::IdleThreadFunction() {
61 if (is_multicore) { 54 if (is_multicore) {
62 MultiCoreRunIdleThread(); 55 MultiCoreRunIdleThread();
@@ -69,21 +62,21 @@ void CpuManager::ShutdownThreadFunction() {
69 ShutdownThread(); 62 ShutdownThread();
70} 63}
71 64
65void CpuManager::HandleInterrupt() {
66 auto& kernel = system.Kernel();
67 auto core_index = kernel.CurrentPhysicalCoreIndex();
68
69 Kernel::KInterruptManager::HandleInterrupt(kernel, static_cast<s32>(core_index));
70}
71
72/////////////////////////////////////////////////////////////////////////////// 72///////////////////////////////////////////////////////////////////////////////
73/// MultiCore /// 73/// MultiCore ///
74/////////////////////////////////////////////////////////////////////////////// 74///////////////////////////////////////////////////////////////////////////////
75 75
76void CpuManager::MultiCoreRunGuestThread() { 76void CpuManager::MultiCoreRunGuestThread() {
77 // Similar to UserModeThreadStarter in HOS
77 auto& kernel = system.Kernel(); 78 auto& kernel = system.Kernel();
78 kernel.CurrentScheduler()->OnThreadStart(); 79 kernel.CurrentScheduler()->OnThreadStart();
79 auto* thread = kernel.CurrentScheduler()->GetSchedulerCurrentThread();
80 auto& host_context = thread->GetHostContext();
81 host_context->SetRewindPoint([this] { GuestRewindFunction(); });
82 MultiCoreRunGuestLoop();
83}
84
85void CpuManager::MultiCoreRunGuestLoop() {
86 auto& kernel = system.Kernel();
87 80
88 while (true) { 81 while (true) {
89 auto* physical_core = &kernel.CurrentPhysicalCore(); 82 auto* physical_core = &kernel.CurrentPhysicalCore();
@@ -91,18 +84,26 @@ void CpuManager::MultiCoreRunGuestLoop() {
91 physical_core->Run(); 84 physical_core->Run();
92 physical_core = &kernel.CurrentPhysicalCore(); 85 physical_core = &kernel.CurrentPhysicalCore();
93 } 86 }
94 { 87
95 Kernel::KScopedDisableDispatch dd(kernel); 88 HandleInterrupt();
96 physical_core->ArmInterface().ClearExclusiveState();
97 }
98 } 89 }
99} 90}
100 91
101void CpuManager::MultiCoreRunIdleThread() { 92void CpuManager::MultiCoreRunIdleThread() {
93 // Not accurate to HOS. Remove this entire method when singlecore is removed.
94 // See notes in KScheduler::ScheduleImpl for more information about why this
95 // is inaccurate.
96
102 auto& kernel = system.Kernel(); 97 auto& kernel = system.Kernel();
98 kernel.CurrentScheduler()->OnThreadStart();
99
103 while (true) { 100 while (true) {
104 Kernel::KScopedDisableDispatch dd(kernel); 101 auto& physical_core = kernel.CurrentPhysicalCore();
105 kernel.CurrentPhysicalCore().Idle(); 102 if (!physical_core.IsInterrupted()) {
103 physical_core.Idle();
104 }
105
106 HandleInterrupt();
106 } 107 }
107} 108}
108 109
@@ -113,80 +114,73 @@ void CpuManager::MultiCoreRunIdleThread() {
113void CpuManager::SingleCoreRunGuestThread() { 114void CpuManager::SingleCoreRunGuestThread() {
114 auto& kernel = system.Kernel(); 115 auto& kernel = system.Kernel();
115 kernel.CurrentScheduler()->OnThreadStart(); 116 kernel.CurrentScheduler()->OnThreadStart();
116 auto* thread = kernel.CurrentScheduler()->GetSchedulerCurrentThread();
117 auto& host_context = thread->GetHostContext();
118 host_context->SetRewindPoint([this] { GuestRewindFunction(); });
119 SingleCoreRunGuestLoop();
120}
121 117
122void CpuManager::SingleCoreRunGuestLoop() {
123 auto& kernel = system.Kernel();
124 while (true) { 118 while (true) {
125 auto* physical_core = &kernel.CurrentPhysicalCore(); 119 auto* physical_core = &kernel.CurrentPhysicalCore();
126 if (!physical_core->IsInterrupted()) { 120 if (!physical_core->IsInterrupted()) {
127 physical_core->Run(); 121 physical_core->Run();
128 physical_core = &kernel.CurrentPhysicalCore(); 122 physical_core = &kernel.CurrentPhysicalCore();
129 } 123 }
124
130 kernel.SetIsPhantomModeForSingleCore(true); 125 kernel.SetIsPhantomModeForSingleCore(true);
131 system.CoreTiming().Advance(); 126 system.CoreTiming().Advance();
132 kernel.SetIsPhantomModeForSingleCore(false); 127 kernel.SetIsPhantomModeForSingleCore(false);
133 physical_core->ArmInterface().ClearExclusiveState(); 128
134 PreemptSingleCore(); 129 PreemptSingleCore();
135 auto& scheduler = kernel.Scheduler(current_core); 130 HandleInterrupt();
136 scheduler.RescheduleCurrentCore();
137 } 131 }
138} 132}
139 133
140void CpuManager::SingleCoreRunIdleThread() { 134void CpuManager::SingleCoreRunIdleThread() {
141 auto& kernel = system.Kernel(); 135 auto& kernel = system.Kernel();
136 kernel.CurrentScheduler()->OnThreadStart();
137
142 while (true) { 138 while (true) {
143 auto& physical_core = kernel.CurrentPhysicalCore();
144 PreemptSingleCore(false); 139 PreemptSingleCore(false);
145 system.CoreTiming().AddTicks(1000U); 140 system.CoreTiming().AddTicks(1000U);
146 idle_count++; 141 idle_count++;
147 auto& scheduler = physical_core.Scheduler(); 142 HandleInterrupt();
148 scheduler.RescheduleCurrentCore();
149 } 143 }
150} 144}
151 145
152void CpuManager::PreemptSingleCore(bool from_running_enviroment) { 146void CpuManager::PreemptSingleCore(bool from_running_environment) {
153 { 147 auto& kernel = system.Kernel();
154 auto& kernel = system.Kernel();
155 auto& scheduler = kernel.Scheduler(current_core);
156 Kernel::KThread* current_thread = scheduler.GetSchedulerCurrentThread();
157 if (idle_count >= 4 || from_running_enviroment) {
158 if (!from_running_enviroment) {
159 system.CoreTiming().Idle();
160 idle_count = 0;
161 }
162 kernel.SetIsPhantomModeForSingleCore(true);
163 system.CoreTiming().Advance();
164 kernel.SetIsPhantomModeForSingleCore(false);
165 }
166 current_core.store((current_core + 1) % Core::Hardware::NUM_CPU_CORES);
167 system.CoreTiming().ResetTicks();
168 scheduler.Unload(scheduler.GetSchedulerCurrentThread());
169
170 auto& next_scheduler = kernel.Scheduler(current_core);
171 Common::Fiber::YieldTo(current_thread->GetHostContext(), *next_scheduler.ControlContext());
172 }
173 148
174 // May have changed scheduler 149 if (idle_count >= 4 || from_running_environment) {
175 { 150 if (!from_running_environment) {
176 auto& scheduler = system.Kernel().Scheduler(current_core); 151 system.CoreTiming().Idle();
177 scheduler.Reload(scheduler.GetSchedulerCurrentThread());
178 if (!scheduler.IsIdle()) {
179 idle_count = 0; 152 idle_count = 0;
180 } 153 }
154 kernel.SetIsPhantomModeForSingleCore(true);
155 system.CoreTiming().Advance();
156 kernel.SetIsPhantomModeForSingleCore(false);
157 }
158 current_core.store((current_core + 1) % Core::Hardware::NUM_CPU_CORES);
159 system.CoreTiming().ResetTicks();
160 kernel.Scheduler(current_core).PreemptSingleCore();
161
162 // We've now been scheduled again, and we may have exchanged schedulers.
163 // Reload the scheduler in case it's different.
164 if (!kernel.Scheduler(current_core).IsIdle()) {
165 idle_count = 0;
181 } 166 }
182} 167}
183 168
169void CpuManager::GuestActivate() {
170 // Similar to the HorizonKernelMain callback in HOS
171 auto& kernel = system.Kernel();
172 auto* scheduler = kernel.CurrentScheduler();
173
174 scheduler->Activate();
175 UNREACHABLE();
176}
177
184void CpuManager::ShutdownThread() { 178void CpuManager::ShutdownThread() {
185 auto& kernel = system.Kernel(); 179 auto& kernel = system.Kernel();
180 auto* thread = kernel.GetCurrentEmuThread();
186 auto core = is_multicore ? kernel.CurrentPhysicalCoreIndex() : 0; 181 auto core = is_multicore ? kernel.CurrentPhysicalCoreIndex() : 0;
187 auto* current_thread = kernel.GetCurrentEmuThread();
188 182
189 Common::Fiber::YieldTo(current_thread->GetHostContext(), *core_data[core].host_context); 183 Common::Fiber::YieldTo(thread->GetHostContext(), *core_data[core].host_context);
190 UNREACHABLE(); 184 UNREACHABLE();
191} 185}
192 186
@@ -218,9 +212,12 @@ void CpuManager::RunThread(std::size_t core) {
218 system.GPU().ObtainContext(); 212 system.GPU().ObtainContext();
219 } 213 }
220 214
221 auto* current_thread = system.Kernel().CurrentScheduler()->GetIdleThread(); 215 auto& kernel = system.Kernel();
222 Kernel::SetCurrentThread(system.Kernel(), current_thread); 216 auto& scheduler = *kernel.CurrentScheduler();
223 Common::Fiber::YieldTo(data.host_context, *current_thread->GetHostContext()); 217 auto* thread = scheduler.GetSchedulerCurrentThread();
218 Kernel::SetCurrentThread(kernel, thread);
219
220 Common::Fiber::YieldTo(data.host_context, *thread->GetHostContext());
224} 221}
225 222
226} // namespace Core 223} // namespace Core