SvcSystem.cs 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. using ChocolArm64.Memory;
  2. using ChocolArm64.State;
  3. using Ryujinx.Core.OsHle.Exceptions;
  4. using Ryujinx.Core.OsHle.Handles;
  5. using Ryujinx.Core.OsHle.Ipc;
  6. using Ryujinx.Core.OsHle.Services;
  7. using System;
  8. using System.Threading;
  9. using static Ryujinx.Core.OsHle.ErrorCode;
  10. namespace Ryujinx.Core.OsHle.Kernel
  11. {
  12. partial class SvcHandler
  13. {
  14. private const int AllowedCpuIdBitmask = 0b1111;
  15. private const bool EnableProcessDebugging = false;
  16. private void SvcExitProcess(AThreadState ThreadState)
  17. {
  18. Ns.Os.ExitProcess(ThreadState.ProcessId);
  19. }
  20. private void SvcClearEvent(AThreadState ThreadState)
  21. {
  22. int Handle = (int)ThreadState.X0;
  23. //TODO: Implement events.
  24. ThreadState.X0 = 0;
  25. }
  26. private void SvcCloseHandle(AThreadState ThreadState)
  27. {
  28. int Handle = (int)ThreadState.X0;
  29. object Obj = Process.HandleTable.CloseHandle(Handle);
  30. if (Obj == null)
  31. {
  32. Logging.Warn(LogClass.KernelSvc, $"Tried to CloseHandle on invalid handle 0x{Handle:x8}!");
  33. ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
  34. return;
  35. }
  36. if (Obj is KSession Session)
  37. {
  38. Session.Dispose();
  39. }
  40. else if (Obj is HTransferMem TMem)
  41. {
  42. TMem.Memory.Manager.Reprotect(
  43. TMem.Position,
  44. TMem.Size,
  45. TMem.Perm);
  46. }
  47. ThreadState.X0 = 0;
  48. }
  49. private void SvcResetSignal(AThreadState ThreadState)
  50. {
  51. int Handle = (int)ThreadState.X0;
  52. KEvent Event = Process.HandleTable.GetData<KEvent>(Handle);
  53. if (Event != null)
  54. {
  55. Event.WaitEvent.Reset();
  56. ThreadState.X0 = 0;
  57. }
  58. else
  59. {
  60. Logging.Warn(LogClass.KernelSvc, $"Tried to ResetSignal on invalid event handle 0x{Handle:x8}!");
  61. ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
  62. }
  63. }
  64. private void SvcWaitSynchronization(AThreadState ThreadState)
  65. {
  66. long HandlesPtr = (long)ThreadState.X1;
  67. int HandlesCount = (int)ThreadState.X2;
  68. ulong Timeout = ThreadState.X3;
  69. KThread CurrThread = Process.GetThread(ThreadState.Tpidr);
  70. WaitHandle[] Handles = new WaitHandle[HandlesCount];
  71. for (int Index = 0; Index < HandlesCount; Index++)
  72. {
  73. int Handle = Memory.ReadInt32(HandlesPtr + Index * 4);
  74. KSynchronizationObject SyncObj = Process.HandleTable.GetData<KSynchronizationObject>(Handle);
  75. if (SyncObj == null)
  76. {
  77. Logging.Warn(LogClass.KernelSvc, $"Tried to WaitSynchronization on invalid handle 0x{Handle:x8}!");
  78. ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
  79. return;
  80. }
  81. Handles[Index] = SyncObj.WaitEvent;
  82. }
  83. Process.Scheduler.Suspend(CurrThread.ProcessorId);
  84. int HandleIndex;
  85. ulong Result = 0;
  86. if (Timeout != ulong.MaxValue)
  87. {
  88. HandleIndex = WaitHandle.WaitAny(Handles, NsTimeConverter.GetTimeMs(Timeout));
  89. if (HandleIndex == WaitHandle.WaitTimeout)
  90. {
  91. Result = MakeError(ErrorModule.Kernel, KernelErr.Timeout);
  92. }
  93. }
  94. else
  95. {
  96. HandleIndex = WaitHandle.WaitAny(Handles);
  97. }
  98. Process.Scheduler.Resume(CurrThread);
  99. ThreadState.X0 = Result;
  100. if (Result == 0)
  101. {
  102. ThreadState.X1 = (ulong)HandleIndex;
  103. }
  104. }
  105. private void SvcGetSystemTick(AThreadState ThreadState)
  106. {
  107. ThreadState.X0 = ThreadState.CntpctEl0;
  108. }
  109. private void SvcConnectToNamedPort(AThreadState ThreadState)
  110. {
  111. long StackPtr = (long)ThreadState.X0;
  112. long NamePtr = (long)ThreadState.X1;
  113. string Name = AMemoryHelper.ReadAsciiString(Memory, NamePtr, 8);
  114. //TODO: Validate that app has perms to access the service, and that the service
  115. //actually exists, return error codes otherwise.
  116. KSession Session = new KSession(ServiceFactory.MakeService(Name), Name);
  117. ulong Handle = (ulong)Process.HandleTable.OpenHandle(Session);
  118. ThreadState.X0 = 0;
  119. ThreadState.X1 = Handle;
  120. }
  121. private void SvcSendSyncRequest(AThreadState ThreadState)
  122. {
  123. SendSyncRequest(ThreadState, ThreadState.Tpidr, 0x100, (int)ThreadState.X0);
  124. }
  125. private void SvcSendSyncRequestWithUserBuffer(AThreadState ThreadState)
  126. {
  127. SendSyncRequest(
  128. ThreadState,
  129. (long)ThreadState.X0,
  130. (long)ThreadState.X1,
  131. (int)ThreadState.X2);
  132. }
  133. private void SendSyncRequest(AThreadState ThreadState, long CmdPtr, long Size, int Handle)
  134. {
  135. KThread CurrThread = Process.GetThread(ThreadState.Tpidr);
  136. byte[] CmdData = AMemoryHelper.ReadBytes(Memory, CmdPtr, Size);
  137. KSession Session = Process.HandleTable.GetData<KSession>(Handle);
  138. if (Session != null)
  139. {
  140. Process.Scheduler.Suspend(CurrThread.ProcessorId);
  141. IpcMessage Cmd = new IpcMessage(CmdData, CmdPtr);
  142. IpcHandler.IpcCall(Ns, Process, Memory, Session, Cmd, CmdPtr);
  143. Thread.Yield();
  144. Process.Scheduler.Resume(CurrThread);
  145. ThreadState.X0 = 0;
  146. }
  147. else
  148. {
  149. Logging.Warn(LogClass.KernelSvc, $"Tried to SendSyncRequest on invalid session handle 0x{Handle:x8}!");
  150. ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
  151. }
  152. }
  153. private void SvcBreak(AThreadState ThreadState)
  154. {
  155. long Reason = (long)ThreadState.X0;
  156. long Unknown = (long)ThreadState.X1;
  157. long Info = (long)ThreadState.X2;
  158. Process.PrintStackTrace(ThreadState);
  159. throw new GuestBrokeExecutionException();
  160. }
  161. private void SvcOutputDebugString(AThreadState ThreadState)
  162. {
  163. long Position = (long)ThreadState.X0;
  164. long Size = (long)ThreadState.X1;
  165. string Str = AMemoryHelper.ReadAsciiString(Memory, Position, Size);
  166. Logging.Info(LogClass.KernelSvc, Str);
  167. ThreadState.X0 = 0;
  168. }
  169. private void SvcGetInfo(AThreadState ThreadState)
  170. {
  171. long StackPtr = (long)ThreadState.X0;
  172. int InfoType = (int)ThreadState.X1;
  173. long Handle = (long)ThreadState.X2;
  174. int InfoId = (int)ThreadState.X3;
  175. //Fail for info not available on older Kernel versions.
  176. if (InfoType == 18 ||
  177. InfoType == 19 ||
  178. InfoType == 20)
  179. {
  180. ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidInfo);
  181. return;
  182. }
  183. switch (InfoType)
  184. {
  185. case 0:
  186. ThreadState.X1 = AllowedCpuIdBitmask;
  187. break;
  188. case 2:
  189. ThreadState.X1 = MemoryRegions.MapRegionAddress;
  190. break;
  191. case 3:
  192. ThreadState.X1 = MemoryRegions.MapRegionSize;
  193. break;
  194. case 4:
  195. ThreadState.X1 = MemoryRegions.HeapRegionAddress;
  196. break;
  197. case 5:
  198. ThreadState.X1 = MemoryRegions.HeapRegionSize;
  199. break;
  200. case 6:
  201. ThreadState.X1 = MemoryRegions.TotalMemoryAvailable;
  202. break;
  203. case 7:
  204. ThreadState.X1 = MemoryRegions.TotalMemoryUsed + CurrentHeapSize;
  205. break;
  206. case 8:
  207. ThreadState.X1 = EnableProcessDebugging ? 1 : 0;
  208. break;
  209. case 11:
  210. ThreadState.X1 = (ulong)Rng.Next() + ((ulong)Rng.Next() << 32);
  211. break;
  212. case 12:
  213. ThreadState.X1 = MemoryRegions.AddrSpaceStart;
  214. break;
  215. case 13:
  216. ThreadState.X1 = MemoryRegions.AddrSpaceSize;
  217. break;
  218. case 14:
  219. ThreadState.X1 = MemoryRegions.MapRegionAddress;
  220. break;
  221. case 15:
  222. ThreadState.X1 = MemoryRegions.MapRegionSize;
  223. break;
  224. default:
  225. Process.PrintStackTrace(ThreadState);
  226. throw new NotImplementedException($"SvcGetInfo: {InfoType} {Handle:x8} {InfoId}");
  227. }
  228. ThreadState.X0 = 0;
  229. }
  230. }
  231. }