IpcHandler.cs 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. using ARMeilleure.Memory;
  2. using Ryujinx.HLE.HOS.Kernel.Common;
  3. using Ryujinx.HLE.HOS.Kernel.Ipc;
  4. using Ryujinx.HLE.HOS.Kernel.Process;
  5. using Ryujinx.HLE.HOS.Kernel.Threading;
  6. using System;
  7. using System.IO;
  8. namespace Ryujinx.HLE.HOS.Ipc
  9. {
  10. static class IpcHandler
  11. {
  12. public static KernelResult IpcCall(
  13. Switch device,
  14. KProcess process,
  15. IMemoryManager memory,
  16. KThread thread,
  17. KClientSession session,
  18. IpcMessage request,
  19. long cmdPtr)
  20. {
  21. IpcMessage response = new IpcMessage();
  22. using (MemoryStream raw = new MemoryStream(request.RawData))
  23. {
  24. BinaryReader reqReader = new BinaryReader(raw);
  25. if (request.Type == IpcMessageType.Request ||
  26. request.Type == IpcMessageType.RequestWithContext)
  27. {
  28. response.Type = IpcMessageType.Response;
  29. using (MemoryStream resMs = new MemoryStream())
  30. {
  31. BinaryWriter resWriter = new BinaryWriter(resMs);
  32. ServiceCtx context = new ServiceCtx(
  33. device,
  34. process,
  35. memory,
  36. thread,
  37. session,
  38. request,
  39. response,
  40. reqReader,
  41. resWriter);
  42. session.Service.CallMethod(context);
  43. response.RawData = resMs.ToArray();
  44. }
  45. }
  46. else if (request.Type == IpcMessageType.Control ||
  47. request.Type == IpcMessageType.ControlWithContext)
  48. {
  49. long magic = reqReader.ReadInt64();
  50. long cmdId = reqReader.ReadInt64();
  51. switch (cmdId)
  52. {
  53. case 0:
  54. {
  55. request = FillResponse(response, 0, session.Service.ConvertToDomain());
  56. break;
  57. }
  58. case 3:
  59. {
  60. request = FillResponse(response, 0, 0x500);
  61. break;
  62. }
  63. // TODO: Whats the difference between IpcDuplicateSession/Ex?
  64. case 2:
  65. case 4:
  66. {
  67. int unknown = reqReader.ReadInt32();
  68. if (process.HandleTable.GenerateHandle(session, out int handle) != KernelResult.Success)
  69. {
  70. throw new InvalidOperationException("Out of handles!");
  71. }
  72. response.HandleDesc = IpcHandleDesc.MakeMove(handle);
  73. request = FillResponse(response, 0);
  74. break;
  75. }
  76. default: throw new NotImplementedException(cmdId.ToString());
  77. }
  78. }
  79. else if (request.Type == IpcMessageType.CloseSession)
  80. {
  81. // TODO
  82. return KernelResult.PortRemoteClosed;
  83. }
  84. else
  85. {
  86. throw new NotImplementedException(request.Type.ToString());
  87. }
  88. memory.WriteBytes(cmdPtr, response.GetBytes(cmdPtr));
  89. }
  90. return KernelResult.Success;
  91. }
  92. private static IpcMessage FillResponse(IpcMessage response, long result, params int[] values)
  93. {
  94. using (MemoryStream ms = new MemoryStream())
  95. {
  96. BinaryWriter writer = new BinaryWriter(ms);
  97. foreach (int value in values)
  98. {
  99. writer.Write(value);
  100. }
  101. return FillResponse(response, result, ms.ToArray());
  102. }
  103. }
  104. private static IpcMessage FillResponse(IpcMessage response, long result, byte[] data = null)
  105. {
  106. response.Type = IpcMessageType.Response;
  107. using (MemoryStream ms = new MemoryStream())
  108. {
  109. BinaryWriter writer = new BinaryWriter(ms);
  110. writer.Write(IpcMagic.Sfco);
  111. writer.Write(result);
  112. if (data != null)
  113. {
  114. writer.Write(data);
  115. }
  116. response.RawData = ms.ToArray();
  117. }
  118. return response;
  119. }
  120. }
  121. }