SvcSystem.cs 11 KB

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