k_address_arbiter.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  1. // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include "core/arm/exclusive_monitor.h"
  4. #include "core/core.h"
  5. #include "core/hle/kernel/k_address_arbiter.h"
  6. #include "core/hle/kernel/k_scheduler.h"
  7. #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
  8. #include "core/hle/kernel/k_thread.h"
  9. #include "core/hle/kernel/k_thread_queue.h"
  10. #include "core/hle/kernel/kernel.h"
  11. #include "core/hle/kernel/svc_results.h"
  12. #include "core/hle/kernel/time_manager.h"
  13. #include "core/memory.h"
  14. namespace Kernel {
  15. KAddressArbiter::KAddressArbiter(Core::System& system_)
  16. : system{system_}, kernel{system.Kernel()} {}
  17. KAddressArbiter::~KAddressArbiter() = default;
  18. namespace {
  19. bool ReadFromUser(Core::System& system, s32* out, VAddr address) {
  20. *out = system.Memory().Read32(address);
  21. return true;
  22. }
  23. bool DecrementIfLessThan(Core::System& system, s32* out, VAddr address, s32 value) {
  24. auto& monitor = system.Monitor();
  25. const auto current_core = system.Kernel().CurrentPhysicalCoreIndex();
  26. // TODO(bunnei): We should disable interrupts here via KScopedInterruptDisable.
  27. // TODO(bunnei): We should call CanAccessAtomic(..) here.
  28. // Load the value from the address.
  29. const s32 current_value = static_cast<s32>(monitor.ExclusiveRead32(current_core, address));
  30. // Compare it to the desired one.
  31. if (current_value < value) {
  32. // If less than, we want to try to decrement.
  33. const s32 decrement_value = current_value - 1;
  34. // Decrement and try to store.
  35. if (!monitor.ExclusiveWrite32(current_core, address, static_cast<u32>(decrement_value))) {
  36. // If we failed to store, try again.
  37. DecrementIfLessThan(system, out, address, value);
  38. }
  39. } else {
  40. // Otherwise, clear our exclusive hold and finish
  41. monitor.ClearExclusive(current_core);
  42. }
  43. // We're done.
  44. *out = current_value;
  45. return true;
  46. }
  47. bool UpdateIfEqual(Core::System& system, s32* out, VAddr address, s32 value, s32 new_value) {
  48. auto& monitor = system.Monitor();
  49. const auto current_core = system.Kernel().CurrentPhysicalCoreIndex();
  50. // TODO(bunnei): We should disable interrupts here via KScopedInterruptDisable.
  51. // TODO(bunnei): We should call CanAccessAtomic(..) here.
  52. // Load the value from the address.
  53. const s32 current_value = static_cast<s32>(monitor.ExclusiveRead32(current_core, address));
  54. // Compare it to the desired one.
  55. if (current_value == value) {
  56. // If equal, we want to try to write the new value.
  57. // Try to store.
  58. if (!monitor.ExclusiveWrite32(current_core, address, static_cast<u32>(new_value))) {
  59. // If we failed to store, try again.
  60. UpdateIfEqual(system, out, address, value, new_value);
  61. }
  62. } else {
  63. // Otherwise, clear our exclusive hold and finish.
  64. monitor.ClearExclusive(current_core);
  65. }
  66. // We're done.
  67. *out = current_value;
  68. return true;
  69. }
  70. class ThreadQueueImplForKAddressArbiter final : public KThreadQueue {
  71. public:
  72. explicit ThreadQueueImplForKAddressArbiter(KernelCore& kernel_, KAddressArbiter::ThreadTree* t)
  73. : KThreadQueue(kernel_), m_tree(t) {}
  74. void CancelWait(KThread* waiting_thread, Result wait_result, bool cancel_timer_task) override {
  75. // If the thread is waiting on an address arbiter, remove it from the tree.
  76. if (waiting_thread->IsWaitingForAddressArbiter()) {
  77. m_tree->erase(m_tree->iterator_to(*waiting_thread));
  78. waiting_thread->ClearAddressArbiter();
  79. }
  80. // Invoke the base cancel wait handler.
  81. KThreadQueue::CancelWait(waiting_thread, wait_result, cancel_timer_task);
  82. }
  83. private:
  84. KAddressArbiter::ThreadTree* m_tree;
  85. };
  86. } // namespace
  87. Result KAddressArbiter::Signal(VAddr addr, s32 count) {
  88. // Perform signaling.
  89. s32 num_waiters{};
  90. {
  91. KScopedSchedulerLock sl(kernel);
  92. auto it = thread_tree.nfind_key({addr, -1});
  93. while ((it != thread_tree.end()) && (count <= 0 || num_waiters < count) &&
  94. (it->GetAddressArbiterKey() == addr)) {
  95. // End the thread's wait.
  96. KThread* target_thread = std::addressof(*it);
  97. target_thread->EndWait(ResultSuccess);
  98. ASSERT(target_thread->IsWaitingForAddressArbiter());
  99. target_thread->ClearAddressArbiter();
  100. it = thread_tree.erase(it);
  101. ++num_waiters;
  102. }
  103. }
  104. return ResultSuccess;
  105. }
  106. Result KAddressArbiter::SignalAndIncrementIfEqual(VAddr addr, s32 value, s32 count) {
  107. // Perform signaling.
  108. s32 num_waiters{};
  109. {
  110. KScopedSchedulerLock sl(kernel);
  111. // Check the userspace value.
  112. s32 user_value{};
  113. if (!UpdateIfEqual(system, &user_value, addr, value, value + 1)) {
  114. LOG_ERROR(Kernel, "Invalid current memory!");
  115. return ResultInvalidCurrentMemory;
  116. }
  117. if (user_value != value) {
  118. return ResultInvalidState;
  119. }
  120. auto it = thread_tree.nfind_key({addr, -1});
  121. while ((it != thread_tree.end()) && (count <= 0 || num_waiters < count) &&
  122. (it->GetAddressArbiterKey() == addr)) {
  123. // End the thread's wait.
  124. KThread* target_thread = std::addressof(*it);
  125. target_thread->EndWait(ResultSuccess);
  126. ASSERT(target_thread->IsWaitingForAddressArbiter());
  127. target_thread->ClearAddressArbiter();
  128. it = thread_tree.erase(it);
  129. ++num_waiters;
  130. }
  131. }
  132. return ResultSuccess;
  133. }
  134. Result KAddressArbiter::SignalAndModifyByWaitingCountIfEqual(VAddr addr, s32 value, s32 count) {
  135. // Perform signaling.
  136. s32 num_waiters{};
  137. {
  138. [[maybe_unused]] const KScopedSchedulerLock sl(kernel);
  139. auto it = thread_tree.nfind_key({addr, -1});
  140. // Determine the updated value.
  141. s32 new_value{};
  142. if (count <= 0) {
  143. if (it != thread_tree.end() && it->GetAddressArbiterKey() == addr) {
  144. new_value = value - 2;
  145. } else {
  146. new_value = value + 1;
  147. }
  148. } else {
  149. if (it != thread_tree.end() && it->GetAddressArbiterKey() == addr) {
  150. auto tmp_it = it;
  151. s32 tmp_num_waiters{};
  152. while (++tmp_it != thread_tree.end() && tmp_it->GetAddressArbiterKey() == addr) {
  153. if (tmp_num_waiters++ >= count) {
  154. break;
  155. }
  156. }
  157. if (tmp_num_waiters < count) {
  158. new_value = value - 1;
  159. } else {
  160. new_value = value;
  161. }
  162. } else {
  163. new_value = value + 1;
  164. }
  165. }
  166. // Check the userspace value.
  167. s32 user_value{};
  168. bool succeeded{};
  169. if (value != new_value) {
  170. succeeded = UpdateIfEqual(system, &user_value, addr, value, new_value);
  171. } else {
  172. succeeded = ReadFromUser(system, &user_value, addr);
  173. }
  174. if (!succeeded) {
  175. LOG_ERROR(Kernel, "Invalid current memory!");
  176. return ResultInvalidCurrentMemory;
  177. }
  178. if (user_value != value) {
  179. return ResultInvalidState;
  180. }
  181. while ((it != thread_tree.end()) && (count <= 0 || num_waiters < count) &&
  182. (it->GetAddressArbiterKey() == addr)) {
  183. // End the thread's wait.
  184. KThread* target_thread = std::addressof(*it);
  185. target_thread->EndWait(ResultSuccess);
  186. ASSERT(target_thread->IsWaitingForAddressArbiter());
  187. target_thread->ClearAddressArbiter();
  188. it = thread_tree.erase(it);
  189. ++num_waiters;
  190. }
  191. }
  192. return ResultSuccess;
  193. }
  194. Result KAddressArbiter::WaitIfLessThan(VAddr addr, s32 value, bool decrement, s64 timeout) {
  195. // Prepare to wait.
  196. KThread* cur_thread = GetCurrentThreadPointer(kernel);
  197. ThreadQueueImplForKAddressArbiter wait_queue(kernel, std::addressof(thread_tree));
  198. {
  199. KScopedSchedulerLockAndSleep slp{kernel, cur_thread, timeout};
  200. // Check that the thread isn't terminating.
  201. if (cur_thread->IsTerminationRequested()) {
  202. slp.CancelSleep();
  203. return ResultTerminationRequested;
  204. }
  205. // Read the value from userspace.
  206. s32 user_value{};
  207. bool succeeded{};
  208. if (decrement) {
  209. succeeded = DecrementIfLessThan(system, &user_value, addr, value);
  210. } else {
  211. succeeded = ReadFromUser(system, &user_value, addr);
  212. }
  213. if (!succeeded) {
  214. slp.CancelSleep();
  215. return ResultInvalidCurrentMemory;
  216. }
  217. // Check that the value is less than the specified one.
  218. if (user_value >= value) {
  219. slp.CancelSleep();
  220. return ResultInvalidState;
  221. }
  222. // Check that the timeout is non-zero.
  223. if (timeout == 0) {
  224. slp.CancelSleep();
  225. return ResultTimedOut;
  226. }
  227. // Set the arbiter.
  228. cur_thread->SetAddressArbiter(&thread_tree, addr);
  229. thread_tree.insert(*cur_thread);
  230. // Wait for the thread to finish.
  231. cur_thread->BeginWait(std::addressof(wait_queue));
  232. cur_thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::Arbitration);
  233. }
  234. // Get the result.
  235. return cur_thread->GetWaitResult();
  236. }
  237. Result KAddressArbiter::WaitIfEqual(VAddr addr, s32 value, s64 timeout) {
  238. // Prepare to wait.
  239. KThread* cur_thread = GetCurrentThreadPointer(kernel);
  240. ThreadQueueImplForKAddressArbiter wait_queue(kernel, std::addressof(thread_tree));
  241. {
  242. KScopedSchedulerLockAndSleep slp{kernel, cur_thread, timeout};
  243. // Check that the thread isn't terminating.
  244. if (cur_thread->IsTerminationRequested()) {
  245. slp.CancelSleep();
  246. return ResultTerminationRequested;
  247. }
  248. // Read the value from userspace.
  249. s32 user_value{};
  250. if (!ReadFromUser(system, &user_value, addr)) {
  251. slp.CancelSleep();
  252. return ResultInvalidCurrentMemory;
  253. }
  254. // Check that the value is equal.
  255. if (value != user_value) {
  256. slp.CancelSleep();
  257. return ResultInvalidState;
  258. }
  259. // Check that the timeout is non-zero.
  260. if (timeout == 0) {
  261. slp.CancelSleep();
  262. return ResultTimedOut;
  263. }
  264. // Set the arbiter.
  265. cur_thread->SetAddressArbiter(&thread_tree, addr);
  266. thread_tree.insert(*cur_thread);
  267. // Wait for the thread to finish.
  268. cur_thread->BeginWait(std::addressof(wait_queue));
  269. cur_thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::Arbitration);
  270. }
  271. // Get the result.
  272. return cur_thread->GetWaitResult();
  273. }
  274. } // namespace Kernel