SvcSystem.cs 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762
  1. using ChocolArm64.Memory;
  2. using Ryujinx.Common;
  3. using Ryujinx.Common.Logging;
  4. using Ryujinx.HLE.Exceptions;
  5. using Ryujinx.HLE.HOS.Ipc;
  6. using Ryujinx.HLE.HOS.Kernel.Common;
  7. using Ryujinx.HLE.HOS.Kernel.Ipc;
  8. using Ryujinx.HLE.HOS.Kernel.Memory;
  9. using Ryujinx.HLE.HOS.Kernel.Process;
  10. using Ryujinx.HLE.HOS.Kernel.Threading;
  11. using Ryujinx.HLE.HOS.Services;
  12. using System.Threading;
  13. namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
  14. {
  15. partial class SvcHandler
  16. {
  17. public void ExitProcess64()
  18. {
  19. ExitProcess();
  20. }
  21. private void ExitProcess()
  22. {
  23. _system.Scheduler.GetCurrentProcess().Terminate();
  24. }
  25. public KernelResult SignalEvent64(int handle)
  26. {
  27. return SignalEvent(handle);
  28. }
  29. private KernelResult SignalEvent(int handle)
  30. {
  31. KWritableEvent writableEvent = _process.HandleTable.GetObject<KWritableEvent>(handle);
  32. KernelResult result;
  33. if (writableEvent != null)
  34. {
  35. writableEvent.Signal();
  36. result = KernelResult.Success;
  37. }
  38. else
  39. {
  40. result = KernelResult.InvalidHandle;
  41. }
  42. return result;
  43. }
  44. public KernelResult ClearEvent64(int handle)
  45. {
  46. return ClearEvent(handle);
  47. }
  48. private KernelResult ClearEvent(int handle)
  49. {
  50. KernelResult result;
  51. KWritableEvent writableEvent = _process.HandleTable.GetObject<KWritableEvent>(handle);
  52. if (writableEvent == null)
  53. {
  54. KReadableEvent readableEvent = _process.HandleTable.GetObject<KReadableEvent>(handle);
  55. result = readableEvent?.Clear() ?? KernelResult.InvalidHandle;
  56. }
  57. else
  58. {
  59. result = writableEvent.Clear();
  60. }
  61. return result;
  62. }
  63. public KernelResult CloseHandle64(int handle)
  64. {
  65. return CloseHandle(handle);
  66. }
  67. private KernelResult CloseHandle(int handle)
  68. {
  69. object obj = _process.HandleTable.GetObject<object>(handle);
  70. _process.HandleTable.CloseHandle(handle);
  71. if (obj == null)
  72. {
  73. return KernelResult.InvalidHandle;
  74. }
  75. if (obj is KSession session)
  76. {
  77. session.Dispose();
  78. }
  79. else if (obj is KTransferMemory transferMemory)
  80. {
  81. _process.MemoryManager.ResetTransferMemory(
  82. transferMemory.Address,
  83. transferMemory.Size);
  84. }
  85. return KernelResult.Success;
  86. }
  87. public KernelResult ResetSignal64(int handle)
  88. {
  89. return ResetSignal(handle);
  90. }
  91. private KernelResult ResetSignal(int handle)
  92. {
  93. KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
  94. KReadableEvent readableEvent = currentProcess.HandleTable.GetObject<KReadableEvent>(handle);
  95. KernelResult result;
  96. if (readableEvent != null)
  97. {
  98. result = readableEvent.ClearIfSignaled();
  99. }
  100. else
  101. {
  102. KProcess process = currentProcess.HandleTable.GetKProcess(handle);
  103. if (process != null)
  104. {
  105. result = process.ClearIfNotExited();
  106. }
  107. else
  108. {
  109. result = KernelResult.InvalidHandle;
  110. }
  111. }
  112. return result;
  113. }
  114. public ulong GetSystemTick64()
  115. {
  116. return _system.Scheduler.GetCurrentThread().Context.ThreadState.CntpctEl0;
  117. }
  118. public KernelResult ConnectToNamedPort64(ulong namePtr, out int handle)
  119. {
  120. return ConnectToNamedPort(namePtr, out handle);
  121. }
  122. private KernelResult ConnectToNamedPort(ulong namePtr, out int handle)
  123. {
  124. string name = MemoryHelper.ReadAsciiString(_memory, (long)namePtr, 8);
  125. //TODO: Validate that app has perms to access the service, and that the service
  126. //actually exists, return error codes otherwise.
  127. KSession session = new KSession(ServiceFactory.MakeService(_system, name), name);
  128. return _process.HandleTable.GenerateHandle(session, out handle);
  129. }
  130. public KernelResult SendSyncRequest64(int handle)
  131. {
  132. return SendSyncRequest((ulong)_system.Scheduler.GetCurrentThread().Context.ThreadState.Tpidr, 0x100, handle);
  133. }
  134. public KernelResult SendSyncRequestWithUserBuffer64(ulong messagePtr, ulong size, int handle)
  135. {
  136. return SendSyncRequest(messagePtr, size, handle);
  137. }
  138. private KernelResult SendSyncRequest(ulong messagePtr, ulong size, int handle)
  139. {
  140. byte[] messageData = _memory.ReadBytes((long)messagePtr, (long)size);
  141. KSession session = _process.HandleTable.GetObject<KSession>(handle);
  142. if (session != null)
  143. {
  144. _system.CriticalSection.Enter();
  145. KThread currentThread = _system.Scheduler.GetCurrentThread();
  146. currentThread.SignaledObj = null;
  147. currentThread.ObjSyncResult = KernelResult.Success;
  148. currentThread.Reschedule(ThreadSchedState.Paused);
  149. IpcMessage message = new IpcMessage(messageData, (long)messagePtr);
  150. ThreadPool.QueueUserWorkItem(ProcessIpcRequest, new HleIpcMessage(
  151. currentThread,
  152. session,
  153. message,
  154. (long)messagePtr));
  155. _system.ThreadCounter.AddCount();
  156. _system.CriticalSection.Leave();
  157. return currentThread.ObjSyncResult;
  158. }
  159. else
  160. {
  161. Logger.PrintWarning(LogClass.KernelSvc, $"Invalid session handle 0x{handle:x8}!");
  162. return KernelResult.InvalidHandle;
  163. }
  164. }
  165. private void ProcessIpcRequest(object state)
  166. {
  167. HleIpcMessage ipcMessage = (HleIpcMessage)state;
  168. ipcMessage.Thread.ObjSyncResult = IpcHandler.IpcCall(
  169. _device,
  170. _process,
  171. _memory,
  172. ipcMessage.Session,
  173. ipcMessage.Message,
  174. ipcMessage.MessagePtr);
  175. _system.ThreadCounter.Signal();
  176. ipcMessage.Thread.Reschedule(ThreadSchedState.Running);
  177. }
  178. public KernelResult GetProcessId64(int handle, out long pid)
  179. {
  180. return GetProcessId(handle, out pid);
  181. }
  182. private KernelResult GetProcessId(int handle, out long pid)
  183. {
  184. KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
  185. KProcess process = currentProcess.HandleTable.GetKProcess(handle);
  186. if (process == null)
  187. {
  188. KThread thread = currentProcess.HandleTable.GetKThread(handle);
  189. if (thread != null)
  190. {
  191. process = thread.Owner;
  192. }
  193. //TODO: KDebugEvent.
  194. }
  195. pid = process?.Pid ?? 0;
  196. return process != null
  197. ? KernelResult.Success
  198. : KernelResult.InvalidHandle;
  199. }
  200. public void Break64(ulong reason, ulong x1, ulong info)
  201. {
  202. Break(reason);
  203. }
  204. private void Break(ulong reason)
  205. {
  206. KThread currentThread = _system.Scheduler.GetCurrentThread();
  207. if ((reason & (1UL << 31)) == 0)
  208. {
  209. currentThread.PrintGuestStackTrace();
  210. throw new GuestBrokeExecutionException();
  211. }
  212. else
  213. {
  214. Logger.PrintInfo(LogClass.KernelSvc, "Debugger triggered.");
  215. currentThread.PrintGuestStackTrace();
  216. }
  217. }
  218. public void OutputDebugString64(ulong strPtr, ulong size)
  219. {
  220. OutputDebugString(strPtr, size);
  221. }
  222. private void OutputDebugString(ulong strPtr, ulong size)
  223. {
  224. string str = MemoryHelper.ReadAsciiString(_memory, (long)strPtr, (long)size);
  225. Logger.PrintWarning(LogClass.KernelSvc, str);
  226. }
  227. public KernelResult GetInfo64(uint id, int handle, long subId, out long value)
  228. {
  229. return GetInfo(id, handle, subId, out value);
  230. }
  231. private KernelResult GetInfo(uint id, int handle, long subId, out long value)
  232. {
  233. value = 0;
  234. switch (id)
  235. {
  236. case 0:
  237. case 1:
  238. case 2:
  239. case 3:
  240. case 4:
  241. case 5:
  242. case 6:
  243. case 7:
  244. case 12:
  245. case 13:
  246. case 14:
  247. case 15:
  248. case 16:
  249. case 17:
  250. case 18:
  251. case 20:
  252. case 21:
  253. case 22:
  254. {
  255. if (subId != 0)
  256. {
  257. return KernelResult.InvalidCombination;
  258. }
  259. KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
  260. KProcess process = currentProcess.HandleTable.GetKProcess(handle);
  261. if (process == null)
  262. {
  263. return KernelResult.InvalidHandle;
  264. }
  265. switch (id)
  266. {
  267. case 0: value = process.Capabilities.AllowedCpuCoresMask; break;
  268. case 1: value = process.Capabilities.AllowedThreadPriosMask; break;
  269. case 2: value = (long)process.MemoryManager.AliasRegionStart; break;
  270. case 3: value = (long)(process.MemoryManager.AliasRegionEnd -
  271. process.MemoryManager.AliasRegionStart); break;
  272. case 4: value = (long)process.MemoryManager.HeapRegionStart; break;
  273. case 5: value = (long)(process.MemoryManager.HeapRegionEnd -
  274. process.MemoryManager.HeapRegionStart); break;
  275. case 6: value = (long)process.GetMemoryCapacity(); break;
  276. case 7: value = (long)process.GetMemoryUsage(); break;
  277. case 12: value = (long)process.MemoryManager.GetAddrSpaceBaseAddr(); break;
  278. case 13: value = (long)process.MemoryManager.GetAddrSpaceSize(); break;
  279. case 14: value = (long)process.MemoryManager.StackRegionStart; break;
  280. case 15: value = (long)(process.MemoryManager.StackRegionEnd -
  281. process.MemoryManager.StackRegionStart); break;
  282. case 16: value = (long)process.PersonalMmHeapPagesCount * KMemoryManager.PageSize; break;
  283. case 17:
  284. if (process.PersonalMmHeapPagesCount != 0)
  285. {
  286. value = process.MemoryManager.GetMmUsedPages() * KMemoryManager.PageSize;
  287. }
  288. break;
  289. case 18: value = process.TitleId; break;
  290. case 20: value = (long)process.UserExceptionContextAddress; break;
  291. case 21: value = (long)process.GetMemoryCapacityWithoutPersonalMmHeap(); break;
  292. case 22: value = (long)process.GetMemoryUsageWithoutPersonalMmHeap(); break;
  293. }
  294. break;
  295. }
  296. case 8:
  297. {
  298. if (handle != 0)
  299. {
  300. return KernelResult.InvalidHandle;
  301. }
  302. if (subId != 0)
  303. {
  304. return KernelResult.InvalidCombination;
  305. }
  306. value = _system.Scheduler.GetCurrentProcess().Debug ? 1 : 0;
  307. break;
  308. }
  309. case 9:
  310. {
  311. if (handle != 0)
  312. {
  313. return KernelResult.InvalidHandle;
  314. }
  315. if (subId != 0)
  316. {
  317. return KernelResult.InvalidCombination;
  318. }
  319. KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
  320. if (currentProcess.ResourceLimit != null)
  321. {
  322. KHandleTable handleTable = currentProcess.HandleTable;
  323. KResourceLimit resourceLimit = currentProcess.ResourceLimit;
  324. KernelResult result = handleTable.GenerateHandle(resourceLimit, out int resLimHandle);
  325. if (result != KernelResult.Success)
  326. {
  327. return result;
  328. }
  329. value = (uint)resLimHandle;
  330. }
  331. break;
  332. }
  333. case 10:
  334. {
  335. if (handle != 0)
  336. {
  337. return KernelResult.InvalidHandle;
  338. }
  339. int currentCore = _system.Scheduler.GetCurrentThread().CurrentCore;
  340. if (subId != -1 && subId != currentCore)
  341. {
  342. return KernelResult.InvalidCombination;
  343. }
  344. value = _system.Scheduler.CoreContexts[currentCore].TotalIdleTimeTicks;
  345. break;
  346. }
  347. case 11:
  348. {
  349. if (handle != 0)
  350. {
  351. return KernelResult.InvalidHandle;
  352. }
  353. if ((ulong)subId > 3)
  354. {
  355. return KernelResult.InvalidCombination;
  356. }
  357. KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
  358. value = currentProcess.RandomEntropy[subId];
  359. break;
  360. }
  361. case 0xf0000002u:
  362. {
  363. if (subId < -1 || subId > 3)
  364. {
  365. return KernelResult.InvalidCombination;
  366. }
  367. KThread thread = _system.Scheduler.GetCurrentProcess().HandleTable.GetKThread(handle);
  368. if (thread == null)
  369. {
  370. return KernelResult.InvalidHandle;
  371. }
  372. KThread currentThread = _system.Scheduler.GetCurrentThread();
  373. int currentCore = currentThread.CurrentCore;
  374. if (subId != -1 && subId != currentCore)
  375. {
  376. return KernelResult.Success;
  377. }
  378. KCoreContext coreContext = _system.Scheduler.CoreContexts[currentCore];
  379. long timeDelta = PerformanceCounter.ElapsedMilliseconds - coreContext.LastContextSwitchTime;
  380. if (subId != -1)
  381. {
  382. value = KTimeManager.ConvertMillisecondsToTicks(timeDelta);
  383. }
  384. else
  385. {
  386. long totalTimeRunning = thread.TotalTimeRunning;
  387. if (thread == currentThread)
  388. {
  389. totalTimeRunning += timeDelta;
  390. }
  391. value = KTimeManager.ConvertMillisecondsToTicks(totalTimeRunning);
  392. }
  393. break;
  394. }
  395. default: return KernelResult.InvalidEnumValue;
  396. }
  397. return KernelResult.Success;
  398. }
  399. public KernelResult CreateEvent64(out int wEventHandle, out int rEventHandle)
  400. {
  401. return CreateEvent(out wEventHandle, out rEventHandle);
  402. }
  403. private KernelResult CreateEvent(out int wEventHandle, out int rEventHandle)
  404. {
  405. KEvent Event = new KEvent(_system);
  406. KernelResult result = _process.HandleTable.GenerateHandle(Event.WritableEvent, out wEventHandle);
  407. if (result == KernelResult.Success)
  408. {
  409. result = _process.HandleTable.GenerateHandle(Event.ReadableEvent, out rEventHandle);
  410. if (result != KernelResult.Success)
  411. {
  412. _process.HandleTable.CloseHandle(wEventHandle);
  413. }
  414. }
  415. else
  416. {
  417. rEventHandle = 0;
  418. }
  419. return result;
  420. }
  421. public KernelResult GetProcessList64(ulong address, int maxCount, out int count)
  422. {
  423. return GetProcessList(address, maxCount, out count);
  424. }
  425. private KernelResult GetProcessList(ulong address, int maxCount, out int count)
  426. {
  427. count = 0;
  428. if ((maxCount >> 28) != 0)
  429. {
  430. return KernelResult.MaximumExceeded;
  431. }
  432. if (maxCount != 0)
  433. {
  434. KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
  435. ulong copySize = (ulong)maxCount * 8;
  436. if (address + copySize <= address)
  437. {
  438. return KernelResult.InvalidMemState;
  439. }
  440. if (currentProcess.MemoryManager.OutsideAddrSpace(address, copySize))
  441. {
  442. return KernelResult.InvalidMemState;
  443. }
  444. }
  445. int copyCount = 0;
  446. lock (_system.Processes)
  447. {
  448. foreach (KProcess process in _system.Processes.Values)
  449. {
  450. if (copyCount < maxCount)
  451. {
  452. if (!KernelTransfer.KernelToUserInt64(_system, address + (ulong)copyCount * 8, process.Pid))
  453. {
  454. return KernelResult.UserCopyFailed;
  455. }
  456. }
  457. copyCount++;
  458. }
  459. }
  460. count = copyCount;
  461. return KernelResult.Success;
  462. }
  463. public KernelResult GetSystemInfo64(uint id, int handle, long subId, out long value)
  464. {
  465. return GetSystemInfo(id, handle, subId, out value);
  466. }
  467. private KernelResult GetSystemInfo(uint id, int handle, long subId, out long value)
  468. {
  469. value = 0;
  470. if (id > 2)
  471. {
  472. return KernelResult.InvalidEnumValue;
  473. }
  474. if (handle != 0)
  475. {
  476. return KernelResult.InvalidHandle;
  477. }
  478. if (id < 2)
  479. {
  480. if ((ulong)subId > 3)
  481. {
  482. return KernelResult.InvalidCombination;
  483. }
  484. KMemoryRegionManager region = _system.MemoryRegions[subId];
  485. switch (id)
  486. {
  487. //Memory region capacity.
  488. case 0: value = (long)region.Size; break;
  489. //Memory region free space.
  490. case 1:
  491. {
  492. ulong freePagesCount = region.GetFreePages();
  493. value = (long)(freePagesCount * KMemoryManager.PageSize);
  494. break;
  495. }
  496. }
  497. }
  498. else /* if (Id == 2) */
  499. {
  500. if ((ulong)subId > 1)
  501. {
  502. return KernelResult.InvalidCombination;
  503. }
  504. switch (subId)
  505. {
  506. case 0: value = _system.PrivilegedProcessLowestId; break;
  507. case 1: value = _system.PrivilegedProcessHighestId; break;
  508. }
  509. }
  510. return KernelResult.Success;
  511. }
  512. public KernelResult CreatePort64(
  513. int maxSessions,
  514. bool isLight,
  515. ulong namePtr,
  516. out int serverPortHandle,
  517. out int clientPortHandle)
  518. {
  519. return CreatePort(maxSessions, isLight, namePtr, out serverPortHandle, out clientPortHandle);
  520. }
  521. private KernelResult CreatePort(
  522. int maxSessions,
  523. bool isLight,
  524. ulong namePtr,
  525. out int serverPortHandle,
  526. out int clientPortHandle)
  527. {
  528. serverPortHandle = clientPortHandle = 0;
  529. if (maxSessions < 1)
  530. {
  531. return KernelResult.MaximumExceeded;
  532. }
  533. KPort port = new KPort(_system);
  534. port.Initialize(maxSessions, isLight, (long)namePtr);
  535. KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
  536. KernelResult result = currentProcess.HandleTable.GenerateHandle(port.ClientPort, out clientPortHandle);
  537. if (result != KernelResult.Success)
  538. {
  539. return result;
  540. }
  541. result = currentProcess.HandleTable.GenerateHandle(port.ServerPort, out serverPortHandle);
  542. if (result != KernelResult.Success)
  543. {
  544. currentProcess.HandleTable.CloseHandle(clientPortHandle);
  545. }
  546. return result;
  547. }
  548. public KernelResult ManageNamedPort64(ulong namePtr, int maxSessions, out int handle)
  549. {
  550. return ManageNamedPort(namePtr, maxSessions, out handle);
  551. }
  552. private KernelResult ManageNamedPort(ulong namePtr, int maxSessions, out int handle)
  553. {
  554. handle = 0;
  555. if (!KernelTransfer.UserToKernelString(_system, namePtr, 12, out string name))
  556. {
  557. return KernelResult.UserCopyFailed;
  558. }
  559. if (maxSessions < 0 || name.Length > 11)
  560. {
  561. return KernelResult.MaximumExceeded;
  562. }
  563. if (maxSessions == 0)
  564. {
  565. return KClientPort.RemoveName(_system, name);
  566. }
  567. KPort port = new KPort(_system);
  568. KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
  569. KernelResult result = currentProcess.HandleTable.GenerateHandle(port.ServerPort, out handle);
  570. if (result != KernelResult.Success)
  571. {
  572. return result;
  573. }
  574. port.Initialize(maxSessions, false, 0);
  575. result = port.SetName(name);
  576. if (result != KernelResult.Success)
  577. {
  578. currentProcess.HandleTable.CloseHandle(handle);
  579. }
  580. return result;
  581. }
  582. }
  583. }