IpcHandler.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. using ChocolArm64.Memory;
  2. using Ryujinx.Core.OsHle.Handles;
  3. using Ryujinx.Core.OsHle.Objects;
  4. using Ryujinx.Core.OsHle.Services;
  5. using System;
  6. using System.Collections.Generic;
  7. using System.IO;
  8. namespace Ryujinx.Core.OsHle.Ipc
  9. {
  10. static class IpcHandler
  11. {
  12. private static Dictionary<(string, int), ServiceProcessRequest> ServiceCmds =
  13. new Dictionary<(string, int), ServiceProcessRequest>()
  14. {
  15. { ( "acc:u0", 3), Service.AccU0ListOpenUsers },
  16. { ( "acc:u0", 5), Service.AccU0GetProfile },
  17. { ( "acc:u0", 100), Service.AccU0InitializeApplicationInfo },
  18. { ( "acc:u0", 101), Service.AccU0GetBaasAccountManagerForApplication },
  19. { ( "apm", 0), Service.ApmOpenSession },
  20. { ( "apm:p", 0), Service.ApmOpenSession },
  21. { ( "appletOE", 0), Service.AppletOpenApplicationProxy },
  22. { ( "audout:u", 0), Service.AudOutListAudioOuts },
  23. { ( "audout:u", 1), Service.AudOutOpenAudioOut },
  24. { ( "audren:u", 0), Service.AudRenOpenAudioRenderer },
  25. { ( "audren:u", 1), Service.AudRenGetAudioRendererWorkBufferSize },
  26. { ( "friend:a", 0), Service.FriendCreateFriendService },
  27. { ( "fsp-srv", 1), Service.FspSrvInitialize },
  28. { ( "fsp-srv", 18), Service.FspSrvMountSdCard },
  29. { ( "fsp-srv", 51), Service.FspSrvMountSaveData },
  30. { ( "fsp-srv", 200), Service.FspSrvOpenDataStorageByCurrentProcess },
  31. { ( "fsp-srv", 203), Service.FspSrvOpenRomStorage },
  32. { ( "fsp-srv", 1005), Service.FspSrvGetGlobalAccessLogMode },
  33. { ( "hid", 0), Service.HidCreateAppletResource },
  34. { ( "hid", 11), Service.HidActivateTouchScreen },
  35. { ( "hid", 100), Service.HidSetSupportedNpadStyleSet },
  36. { ( "hid", 101), Service.HidGetSupportedNpadStyleSet },
  37. { ( "hid", 102), Service.HidSetSupportedNpadIdType },
  38. { ( "hid", 103), Service.HidActivateNpad },
  39. { ( "hid", 120), Service.HidSetNpadJoyHoldType },
  40. { ( "hid", 121), Service.HidGetNpadJoyHoldType },
  41. { ( "hid", 203), Service.HidCreateActiveVibrationDeviceList },
  42. { ( "lm", 0), Service.LmInitialize },
  43. { ( "nvdrv", 0), Service.NvDrvOpen },
  44. { ( "nvdrv", 1), Service.NvDrvIoctl },
  45. { ( "nvdrv", 2), Service.NvDrvClose },
  46. { ( "nvdrv", 3), Service.NvDrvInitialize },
  47. { ( "nvdrv", 4), Service.NvDrvQueryEvent },
  48. { ( "nvdrv", 8), Service.NvDrvSetClientPid },
  49. { ( "nvdrv:a", 0), Service.NvDrvOpen },
  50. { ( "nvdrv:a", 1), Service.NvDrvIoctl },
  51. { ( "nvdrv:a", 2), Service.NvDrvClose },
  52. { ( "nvdrv:a", 3), Service.NvDrvInitialize },
  53. { ( "nvdrv:a", 4), Service.NvDrvQueryEvent },
  54. { ( "nvdrv:a", 8), Service.NvDrvSetClientPid },
  55. { ( "pctl:a", 0), Service.PctlCreateService },
  56. { ( "pl:u", 1), Service.PlGetLoadState },
  57. { ( "pl:u", 2), Service.PlGetFontSize },
  58. { ( "pl:u", 3), Service.PlGetSharedMemoryAddressOffset },
  59. { ( "pl:u", 4), Service.PlGetSharedMemoryNativeHandle },
  60. { ( "set", 1), Service.SetGetAvailableLanguageCodes },
  61. { ( "sm:", 0), Service.SmInitialize },
  62. { ( "sm:", 1), Service.SmGetService },
  63. { ( "time:u", 0), Service.TimeGetStandardUserSystemClock },
  64. { ( "time:u", 1), Service.TimeGetStandardNetworkSystemClock },
  65. { ( "time:u", 2), Service.TimeGetStandardSteadyClock },
  66. { ( "time:u", 3), Service.TimeGetTimeZoneService },
  67. { ( "time:u", 4), Service.TimeGetStandardLocalSystemClock },
  68. { ( "time:s", 0), Service.TimeGetStandardUserSystemClock },
  69. { ( "time:s", 1), Service.TimeGetStandardNetworkSystemClock },
  70. { ( "time:s", 2), Service.TimeGetStandardSteadyClock },
  71. { ( "time:s", 3), Service.TimeGetTimeZoneService },
  72. { ( "time:s", 4), Service.TimeGetStandardLocalSystemClock },
  73. { ( "vi:m", 2), Service.ViGetDisplayService },
  74. };
  75. private const long SfciMagic = 'S' << 0 | 'F' << 8 | 'C' << 16 | 'I' << 24;
  76. private const long SfcoMagic = 'S' << 0 | 'F' << 8 | 'C' << 16 | 'O' << 24;
  77. public static void IpcCall(
  78. Switch Ns,
  79. AMemory Memory,
  80. HSession Session,
  81. IpcMessage Request,
  82. int ThreadId,
  83. long CmdPtr,
  84. int HndId)
  85. {
  86. IpcMessage Response = new IpcMessage(Request.IsDomain);
  87. using (MemoryStream Raw = new MemoryStream(Request.RawData))
  88. {
  89. BinaryReader ReqReader = new BinaryReader(Raw);
  90. if (Request.Type == IpcMessageType.Request)
  91. {
  92. string ServiceName = Session.ServiceName;
  93. ServiceProcessRequest ProcReq = null;
  94. bool IgnoreNullPR = false;
  95. string DbgServiceName = string.Empty;
  96. if (Session is HDomain Dom)
  97. {
  98. if (Request.DomCmd == IpcDomCmd.SendMsg)
  99. {
  100. long Magic = ReqReader.ReadInt64();
  101. int CmdId = (int)ReqReader.ReadInt64();
  102. object Obj = Dom.GetObject(Request.DomObjId);
  103. if (Obj is HDomain)
  104. {
  105. ServiceCmds.TryGetValue((ServiceName, CmdId), out ProcReq);
  106. DbgServiceName = $"{ProcReq?.Method.Name ?? CmdId.ToString()}";
  107. }
  108. else if (Obj != null)
  109. {
  110. ((IIpcInterface)Obj).Commands.TryGetValue(CmdId, out ProcReq);
  111. DbgServiceName = $"{Obj.GetType().Name} {ProcReq?.Method.Name ?? CmdId.ToString()}";
  112. }
  113. }
  114. else if (Request.DomCmd == IpcDomCmd.DeleteObj)
  115. {
  116. Dom.DeleteObject(Request.DomObjId);
  117. Response = FillResponse(Response, 0);
  118. IgnoreNullPR = true;
  119. }
  120. }
  121. else
  122. {
  123. long Magic = ReqReader.ReadInt64();
  124. int CmdId = (int)ReqReader.ReadInt64();
  125. if (Session is HSessionObj)
  126. {
  127. object Obj = ((HSessionObj)Session).Obj;
  128. ((IIpcInterface)Obj).Commands.TryGetValue(CmdId, out ProcReq);
  129. DbgServiceName = $"{Obj.GetType().Name} {ProcReq?.Method.Name ?? CmdId.ToString()}";
  130. }
  131. else
  132. {
  133. ServiceCmds.TryGetValue((ServiceName, CmdId), out ProcReq);
  134. DbgServiceName = $"{ProcReq?.Method.Name ?? CmdId.ToString()}";
  135. }
  136. }
  137. DbgServiceName = $"Tid {ThreadId} {ServiceName} {DbgServiceName}";
  138. Logging.Debug($"IpcMessage: {DbgServiceName}");
  139. if (ProcReq != null)
  140. {
  141. using (MemoryStream ResMS = new MemoryStream())
  142. {
  143. BinaryWriter ResWriter = new BinaryWriter(ResMS);
  144. ServiceCtx Context = new ServiceCtx(
  145. Ns,
  146. Memory,
  147. Session,
  148. Request,
  149. Response,
  150. ReqReader,
  151. ResWriter);
  152. long Result = ProcReq(Context);
  153. Response = FillResponse(Response, Result, ResMS.ToArray());
  154. }
  155. }
  156. else if (!IgnoreNullPR)
  157. {
  158. throw new NotImplementedException(DbgServiceName);
  159. }
  160. }
  161. else if (Request.Type == IpcMessageType.Control)
  162. {
  163. long Magic = ReqReader.ReadInt64();
  164. long CmdId = ReqReader.ReadInt64();
  165. switch (CmdId)
  166. {
  167. case 0: Request = IpcConvertSessionToDomain(Ns, Session, Response, HndId); break;
  168. case 3: Request = IpcQueryBufferPointerSize(Response); break;
  169. case 4: Request = IpcDuplicateSessionEx(Ns, Session, Response, ReqReader); break;
  170. default: throw new NotImplementedException(CmdId.ToString());
  171. }
  172. }
  173. else if (Request.Type == IpcMessageType.Unknown2)
  174. {
  175. //TODO
  176. }
  177. else
  178. {
  179. throw new NotImplementedException(Request.Type.ToString());
  180. }
  181. AMemoryHelper.WriteBytes(Memory, CmdPtr, Response.GetBytes(CmdPtr));
  182. }
  183. }
  184. private static IpcMessage IpcConvertSessionToDomain(
  185. Switch Ns,
  186. HSession Session,
  187. IpcMessage Response,
  188. int HndId)
  189. {
  190. HDomain Dom = new HDomain(Session);
  191. Ns.Os.Handles.ReplaceData(HndId, Dom);
  192. return FillResponse(Response, 0, Dom.GenerateObjectId(Dom));
  193. }
  194. private static IpcMessage IpcDuplicateSessionEx(
  195. Switch Ns,
  196. HSession Session,
  197. IpcMessage Response,
  198. BinaryReader ReqReader)
  199. {
  200. int Unknown = ReqReader.ReadInt32();
  201. int Handle = Ns.Os.Handles.GenerateId(Session);
  202. Response.HandleDesc = IpcHandleDesc.MakeMove(Handle);
  203. return FillResponse(Response, 0);
  204. }
  205. private static IpcMessage IpcQueryBufferPointerSize(IpcMessage Response)
  206. {
  207. return FillResponse(Response, 0, 0x500);
  208. }
  209. private static IpcMessage FillResponse(IpcMessage Response, long Result, params int[] Values)
  210. {
  211. using (MemoryStream MS = new MemoryStream())
  212. {
  213. BinaryWriter Writer = new BinaryWriter(MS);
  214. foreach (int Value in Values)
  215. {
  216. Writer.Write(Value);
  217. }
  218. return FillResponse(Response, Result, MS.ToArray());
  219. }
  220. }
  221. private static IpcMessage FillResponse(IpcMessage Response, long Result, byte[] Data = null)
  222. {
  223. Response.Type = IpcMessageType.Response;
  224. using (MemoryStream MS = new MemoryStream())
  225. {
  226. BinaryWriter Writer = new BinaryWriter(MS);
  227. Writer.Write(SfcoMagic);
  228. Writer.Write(Result);
  229. if (Data != null)
  230. {
  231. Writer.Write(Data);
  232. }
  233. Response.RawData = MS.ToArray();
  234. }
  235. return Response;
  236. }
  237. }
  238. }