aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.HLE/OsHle/Ipc/IpcHandler.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Ryujinx.HLE/OsHle/Ipc/IpcHandler.cs')
-rw-r--r--Ryujinx.HLE/OsHle/Ipc/IpcHandler.cs138
1 files changed, 138 insertions, 0 deletions
diff --git a/Ryujinx.HLE/OsHle/Ipc/IpcHandler.cs b/Ryujinx.HLE/OsHle/Ipc/IpcHandler.cs
new file mode 100644
index 00000000..9b46cf4b
--- /dev/null
+++ b/Ryujinx.HLE/OsHle/Ipc/IpcHandler.cs
@@ -0,0 +1,138 @@
+using ChocolArm64.Memory;
+using Ryujinx.HLE.OsHle.Handles;
+using System;
+using System.IO;
+
+namespace Ryujinx.HLE.OsHle.Ipc
+{
+ static class IpcHandler
+ {
+ public static long IpcCall(
+ Switch Ns,
+ Process Process,
+ AMemory Memory,
+ KSession Session,
+ IpcMessage Request,
+ long CmdPtr)
+ {
+ IpcMessage Response = new IpcMessage();
+
+ using (MemoryStream Raw = new MemoryStream(Request.RawData))
+ {
+ BinaryReader ReqReader = new BinaryReader(Raw);
+
+ if (Request.Type == IpcMessageType.Request)
+ {
+ Response.Type = IpcMessageType.Response;
+
+ using (MemoryStream ResMS = new MemoryStream())
+ {
+ BinaryWriter ResWriter = new BinaryWriter(ResMS);
+
+ ServiceCtx Context = new ServiceCtx(
+ Ns,
+ Process,
+ Memory,
+ Session,
+ Request,
+ Response,
+ ReqReader,
+ ResWriter);
+
+ Session.Service.CallMethod(Context);
+
+ Response.RawData = ResMS.ToArray();
+ }
+ }
+ else if (Request.Type == IpcMessageType.Control)
+ {
+ long Magic = ReqReader.ReadInt64();
+ long CmdId = ReqReader.ReadInt64();
+
+ switch (CmdId)
+ {
+ case 0:
+ {
+ Request = FillResponse(Response, 0, Session.Service.ConvertToDomain());
+
+ break;
+ }
+
+ case 3:
+ {
+ Request = FillResponse(Response, 0, 0x500);
+
+ break;
+ }
+
+ //TODO: Whats the difference between IpcDuplicateSession/Ex?
+ case 2:
+ case 4:
+ {
+ int Unknown = ReqReader.ReadInt32();
+
+ int Handle = Process.HandleTable.OpenHandle(Session);
+
+ Response.HandleDesc = IpcHandleDesc.MakeMove(Handle);
+
+ Request = FillResponse(Response, 0);
+
+ break;
+ }
+
+ default: throw new NotImplementedException(CmdId.ToString());
+ }
+ }
+ else if (Request.Type == IpcMessageType.CloseSession)
+ {
+ //TODO
+ }
+ else
+ {
+ throw new NotImplementedException(Request.Type.ToString());
+ }
+
+ Memory.WriteBytes(CmdPtr, Response.GetBytes(CmdPtr));
+ }
+
+ return 0;
+ }
+
+ private static IpcMessage FillResponse(IpcMessage Response, long Result, params int[] Values)
+ {
+ using (MemoryStream MS = new MemoryStream())
+ {
+ BinaryWriter Writer = new BinaryWriter(MS);
+
+ foreach (int Value in Values)
+ {
+ Writer.Write(Value);
+ }
+
+ return FillResponse(Response, Result, MS.ToArray());
+ }
+ }
+
+ private static IpcMessage FillResponse(IpcMessage Response, long Result, byte[] Data = null)
+ {
+ Response.Type = IpcMessageType.Response;
+
+ using (MemoryStream MS = new MemoryStream())
+ {
+ BinaryWriter Writer = new BinaryWriter(MS);
+
+ Writer.Write(IpcMagic.Sfco);
+ Writer.Write(Result);
+
+ if (Data != null)
+ {
+ Writer.Write(Data);
+ }
+
+ Response.RawData = MS.ToArray();
+ }
+
+ return Response;
+ }
+ }
+}