SvcThread.cs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464
  1. using ChocolArm64.State;
  2. using Ryujinx.Common.Logging;
  3. using static Ryujinx.HLE.HOS.ErrorCode;
  4. namespace Ryujinx.HLE.HOS.Kernel
  5. {
  6. partial class SvcHandler
  7. {
  8. private void CreateThread64(CpuThreadState threadState)
  9. {
  10. ulong entrypoint = threadState.X1;
  11. ulong argsPtr = threadState.X2;
  12. ulong stackTop = threadState.X3;
  13. int priority = (int)threadState.X4;
  14. int cpuCore = (int)threadState.X5;
  15. KernelResult result = CreateThread(entrypoint, argsPtr, stackTop, priority, cpuCore, out int handle);
  16. threadState.X0 = (ulong)result;
  17. threadState.X1 = (ulong)handle;
  18. }
  19. private KernelResult CreateThread(
  20. ulong entrypoint,
  21. ulong argsPtr,
  22. ulong stackTop,
  23. int priority,
  24. int cpuCore,
  25. out int handle)
  26. {
  27. handle = 0;
  28. KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
  29. if (cpuCore == -2)
  30. {
  31. cpuCore = currentProcess.DefaultCpuCore;
  32. }
  33. if ((uint)cpuCore >= KScheduler.CpuCoresCount || !currentProcess.IsCpuCoreAllowed(cpuCore))
  34. {
  35. return KernelResult.InvalidCpuCore;
  36. }
  37. if ((uint)priority >= KScheduler.PrioritiesCount || !currentProcess.IsPriorityAllowed(priority))
  38. {
  39. return KernelResult.InvalidPriority;
  40. }
  41. long timeout = KTimeManager.ConvertMillisecondsToNanoseconds(100);
  42. if (currentProcess.ResourceLimit != null &&
  43. !currentProcess.ResourceLimit.Reserve(LimitableResource.Thread, 1, timeout))
  44. {
  45. return KernelResult.ResLimitExceeded;
  46. }
  47. KThread thread = new KThread(_system);
  48. KernelResult result = currentProcess.InitializeThread(
  49. thread,
  50. entrypoint,
  51. argsPtr,
  52. stackTop,
  53. priority,
  54. cpuCore);
  55. if (result != KernelResult.Success)
  56. {
  57. currentProcess.ResourceLimit?.Release(LimitableResource.Thread, 1);
  58. return result;
  59. }
  60. result = _process.HandleTable.GenerateHandle(thread, out handle);
  61. if (result != KernelResult.Success)
  62. {
  63. thread.Terminate();
  64. currentProcess.ResourceLimit?.Release(LimitableResource.Thread, 1);
  65. }
  66. return result;
  67. }
  68. private void SvcStartThread(CpuThreadState threadState)
  69. {
  70. int handle = (int)threadState.X0;
  71. KThread thread = _process.HandleTable.GetObject<KThread>(handle);
  72. if (thread != null)
  73. {
  74. KernelResult result = thread.Start();
  75. if (result != KernelResult.Success)
  76. {
  77. Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error \"{result}\".");
  78. }
  79. threadState.X0 = (ulong)result;
  80. }
  81. else
  82. {
  83. Logger.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{handle:x8}!");
  84. threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
  85. }
  86. }
  87. private void SvcExitThread(CpuThreadState threadState)
  88. {
  89. KThread currentThread = _system.Scheduler.GetCurrentThread();
  90. _system.Scheduler.ExitThread(currentThread);
  91. currentThread.Exit();
  92. }
  93. private void SvcSleepThread(CpuThreadState threadState)
  94. {
  95. long timeout = (long)threadState.X0;
  96. Logger.PrintDebug(LogClass.KernelSvc, "Timeout = 0x" + timeout.ToString("x16"));
  97. KThread currentThread = _system.Scheduler.GetCurrentThread();
  98. if (timeout < 1)
  99. {
  100. switch (timeout)
  101. {
  102. case 0: currentThread.Yield(); break;
  103. case -1: currentThread.YieldWithLoadBalancing(); break;
  104. case -2: currentThread.YieldAndWaitForLoadBalancing(); break;
  105. }
  106. }
  107. else
  108. {
  109. currentThread.Sleep(timeout);
  110. threadState.X0 = 0;
  111. }
  112. }
  113. private void SvcGetThreadPriority(CpuThreadState threadState)
  114. {
  115. int handle = (int)threadState.X1;
  116. KThread thread = _process.HandleTable.GetKThread(handle);
  117. if (thread != null)
  118. {
  119. threadState.X0 = 0;
  120. threadState.X1 = (ulong)thread.DynamicPriority;
  121. }
  122. else
  123. {
  124. Logger.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{handle:x8}!");
  125. threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
  126. }
  127. }
  128. private void SvcSetThreadPriority(CpuThreadState threadState)
  129. {
  130. int handle = (int)threadState.X0;
  131. int priority = (int)threadState.X1;
  132. Logger.PrintDebug(LogClass.KernelSvc,
  133. "Handle = 0x" + handle .ToString("x8") + ", " +
  134. "Priority = 0x" + priority.ToString("x8"));
  135. //TODO: NPDM check.
  136. KThread thread = _process.HandleTable.GetKThread(handle);
  137. if (thread == null)
  138. {
  139. Logger.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{handle:x8}!");
  140. threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
  141. return;
  142. }
  143. thread.SetPriority(priority);
  144. threadState.X0 = 0;
  145. }
  146. private void SvcGetThreadCoreMask(CpuThreadState threadState)
  147. {
  148. int handle = (int)threadState.X2;
  149. Logger.PrintDebug(LogClass.KernelSvc, "Handle = 0x" + handle.ToString("x8"));
  150. KThread thread = _process.HandleTable.GetKThread(handle);
  151. if (thread != null)
  152. {
  153. threadState.X0 = 0;
  154. threadState.X1 = (ulong)thread.PreferredCore;
  155. threadState.X2 = (ulong)thread.AffinityMask;
  156. }
  157. else
  158. {
  159. Logger.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{handle:x8}!");
  160. threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
  161. }
  162. }
  163. private void SetThreadCoreMask64(CpuThreadState threadState)
  164. {
  165. int handle = (int)threadState.X0;
  166. int preferredCore = (int)threadState.X1;
  167. long affinityMask = (long)threadState.X2;
  168. Logger.PrintDebug(LogClass.KernelSvc,
  169. "Handle = 0x" + handle .ToString("x8") + ", " +
  170. "PreferredCore = 0x" + preferredCore.ToString("x8") + ", " +
  171. "AffinityMask = 0x" + affinityMask .ToString("x16"));
  172. KernelResult result = SetThreadCoreMask(handle, preferredCore, affinityMask);
  173. if (result != KernelResult.Success)
  174. {
  175. Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error \"{result}\".");
  176. }
  177. threadState.X0 = (ulong)result;
  178. }
  179. private KernelResult SetThreadCoreMask(int handle, int preferredCore, long affinityMask)
  180. {
  181. KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
  182. if (preferredCore == -2)
  183. {
  184. preferredCore = currentProcess.DefaultCpuCore;
  185. affinityMask = 1 << preferredCore;
  186. }
  187. else
  188. {
  189. if ((currentProcess.Capabilities.AllowedCpuCoresMask | affinityMask) !=
  190. currentProcess.Capabilities.AllowedCpuCoresMask)
  191. {
  192. return KernelResult.InvalidCpuCore;
  193. }
  194. if (affinityMask == 0)
  195. {
  196. return KernelResult.InvalidCombination;
  197. }
  198. if ((uint)preferredCore > 3)
  199. {
  200. if ((preferredCore | 2) != -1)
  201. {
  202. return KernelResult.InvalidCpuCore;
  203. }
  204. }
  205. else if ((affinityMask & (1 << preferredCore)) == 0)
  206. {
  207. return KernelResult.InvalidCombination;
  208. }
  209. }
  210. KThread thread = _process.HandleTable.GetKThread(handle);
  211. if (thread == null)
  212. {
  213. return KernelResult.InvalidHandle;
  214. }
  215. return thread.SetCoreAndAffinityMask(preferredCore, affinityMask);
  216. }
  217. private void SvcGetCurrentProcessorNumber(CpuThreadState threadState)
  218. {
  219. threadState.X0 = (ulong)_system.Scheduler.GetCurrentThread().CurrentCore;
  220. }
  221. private void SvcGetThreadId(CpuThreadState threadState)
  222. {
  223. int handle = (int)threadState.X1;
  224. KThread thread = _process.HandleTable.GetKThread(handle);
  225. if (thread != null)
  226. {
  227. threadState.X0 = 0;
  228. threadState.X1 = (ulong)thread.ThreadUid;
  229. }
  230. else
  231. {
  232. Logger.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{handle:x8}!");
  233. threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
  234. }
  235. }
  236. private void SvcSetThreadActivity(CpuThreadState threadState)
  237. {
  238. int handle = (int)threadState.X0;
  239. bool pause = (int)threadState.X1 == 1;
  240. KThread thread = _process.HandleTable.GetObject<KThread>(handle);
  241. if (thread == null)
  242. {
  243. Logger.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{handle:x8}!");
  244. threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
  245. return;
  246. }
  247. if (thread.Owner != _system.Scheduler.GetCurrentProcess())
  248. {
  249. Logger.PrintWarning(LogClass.KernelSvc, $"Invalid thread, it belongs to another process.");
  250. threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
  251. return;
  252. }
  253. if (thread == _system.Scheduler.GetCurrentThread())
  254. {
  255. Logger.PrintWarning(LogClass.KernelSvc, "Invalid thread, current thread is not accepted.");
  256. threadState.X0 = (ulong)KernelResult.InvalidThread;
  257. return;
  258. }
  259. long result = thread.SetActivity(pause);
  260. if (result != 0)
  261. {
  262. Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{result:x}!");
  263. }
  264. threadState.X0 = (ulong)result;
  265. }
  266. private void SvcGetThreadContext3(CpuThreadState threadState)
  267. {
  268. long position = (long)threadState.X0;
  269. int handle = (int)threadState.X1;
  270. KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
  271. KThread currentThread = _system.Scheduler.GetCurrentThread();
  272. KThread thread = _process.HandleTable.GetObject<KThread>(handle);
  273. if (thread == null)
  274. {
  275. Logger.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{handle:x8}!");
  276. threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
  277. return;
  278. }
  279. if (thread.Owner != currentProcess)
  280. {
  281. Logger.PrintWarning(LogClass.KernelSvc, $"Invalid thread, it belongs to another process.");
  282. threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
  283. return;
  284. }
  285. if (currentThread == thread)
  286. {
  287. Logger.PrintWarning(LogClass.KernelSvc, "Invalid thread, current thread is not accepted.");
  288. threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidThread);
  289. return;
  290. }
  291. _memory.WriteUInt64(position + 0x0, thread.Context.ThreadState.X0);
  292. _memory.WriteUInt64(position + 0x8, thread.Context.ThreadState.X1);
  293. _memory.WriteUInt64(position + 0x10, thread.Context.ThreadState.X2);
  294. _memory.WriteUInt64(position + 0x18, thread.Context.ThreadState.X3);
  295. _memory.WriteUInt64(position + 0x20, thread.Context.ThreadState.X4);
  296. _memory.WriteUInt64(position + 0x28, thread.Context.ThreadState.X5);
  297. _memory.WriteUInt64(position + 0x30, thread.Context.ThreadState.X6);
  298. _memory.WriteUInt64(position + 0x38, thread.Context.ThreadState.X7);
  299. _memory.WriteUInt64(position + 0x40, thread.Context.ThreadState.X8);
  300. _memory.WriteUInt64(position + 0x48, thread.Context.ThreadState.X9);
  301. _memory.WriteUInt64(position + 0x50, thread.Context.ThreadState.X10);
  302. _memory.WriteUInt64(position + 0x58, thread.Context.ThreadState.X11);
  303. _memory.WriteUInt64(position + 0x60, thread.Context.ThreadState.X12);
  304. _memory.WriteUInt64(position + 0x68, thread.Context.ThreadState.X13);
  305. _memory.WriteUInt64(position + 0x70, thread.Context.ThreadState.X14);
  306. _memory.WriteUInt64(position + 0x78, thread.Context.ThreadState.X15);
  307. _memory.WriteUInt64(position + 0x80, thread.Context.ThreadState.X16);
  308. _memory.WriteUInt64(position + 0x88, thread.Context.ThreadState.X17);
  309. _memory.WriteUInt64(position + 0x90, thread.Context.ThreadState.X18);
  310. _memory.WriteUInt64(position + 0x98, thread.Context.ThreadState.X19);
  311. _memory.WriteUInt64(position + 0xa0, thread.Context.ThreadState.X20);
  312. _memory.WriteUInt64(position + 0xa8, thread.Context.ThreadState.X21);
  313. _memory.WriteUInt64(position + 0xb0, thread.Context.ThreadState.X22);
  314. _memory.WriteUInt64(position + 0xb8, thread.Context.ThreadState.X23);
  315. _memory.WriteUInt64(position + 0xc0, thread.Context.ThreadState.X24);
  316. _memory.WriteUInt64(position + 0xc8, thread.Context.ThreadState.X25);
  317. _memory.WriteUInt64(position + 0xd0, thread.Context.ThreadState.X26);
  318. _memory.WriteUInt64(position + 0xd8, thread.Context.ThreadState.X27);
  319. _memory.WriteUInt64(position + 0xe0, thread.Context.ThreadState.X28);
  320. _memory.WriteUInt64(position + 0xe8, thread.Context.ThreadState.X29);
  321. _memory.WriteUInt64(position + 0xf0, thread.Context.ThreadState.X30);
  322. _memory.WriteUInt64(position + 0xf8, thread.Context.ThreadState.X31);
  323. _memory.WriteInt64(position + 0x100, thread.LastPc);
  324. _memory.WriteUInt64(position + 0x108, (ulong)thread.Context.ThreadState.Psr);
  325. _memory.WriteVector128(position + 0x110, thread.Context.ThreadState.V0);
  326. _memory.WriteVector128(position + 0x120, thread.Context.ThreadState.V1);
  327. _memory.WriteVector128(position + 0x130, thread.Context.ThreadState.V2);
  328. _memory.WriteVector128(position + 0x140, thread.Context.ThreadState.V3);
  329. _memory.WriteVector128(position + 0x150, thread.Context.ThreadState.V4);
  330. _memory.WriteVector128(position + 0x160, thread.Context.ThreadState.V5);
  331. _memory.WriteVector128(position + 0x170, thread.Context.ThreadState.V6);
  332. _memory.WriteVector128(position + 0x180, thread.Context.ThreadState.V7);
  333. _memory.WriteVector128(position + 0x190, thread.Context.ThreadState.V8);
  334. _memory.WriteVector128(position + 0x1a0, thread.Context.ThreadState.V9);
  335. _memory.WriteVector128(position + 0x1b0, thread.Context.ThreadState.V10);
  336. _memory.WriteVector128(position + 0x1c0, thread.Context.ThreadState.V11);
  337. _memory.WriteVector128(position + 0x1d0, thread.Context.ThreadState.V12);
  338. _memory.WriteVector128(position + 0x1e0, thread.Context.ThreadState.V13);
  339. _memory.WriteVector128(position + 0x1f0, thread.Context.ThreadState.V14);
  340. _memory.WriteVector128(position + 0x200, thread.Context.ThreadState.V15);
  341. _memory.WriteVector128(position + 0x210, thread.Context.ThreadState.V16);
  342. _memory.WriteVector128(position + 0x220, thread.Context.ThreadState.V17);
  343. _memory.WriteVector128(position + 0x230, thread.Context.ThreadState.V18);
  344. _memory.WriteVector128(position + 0x240, thread.Context.ThreadState.V19);
  345. _memory.WriteVector128(position + 0x250, thread.Context.ThreadState.V20);
  346. _memory.WriteVector128(position + 0x260, thread.Context.ThreadState.V21);
  347. _memory.WriteVector128(position + 0x270, thread.Context.ThreadState.V22);
  348. _memory.WriteVector128(position + 0x280, thread.Context.ThreadState.V23);
  349. _memory.WriteVector128(position + 0x290, thread.Context.ThreadState.V24);
  350. _memory.WriteVector128(position + 0x2a0, thread.Context.ThreadState.V25);
  351. _memory.WriteVector128(position + 0x2b0, thread.Context.ThreadState.V26);
  352. _memory.WriteVector128(position + 0x2c0, thread.Context.ThreadState.V27);
  353. _memory.WriteVector128(position + 0x2d0, thread.Context.ThreadState.V28);
  354. _memory.WriteVector128(position + 0x2e0, thread.Context.ThreadState.V29);
  355. _memory.WriteVector128(position + 0x2f0, thread.Context.ThreadState.V30);
  356. _memory.WriteVector128(position + 0x300, thread.Context.ThreadState.V31);
  357. _memory.WriteInt32(position + 0x310, thread.Context.ThreadState.Fpcr);
  358. _memory.WriteInt32(position + 0x314, thread.Context.ThreadState.Fpsr);
  359. _memory.WriteInt64(position + 0x318, thread.Context.ThreadState.Tpidr);
  360. threadState.X0 = 0;
  361. }
  362. }
  363. }