SvcThreadSync.cs 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. using Ryujinx.HLE.HOS.Kernel.Common;
  2. using Ryujinx.HLE.HOS.Kernel.Process;
  3. using Ryujinx.HLE.HOS.Kernel.Threading;
  4. using System.Collections.Generic;
  5. namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
  6. {
  7. partial class SvcHandler
  8. {
  9. public KernelResult WaitSynchronization64([R(1)] ulong handlesPtr, [R(2)] int handlesCount, [R(3)] long timeout, [R(1)] out int handleIndex)
  10. {
  11. return WaitSynchronization(handlesPtr, handlesCount, timeout, out handleIndex);
  12. }
  13. public KernelResult WaitSynchronization32(
  14. [R(0)] uint timeoutLow,
  15. [R(1)] uint handlesPtr,
  16. [R(2)] int handlesCount,
  17. [R(3)] uint timeoutHigh,
  18. [R(1)] out int handleIndex)
  19. {
  20. long timeout = (long)(timeoutLow | ((ulong)timeoutHigh << 32));
  21. return WaitSynchronization(handlesPtr, handlesCount, timeout, out handleIndex);
  22. }
  23. private KernelResult WaitSynchronization(ulong handlesPtr, int handlesCount, long timeout, out int handleIndex)
  24. {
  25. handleIndex = 0;
  26. if ((uint)handlesCount > 0x40)
  27. {
  28. return KernelResult.MaximumExceeded;
  29. }
  30. List<KSynchronizationObject> syncObjs = new List<KSynchronizationObject>();
  31. for (int index = 0; index < handlesCount; index++)
  32. {
  33. int handle = _process.CpuMemory.ReadInt32((long)handlesPtr + index * 4);
  34. KSynchronizationObject syncObj = _process.HandleTable.GetObject<KSynchronizationObject>(handle);
  35. if (syncObj == null)
  36. {
  37. break;
  38. }
  39. syncObjs.Add(syncObj);
  40. }
  41. return _system.Synchronization.WaitFor(syncObjs.ToArray(), timeout, out handleIndex);
  42. }
  43. public KernelResult CancelSynchronization64([R(0)] int handle)
  44. {
  45. return CancelSynchronization(handle);
  46. }
  47. public KernelResult CancelSynchronization32([R(0)] int handle)
  48. {
  49. return CancelSynchronization(handle);
  50. }
  51. private KernelResult CancelSynchronization(int handle)
  52. {
  53. KThread thread = _process.HandleTable.GetKThread(handle);
  54. if (thread == null)
  55. {
  56. return KernelResult.InvalidHandle;
  57. }
  58. thread.CancelSynchronization();
  59. return KernelResult.Success;
  60. }
  61. public KernelResult ArbitrateLock64([R(0)] int ownerHandle, [R(1)] ulong mutexAddress, [R(2)] int requesterHandle)
  62. {
  63. return ArbitrateLock(ownerHandle, mutexAddress, requesterHandle);
  64. }
  65. public KernelResult ArbitrateLock32([R(0)] int ownerHandle, [R(1)] uint mutexAddress, [R(2)] int requesterHandle)
  66. {
  67. return ArbitrateLock(ownerHandle, mutexAddress, requesterHandle);
  68. }
  69. private KernelResult ArbitrateLock(int ownerHandle, ulong mutexAddress, int requesterHandle)
  70. {
  71. if (IsPointingInsideKernel(mutexAddress))
  72. {
  73. return KernelResult.InvalidMemState;
  74. }
  75. if (IsAddressNotWordAligned(mutexAddress))
  76. {
  77. return KernelResult.InvalidAddress;
  78. }
  79. KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
  80. return currentProcess.AddressArbiter.ArbitrateLock(ownerHandle, mutexAddress, requesterHandle);
  81. }
  82. public KernelResult ArbitrateUnlock64([R(0)] ulong mutexAddress)
  83. {
  84. return ArbitrateUnlock(mutexAddress);
  85. }
  86. public KernelResult ArbitrateUnlock32([R(0)] uint mutexAddress)
  87. {
  88. return ArbitrateUnlock(mutexAddress);
  89. }
  90. private KernelResult ArbitrateUnlock(ulong mutexAddress)
  91. {
  92. if (IsPointingInsideKernel(mutexAddress))
  93. {
  94. return KernelResult.InvalidMemState;
  95. }
  96. if (IsAddressNotWordAligned(mutexAddress))
  97. {
  98. return KernelResult.InvalidAddress;
  99. }
  100. KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
  101. return currentProcess.AddressArbiter.ArbitrateUnlock(mutexAddress);
  102. }
  103. public KernelResult WaitProcessWideKeyAtomic64(
  104. [R(0)] ulong mutexAddress,
  105. [R(1)] ulong condVarAddress,
  106. [R(2)] int handle,
  107. [R(3)] long timeout)
  108. {
  109. return WaitProcessWideKeyAtomic(mutexAddress, condVarAddress, handle, timeout);
  110. }
  111. public KernelResult WaitProcessWideKeyAtomic32(
  112. [R(0)] uint mutexAddress,
  113. [R(1)] uint condVarAddress,
  114. [R(2)] int handle,
  115. [R(3)] uint timeoutLow,
  116. [R(4)] uint timeoutHigh)
  117. {
  118. long timeout = (long)(timeoutLow | ((ulong)timeoutHigh << 32));
  119. return WaitProcessWideKeyAtomic(mutexAddress, condVarAddress, handle, timeout);
  120. }
  121. private KernelResult WaitProcessWideKeyAtomic(
  122. ulong mutexAddress,
  123. ulong condVarAddress,
  124. int handle,
  125. long timeout)
  126. {
  127. if (IsPointingInsideKernel(mutexAddress))
  128. {
  129. return KernelResult.InvalidMemState;
  130. }
  131. if (IsAddressNotWordAligned(mutexAddress))
  132. {
  133. return KernelResult.InvalidAddress;
  134. }
  135. KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
  136. return currentProcess.AddressArbiter.WaitProcessWideKeyAtomic(
  137. mutexAddress,
  138. condVarAddress,
  139. handle,
  140. timeout);
  141. }
  142. public KernelResult SignalProcessWideKey64([R(0)] ulong address, [R(1)] int count)
  143. {
  144. return SignalProcessWideKey(address, count);
  145. }
  146. public KernelResult SignalProcessWideKey32([R(0)] uint address, [R(1)] int count)
  147. {
  148. return SignalProcessWideKey(address, count);
  149. }
  150. private KernelResult SignalProcessWideKey(ulong address, int count)
  151. {
  152. KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
  153. currentProcess.AddressArbiter.SignalProcessWideKey(address, count);
  154. return KernelResult.Success;
  155. }
  156. public KernelResult WaitForAddress64([R(0)] ulong address, [R(1)] ArbitrationType type, [R(2)] int value, [R(3)] long timeout)
  157. {
  158. return WaitForAddress(address, type, value, timeout);
  159. }
  160. public KernelResult WaitForAddress32([R(0)] uint address, [R(1)] ArbitrationType type, [R(2)] int value, [R(3)] uint timeoutLow, [R(4)] uint timeoutHigh)
  161. {
  162. long timeout = (long)(timeoutLow | ((ulong)timeoutHigh << 32));
  163. return WaitForAddress(address, type, value, timeout);
  164. }
  165. private KernelResult WaitForAddress(ulong address, ArbitrationType type, int value, long timeout)
  166. {
  167. if (IsPointingInsideKernel(address))
  168. {
  169. return KernelResult.InvalidMemState;
  170. }
  171. if (IsAddressNotWordAligned(address))
  172. {
  173. return KernelResult.InvalidAddress;
  174. }
  175. KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
  176. KernelResult result;
  177. switch (type)
  178. {
  179. case ArbitrationType.WaitIfLessThan:
  180. result = currentProcess.AddressArbiter.WaitForAddressIfLessThan(address, value, false, timeout);
  181. break;
  182. case ArbitrationType.DecrementAndWaitIfLessThan:
  183. result = currentProcess.AddressArbiter.WaitForAddressIfLessThan(address, value, true, timeout);
  184. break;
  185. case ArbitrationType.WaitIfEqual:
  186. result = currentProcess.AddressArbiter.WaitForAddressIfEqual(address, value, timeout);
  187. break;
  188. default:
  189. result = KernelResult.InvalidEnumValue;
  190. break;
  191. }
  192. return result;
  193. }
  194. public KernelResult SignalToAddress64([R(0)] ulong address, [R(1)] SignalType type, [R(2)] int value, [R(3)] int count)
  195. {
  196. return SignalToAddress(address, type, value, count);
  197. }
  198. public KernelResult SignalToAddress32([R(0)] uint address, [R(1)] SignalType type, [R(2)] int value, [R(3)] int count)
  199. {
  200. return SignalToAddress(address, type, value, count);
  201. }
  202. private KernelResult SignalToAddress(ulong address, SignalType type, int value, int count)
  203. {
  204. if (IsPointingInsideKernel(address))
  205. {
  206. return KernelResult.InvalidMemState;
  207. }
  208. if (IsAddressNotWordAligned(address))
  209. {
  210. return KernelResult.InvalidAddress;
  211. }
  212. KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
  213. KernelResult result;
  214. switch (type)
  215. {
  216. case SignalType.Signal:
  217. result = currentProcess.AddressArbiter.Signal(address, count);
  218. break;
  219. case SignalType.SignalAndIncrementIfEqual:
  220. result = currentProcess.AddressArbiter.SignalAndIncrementIfEqual(address, value, count);
  221. break;
  222. case SignalType.SignalAndModifyIfEqual:
  223. result = currentProcess.AddressArbiter.SignalAndModifyIfEqual(address, value, count);
  224. break;
  225. default:
  226. result = KernelResult.InvalidEnumValue;
  227. break;
  228. }
  229. return result;
  230. }
  231. private bool IsPointingInsideKernel(ulong address)
  232. {
  233. return (address + 0x1000000000) < 0xffffff000;
  234. }
  235. private bool IsAddressNotWordAligned(ulong address)
  236. {
  237. return (address & 3) != 0;
  238. }
  239. }
  240. }