k_address_arbiter.cpp 11 KB

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