IpcHandler.cs 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. using ChocolArm64.Memory;
  2. using Ryujinx.Core.OsHle.Handles;
  3. using Ryujinx.Core.OsHle.IpcServices;
  4. using System;
  5. using System.IO;
  6. namespace Ryujinx.Core.OsHle.Ipc
  7. {
  8. static class IpcHandler
  9. {
  10. private const long SfciMagic = 'S' << 0 | 'F' << 8 | 'C' << 16 | 'I' << 24;
  11. private const long SfcoMagic = 'S' << 0 | 'F' << 8 | 'C' << 16 | 'O' << 24;
  12. public static void IpcCall(
  13. Switch Ns,
  14. Process Process,
  15. AMemory Memory,
  16. HSession Session,
  17. IpcMessage Request,
  18. int ThreadId,
  19. long CmdPtr,
  20. int HndId)
  21. {
  22. IpcMessage Response = new IpcMessage(Request.IsDomain && Request.Type == IpcMessageType.Request);
  23. using (MemoryStream Raw = new MemoryStream(Request.RawData))
  24. {
  25. BinaryReader ReqReader = new BinaryReader(Raw);
  26. if (Request.Type == IpcMessageType.Request)
  27. {
  28. string ServiceName = Session.Service.GetType().Name;
  29. ServiceProcessRequest ProcReq = null;
  30. bool IgnoreNullPR = false;
  31. string DbgServiceName = string.Empty;
  32. if (Session is HDomain Dom)
  33. {
  34. if (Request.DomCmd == IpcDomCmd.SendMsg)
  35. {
  36. long Magic = ReqReader.ReadInt64();
  37. int CmdId = (int)ReqReader.ReadInt64();
  38. object Obj = Dom.GetObject(Request.DomObjId);
  39. if (Obj is HDomain)
  40. {
  41. Session.Service.Commands.TryGetValue(CmdId, out ProcReq);
  42. DbgServiceName = $"{ProcReq?.Method.Name ?? CmdId.ToString()}";
  43. }
  44. else if (Obj != null)
  45. {
  46. ((IIpcService)Obj).Commands.TryGetValue(CmdId, out ProcReq);
  47. DbgServiceName = $"{Obj.GetType().Name} {ProcReq?.Method.Name ?? CmdId.ToString()}";
  48. }
  49. }
  50. else if (Request.DomCmd == IpcDomCmd.DeleteObj)
  51. {
  52. Dom.Delete(Request.DomObjId);
  53. Response = FillResponse(Response, 0);
  54. IgnoreNullPR = true;
  55. }
  56. }
  57. else
  58. {
  59. long Magic = ReqReader.ReadInt64();
  60. int CmdId = (int)ReqReader.ReadInt64();
  61. if (Session is HSessionObj)
  62. {
  63. object Obj = ((HSessionObj)Session).Obj;
  64. ((IIpcService)Obj).Commands.TryGetValue(CmdId, out ProcReq);
  65. DbgServiceName = $"{Obj.GetType().Name} {ProcReq?.Method.Name ?? CmdId.ToString()}";
  66. }
  67. else
  68. {
  69. Session.Service.Commands.TryGetValue(CmdId, out ProcReq);
  70. DbgServiceName = $"{ProcReq?.Method.Name ?? CmdId.ToString()}";
  71. }
  72. }
  73. DbgServiceName = $"Tid {ThreadId} {ServiceName} {DbgServiceName}";
  74. Logging.Debug($"IpcMessage: {DbgServiceName}");
  75. if (ProcReq != null)
  76. {
  77. using (MemoryStream ResMS = new MemoryStream())
  78. {
  79. BinaryWriter ResWriter = new BinaryWriter(ResMS);
  80. ServiceCtx Context = new ServiceCtx(
  81. Ns,
  82. Process,
  83. Memory,
  84. Session,
  85. Request,
  86. Response,
  87. ReqReader,
  88. ResWriter);
  89. long Result = ProcReq(Context);
  90. Response = FillResponse(Response, Result, ResMS.ToArray());
  91. }
  92. }
  93. else if (!IgnoreNullPR)
  94. {
  95. throw new NotImplementedException(DbgServiceName);
  96. }
  97. }
  98. else if (Request.Type == IpcMessageType.Control)
  99. {
  100. long Magic = ReqReader.ReadInt64();
  101. long CmdId = ReqReader.ReadInt64();
  102. switch (CmdId)
  103. {
  104. case 0:
  105. {
  106. HDomain Dom = new HDomain(Session);
  107. Process.HandleTable.ReplaceData(HndId, Dom);
  108. Request = FillResponse(Response, 0, Dom.Add(Dom));
  109. break;
  110. }
  111. case 3:
  112. {
  113. Request = FillResponse(Response, 0, 0x500);
  114. break;
  115. }
  116. //TODO: Whats the difference between IpcDuplicateSession/Ex?
  117. case 2:
  118. case 4:
  119. {
  120. int Unknown = ReqReader.ReadInt32();
  121. int Handle = Process.HandleTable.OpenHandle(Session);
  122. Response.HandleDesc = IpcHandleDesc.MakeMove(Handle);
  123. Request = FillResponse(Response, 0);
  124. break;
  125. }
  126. default: throw new NotImplementedException(CmdId.ToString());
  127. }
  128. }
  129. else if (Request.Type == IpcMessageType.CloseSession)
  130. {
  131. //TODO
  132. }
  133. else
  134. {
  135. throw new NotImplementedException(Request.Type.ToString());
  136. }
  137. AMemoryHelper.WriteBytes(Memory, CmdPtr, Response.GetBytes(CmdPtr));
  138. }
  139. }
  140. private static IpcMessage FillResponse(IpcMessage Response, long Result, params int[] Values)
  141. {
  142. using (MemoryStream MS = new MemoryStream())
  143. {
  144. BinaryWriter Writer = new BinaryWriter(MS);
  145. foreach (int Value in Values)
  146. {
  147. Writer.Write(Value);
  148. }
  149. return FillResponse(Response, Result, MS.ToArray());
  150. }
  151. }
  152. private static IpcMessage FillResponse(IpcMessage Response, long Result, byte[] Data = null)
  153. {
  154. Response.Type = IpcMessageType.Response;
  155. using (MemoryStream MS = new MemoryStream())
  156. {
  157. BinaryWriter Writer = new BinaryWriter(MS);
  158. Writer.Write(SfcoMagic);
  159. Writer.Write(Result);
  160. if (Data != null)
  161. {
  162. Writer.Write(Data);
  163. }
  164. Response.RawData = MS.ToArray();
  165. }
  166. return Response;
  167. }
  168. }
  169. }