physical_core.cpp 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include "common/scope_exit.h"
  4. #include "common/settings.h"
  5. #include "core/core.h"
  6. #include "core/debugger/debugger.h"
  7. #include "core/hle/kernel/k_process.h"
  8. #include "core/hle/kernel/k_thread.h"
  9. #include "core/hle/kernel/kernel.h"
  10. #include "core/hle/kernel/physical_core.h"
  11. #include "core/hle/kernel/svc.h"
  12. namespace Kernel {
  13. PhysicalCore::PhysicalCore(KernelCore& kernel, std::size_t core_index)
  14. : m_kernel{kernel}, m_core_index{core_index} {
  15. m_is_single_core = !kernel.IsMulticore();
  16. }
  17. PhysicalCore::~PhysicalCore() = default;
  18. void PhysicalCore::RunThread(Kernel::KThread* thread) {
  19. auto* process = thread->GetOwnerProcess();
  20. auto& system = m_kernel.System();
  21. auto* interface = process->GetArmInterface(m_core_index);
  22. interface->Initialize();
  23. const auto EnterContext = [&]() {
  24. system.EnterCPUProfile();
  25. // Lock the core context.
  26. std::scoped_lock lk{m_guard};
  27. // Check if we are already interrupted. If we are, we can just stop immediately.
  28. if (m_is_interrupted) {
  29. return false;
  30. }
  31. // Mark that we are running.
  32. m_arm_interface = interface;
  33. m_current_thread = thread;
  34. // Acquire the lock on the thread parameters.
  35. // This allows us to force synchronization with Interrupt.
  36. interface->LockThread(thread);
  37. return true;
  38. };
  39. const auto ExitContext = [&]() {
  40. // Unlock the thread.
  41. interface->UnlockThread(thread);
  42. // Lock the core context.
  43. std::scoped_lock lk{m_guard};
  44. // On exit, we no longer are running.
  45. m_arm_interface = nullptr;
  46. m_current_thread = nullptr;
  47. system.ExitCPUProfile();
  48. };
  49. while (true) {
  50. // If the thread is scheduled for termination, exit.
  51. if (thread->HasDpc() && thread->IsTerminationRequested()) {
  52. thread->Exit();
  53. }
  54. // Notify the debugger and go to sleep if a step was performed
  55. // and this thread has been scheduled again.
  56. if (thread->GetStepState() == StepState::StepPerformed) {
  57. system.GetDebugger().NotifyThreadStopped(thread);
  58. thread->RequestSuspend(SuspendType::Debug);
  59. return;
  60. }
  61. // Otherwise, run the thread.
  62. Core::HaltReason hr{};
  63. {
  64. // If we were interrupted, exit immediately.
  65. if (!EnterContext()) {
  66. return;
  67. }
  68. if (thread->GetStepState() == StepState::StepPending) {
  69. hr = interface->StepThread(thread);
  70. if (True(hr & Core::HaltReason::StepThread)) {
  71. thread->SetStepState(StepState::StepPerformed);
  72. }
  73. } else {
  74. hr = interface->RunThread(thread);
  75. }
  76. ExitContext();
  77. }
  78. // Determine why we stopped.
  79. const bool supervisor_call = True(hr & Core::HaltReason::SupervisorCall);
  80. const bool prefetch_abort = True(hr & Core::HaltReason::PrefetchAbort);
  81. const bool breakpoint = True(hr & Core::HaltReason::InstructionBreakpoint);
  82. const bool data_abort = True(hr & Core::HaltReason::DataAbort);
  83. const bool interrupt = True(hr & Core::HaltReason::BreakLoop);
  84. // Since scheduling may occur here, we cannot use any cached
  85. // state after returning from calls we make.
  86. // Notify the debugger and go to sleep if a breakpoint was hit,
  87. // or if the thread is unable to continue for any reason.
  88. if (breakpoint || prefetch_abort) {
  89. if (breakpoint) {
  90. interface->RewindBreakpointInstruction();
  91. }
  92. if (system.DebuggerEnabled()) {
  93. system.GetDebugger().NotifyThreadStopped(thread);
  94. } else {
  95. interface->LogBacktrace(process);
  96. }
  97. thread->RequestSuspend(SuspendType::Debug);
  98. return;
  99. }
  100. // Notify the debugger and go to sleep on data abort.
  101. if (data_abort) {
  102. if (system.DebuggerEnabled()) {
  103. system.GetDebugger().NotifyThreadWatchpoint(thread, *interface->HaltedWatchpoint());
  104. }
  105. thread->RequestSuspend(SuspendType::Debug);
  106. return;
  107. }
  108. // Handle system calls.
  109. if (supervisor_call) {
  110. // Perform call.
  111. Svc::Call(system, interface->GetSvcNumber());
  112. return;
  113. }
  114. // Handle external interrupt sources.
  115. if (interrupt || !m_is_single_core) {
  116. return;
  117. }
  118. }
  119. }
  120. void PhysicalCore::LoadContext(const KThread* thread) {
  121. auto* const process = thread->GetOwnerProcess();
  122. if (!process) {
  123. // Kernel threads do not run on emulated CPU cores.
  124. return;
  125. }
  126. auto* interface = process->GetArmInterface(m_core_index);
  127. if (interface) {
  128. interface->SetContext(thread->GetContext());
  129. interface->SetTpidrroEl0(GetInteger(thread->GetTlsAddress()));
  130. interface->SetWatchpointArray(&process->GetWatchpoints());
  131. }
  132. }
  133. void PhysicalCore::LoadSvcArguments(const KProcess& process, std::span<const uint64_t, 8> args) {
  134. process.GetArmInterface(m_core_index)->SetSvcArguments(args);
  135. }
  136. void PhysicalCore::SaveContext(KThread* thread) const {
  137. auto* const process = thread->GetOwnerProcess();
  138. if (!process) {
  139. // Kernel threads do not run on emulated CPU cores.
  140. return;
  141. }
  142. auto* interface = process->GetArmInterface(m_core_index);
  143. if (interface) {
  144. interface->GetContext(thread->GetContext());
  145. }
  146. }
  147. void PhysicalCore::SaveSvcArguments(KProcess& process, std::span<uint64_t, 8> args) const {
  148. process.GetArmInterface(m_core_index)->GetSvcArguments(args);
  149. }
  150. void PhysicalCore::CloneFpuStatus(KThread* dst) const {
  151. auto* process = dst->GetOwnerProcess();
  152. Svc::ThreadContext ctx{};
  153. process->GetArmInterface(m_core_index)->GetContext(ctx);
  154. dst->GetContext().fpcr = ctx.fpcr;
  155. dst->GetContext().fpsr = ctx.fpsr;
  156. }
  157. void PhysicalCore::LogBacktrace() {
  158. auto* process = GetCurrentProcessPointer(m_kernel);
  159. if (!process) {
  160. return;
  161. }
  162. auto* interface = process->GetArmInterface(m_core_index);
  163. if (interface) {
  164. interface->LogBacktrace(process);
  165. }
  166. }
  167. void PhysicalCore::Idle() {
  168. std::unique_lock lk{m_guard};
  169. m_on_interrupt.wait(lk, [this] { return m_is_interrupted; });
  170. }
  171. bool PhysicalCore::IsInterrupted() const {
  172. return m_is_interrupted;
  173. }
  174. void PhysicalCore::Interrupt() {
  175. // Lock core context.
  176. std::scoped_lock lk{m_guard};
  177. // Load members.
  178. auto* arm_interface = m_arm_interface;
  179. auto* thread = m_current_thread;
  180. // Add interrupt flag.
  181. m_is_interrupted = true;
  182. // Interrupt ourselves.
  183. m_on_interrupt.notify_one();
  184. // If there is no thread running, we are done.
  185. if (arm_interface == nullptr) {
  186. return;
  187. }
  188. // Interrupt the CPU.
  189. arm_interface->SignalInterrupt(thread);
  190. }
  191. void PhysicalCore::ClearInterrupt() {
  192. std::scoped_lock lk{m_guard};
  193. m_is_interrupted = false;
  194. }
  195. } // namespace Kernel