SvcSystem.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401
  1. using ChocolArm64.Memory;
  2. using ChocolArm64.State;
  3. using Ryujinx.Common.Logging;
  4. using Ryujinx.HLE.Exceptions;
  5. using Ryujinx.HLE.HOS.Ipc;
  6. using Ryujinx.HLE.HOS.Services;
  7. using System;
  8. using System.Threading;
  9. using static Ryujinx.HLE.HOS.ErrorCode;
  10. namespace Ryujinx.HLE.HOS.Kernel
  11. {
  12. partial class SvcHandler
  13. {
  14. private const int AllowedCpuIdBitmask = 0b1111;
  15. private const bool EnableProcessDebugging = false;
  16. private void SvcExitProcess(CpuThreadState ThreadState)
  17. {
  18. Device.System.ExitProcess(Process.ProcessId);
  19. }
  20. private void SignalEvent64(CpuThreadState ThreadState)
  21. {
  22. ThreadState.X0 = (ulong)SignalEvent((int)ThreadState.X0);
  23. }
  24. private KernelResult SignalEvent(int Handle)
  25. {
  26. KWritableEvent WritableEvent = Process.HandleTable.GetObject<KWritableEvent>(Handle);
  27. KernelResult Result;
  28. if (WritableEvent != null)
  29. {
  30. WritableEvent.Signal();
  31. Result = KernelResult.Success;
  32. }
  33. else
  34. {
  35. Result = KernelResult.InvalidHandle;
  36. }
  37. if (Result != KernelResult.Success)
  38. {
  39. Logger.PrintWarning(LogClass.KernelSvc, "Operation failed with error: " + Result + "!");
  40. }
  41. return Result;
  42. }
  43. private void ClearEvent64(CpuThreadState ThreadState)
  44. {
  45. ThreadState.X0 = (ulong)ClearEvent((int)ThreadState.X0);
  46. }
  47. private KernelResult ClearEvent(int Handle)
  48. {
  49. KernelResult Result;
  50. KWritableEvent WritableEvent = Process.HandleTable.GetObject<KWritableEvent>(Handle);
  51. if (WritableEvent == null)
  52. {
  53. KReadableEvent ReadableEvent = Process.HandleTable.GetObject<KReadableEvent>(Handle);
  54. Result = ReadableEvent?.Clear() ?? KernelResult.InvalidHandle;
  55. }
  56. else
  57. {
  58. Result = WritableEvent.Clear();
  59. }
  60. if (Result != KernelResult.Success)
  61. {
  62. Logger.PrintWarning(LogClass.KernelSvc, "Operation failed with error: " + Result + "!");
  63. }
  64. return Result;
  65. }
  66. private void SvcCloseHandle(CpuThreadState ThreadState)
  67. {
  68. int Handle = (int)ThreadState.X0;
  69. object Obj = Process.HandleTable.GetObject<object>(Handle);
  70. Process.HandleTable.CloseHandle(Handle);
  71. if (Obj == null)
  72. {
  73. Logger.PrintWarning(LogClass.KernelSvc, $"Invalid handle 0x{Handle:x8}!");
  74. ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
  75. return;
  76. }
  77. if (Obj is KSession Session)
  78. {
  79. Session.Dispose();
  80. }
  81. else if (Obj is KTransferMemory TransferMemory)
  82. {
  83. Process.MemoryManager.ResetTransferMemory(
  84. TransferMemory.Position,
  85. TransferMemory.Size);
  86. }
  87. ThreadState.X0 = 0;
  88. }
  89. private void ResetSignal64(CpuThreadState ThreadState)
  90. {
  91. ThreadState.X0 = (ulong)ResetSignal((int)ThreadState.X0);
  92. }
  93. private KernelResult ResetSignal(int Handle)
  94. {
  95. KReadableEvent ReadableEvent = Process.HandleTable.GetObject<KReadableEvent>(Handle);
  96. KernelResult Result;
  97. //TODO: KProcess support.
  98. if (ReadableEvent != null)
  99. {
  100. Result = ReadableEvent.ClearIfSignaled();
  101. }
  102. else
  103. {
  104. Result = KernelResult.InvalidHandle;
  105. }
  106. if (Result == KernelResult.InvalidState)
  107. {
  108. Logger.PrintDebug(LogClass.KernelSvc, "Operation failed with error: " + Result + "!");
  109. }
  110. else if (Result != KernelResult.Success)
  111. {
  112. Logger.PrintWarning(LogClass.KernelSvc, "Operation failed with error: " + Result + "!");
  113. }
  114. return Result;
  115. }
  116. private void SvcGetSystemTick(CpuThreadState ThreadState)
  117. {
  118. ThreadState.X0 = ThreadState.CntpctEl0;
  119. }
  120. private void SvcConnectToNamedPort(CpuThreadState ThreadState)
  121. {
  122. long StackPtr = (long)ThreadState.X0;
  123. long NamePtr = (long)ThreadState.X1;
  124. string Name = MemoryHelper.ReadAsciiString(Memory, 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. if (Process.HandleTable.GenerateHandle(Session, out int Handle) != KernelResult.Success)
  129. {
  130. throw new InvalidOperationException("Out of handles!");
  131. }
  132. ThreadState.X0 = 0;
  133. ThreadState.X1 = (uint)Handle;
  134. }
  135. private void SvcSendSyncRequest(CpuThreadState ThreadState)
  136. {
  137. SendSyncRequest(ThreadState, ThreadState.Tpidr, 0x100, (int)ThreadState.X0);
  138. }
  139. private void SvcSendSyncRequestWithUserBuffer(CpuThreadState ThreadState)
  140. {
  141. SendSyncRequest(
  142. ThreadState,
  143. (long)ThreadState.X0,
  144. (long)ThreadState.X1,
  145. (int)ThreadState.X2);
  146. }
  147. private void SendSyncRequest(CpuThreadState ThreadState, long MessagePtr, long Size, int Handle)
  148. {
  149. KThread CurrThread = Process.GetThread(ThreadState.Tpidr);
  150. byte[] MessageData = Memory.ReadBytes(MessagePtr, Size);
  151. KSession Session = Process.HandleTable.GetObject<KSession>(Handle);
  152. if (Session != null)
  153. {
  154. //Process.Scheduler.Suspend(CurrThread);
  155. System.CriticalSectionLock.Lock();
  156. KThread CurrentThread = System.Scheduler.GetCurrentThread();
  157. CurrentThread.SignaledObj = null;
  158. CurrentThread.ObjSyncResult = 0;
  159. CurrentThread.Reschedule(ThreadSchedState.Paused);
  160. IpcMessage Message = new IpcMessage(MessageData, MessagePtr);
  161. ThreadPool.QueueUserWorkItem(ProcessIpcRequest, new HleIpcMessage(
  162. CurrentThread,
  163. Session,
  164. Message,
  165. MessagePtr));
  166. System.CriticalSectionLock.Unlock();
  167. ThreadState.X0 = (ulong)CurrentThread.ObjSyncResult;
  168. }
  169. else
  170. {
  171. Logger.PrintWarning(LogClass.KernelSvc, $"Invalid session handle 0x{Handle:x8}!");
  172. ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
  173. }
  174. }
  175. private void ProcessIpcRequest(object State)
  176. {
  177. HleIpcMessage IpcMessage = (HleIpcMessage)State;
  178. IpcMessage.Thread.ObjSyncResult = (int)IpcHandler.IpcCall(
  179. Device,
  180. Process,
  181. Memory,
  182. IpcMessage.Session,
  183. IpcMessage.Message,
  184. IpcMessage.MessagePtr);
  185. IpcMessage.Thread.Reschedule(ThreadSchedState.Running);
  186. }
  187. private void SvcBreak(CpuThreadState ThreadState)
  188. {
  189. long Reason = (long)ThreadState.X0;
  190. long Unknown = (long)ThreadState.X1;
  191. long Info = (long)ThreadState.X2;
  192. if ((Reason & (1 << 31)) == 0)
  193. {
  194. Process.PrintStackTrace(ThreadState);
  195. throw new GuestBrokeExecutionException();
  196. }
  197. else
  198. {
  199. Logger.PrintInfo(LogClass.KernelSvc, "Debugger triggered");
  200. Process.PrintStackTrace(ThreadState);
  201. }
  202. }
  203. private void SvcOutputDebugString(CpuThreadState ThreadState)
  204. {
  205. long Position = (long)ThreadState.X0;
  206. long Size = (long)ThreadState.X1;
  207. string Str = MemoryHelper.ReadAsciiString(Memory, Position, Size);
  208. Logger.PrintWarning(LogClass.KernelSvc, Str);
  209. ThreadState.X0 = 0;
  210. }
  211. private void SvcGetInfo(CpuThreadState ThreadState)
  212. {
  213. long StackPtr = (long)ThreadState.X0;
  214. int InfoType = (int)ThreadState.X1;
  215. long Handle = (long)ThreadState.X2;
  216. int InfoId = (int)ThreadState.X3;
  217. //Fail for info not available on older Kernel versions.
  218. if (InfoType == 18 ||
  219. InfoType == 19 ||
  220. InfoType == 20 ||
  221. InfoType == 21 ||
  222. InfoType == 22)
  223. {
  224. ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidEnumValue);
  225. return;
  226. }
  227. switch (InfoType)
  228. {
  229. case 0:
  230. ThreadState.X1 = AllowedCpuIdBitmask;
  231. break;
  232. case 2:
  233. ThreadState.X1 = (ulong)Process.MemoryManager.MapRegionStart;
  234. break;
  235. case 3:
  236. ThreadState.X1 = (ulong)Process.MemoryManager.MapRegionEnd -
  237. (ulong)Process.MemoryManager.MapRegionStart;
  238. break;
  239. case 4:
  240. ThreadState.X1 = (ulong)Process.MemoryManager.HeapRegionStart;
  241. break;
  242. case 5:
  243. ThreadState.X1 = (ulong)Process.MemoryManager.HeapRegionEnd -
  244. (ulong)Process.MemoryManager.HeapRegionStart;
  245. break;
  246. case 6:
  247. ThreadState.X1 = (ulong)Process.Device.Memory.Allocator.TotalAvailableSize;
  248. break;
  249. case 7:
  250. ThreadState.X1 = (ulong)Process.Device.Memory.Allocator.TotalUsedSize;
  251. break;
  252. case 8:
  253. ThreadState.X1 = EnableProcessDebugging ? 1 : 0;
  254. break;
  255. case 11:
  256. ThreadState.X1 = (ulong)Rng.Next() + ((ulong)Rng.Next() << 32);
  257. break;
  258. case 12:
  259. ThreadState.X1 = (ulong)Process.MemoryManager.AddrSpaceStart;
  260. break;
  261. case 13:
  262. ThreadState.X1 = (ulong)Process.MemoryManager.AddrSpaceEnd -
  263. (ulong)Process.MemoryManager.AddrSpaceStart;
  264. break;
  265. case 14:
  266. ThreadState.X1 = (ulong)Process.MemoryManager.NewMapRegionStart;
  267. break;
  268. case 15:
  269. ThreadState.X1 = (ulong)Process.MemoryManager.NewMapRegionEnd -
  270. (ulong)Process.MemoryManager.NewMapRegionStart;
  271. break;
  272. case 16:
  273. ThreadState.X1 = (ulong)(Process.MetaData?.SystemResourceSize ?? 0);
  274. break;
  275. case 17:
  276. ThreadState.X1 = (ulong)Process.MemoryManager.PersonalMmHeapUsage;
  277. break;
  278. default:
  279. Process.PrintStackTrace(ThreadState);
  280. throw new NotImplementedException($"SvcGetInfo: {InfoType} 0x{Handle:x8} {InfoId}");
  281. }
  282. ThreadState.X0 = 0;
  283. }
  284. private void CreateEvent64(CpuThreadState State)
  285. {
  286. KernelResult Result = CreateEvent(out int WEventHandle, out int REventHandle);
  287. State.X0 = (ulong)Result;
  288. State.X1 = (ulong)WEventHandle;
  289. State.X2 = (ulong)REventHandle;
  290. }
  291. private KernelResult CreateEvent(out int WEventHandle, out int REventHandle)
  292. {
  293. KEvent Event = new KEvent(System);
  294. KernelResult Result = Process.HandleTable.GenerateHandle(Event.WritableEvent, out WEventHandle);
  295. if (Result == KernelResult.Success)
  296. {
  297. Result = Process.HandleTable.GenerateHandle(Event.ReadableEvent, out REventHandle);
  298. if (Result != KernelResult.Success)
  299. {
  300. Process.HandleTable.CloseHandle(WEventHandle);
  301. }
  302. }
  303. else
  304. {
  305. REventHandle = 0;
  306. }
  307. return Result;
  308. }
  309. }
  310. }