k_address_arbiter.cpp 11 KB

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