aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Core/OsHle/Ipc/IpcHandler.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Ryujinx.Core/OsHle/Ipc/IpcHandler.cs')
-rw-r--r--Ryujinx.Core/OsHle/Ipc/IpcHandler.cs277
1 files changed, 277 insertions, 0 deletions
diff --git a/Ryujinx.Core/OsHle/Ipc/IpcHandler.cs b/Ryujinx.Core/OsHle/Ipc/IpcHandler.cs
new file mode 100644
index 00000000..deab8896
--- /dev/null
+++ b/Ryujinx.Core/OsHle/Ipc/IpcHandler.cs
@@ -0,0 +1,277 @@
+using ChocolArm64.Memory;
+using Ryujinx.Core.OsHle.Handles;
+using Ryujinx.Core.OsHle.Objects;
+using Ryujinx.Core.OsHle.Services;
+using System;
+using System.Collections.Generic;
+using System.IO;
+
+namespace Ryujinx.Core.OsHle.Ipc
+{
+ static class IpcHandler
+ {
+ private static Dictionary<(string, int), ServiceProcessRequest> ServiceCmds =
+ new Dictionary<(string, int), ServiceProcessRequest>()
+ {
+ { ( "acc:u0", 3), Service.AccU0ListOpenUsers },
+ { ( "acc:u0", 5), Service.AccU0GetProfile },
+ { ( "acc:u0", 100), Service.AccU0InitializeApplicationInfo },
+ { ( "acc:u0", 101), Service.AccU0GetBaasAccountManagerForApplication },
+ { ( "apm", 0), Service.ApmOpenSession },
+ { ( "apm:p", 0), Service.ApmOpenSession },
+ { ( "appletOE", 0), Service.AppletOpenApplicationProxy },
+ { ( "audout:u", 0), Service.AudOutListAudioOuts },
+ { ( "audout:u", 1), Service.AudOutOpenAudioOut },
+ { ( "audren:u", 0), Service.AudRenOpenAudioRenderer },
+ { ( "audren:u", 1), Service.AudRenGetAudioRendererWorkBufferSize },
+ { ( "friend:a", 0), Service.FriendCreateFriendService },
+ { ( "fsp-srv", 1), Service.FspSrvInitialize },
+ { ( "fsp-srv", 18), Service.FspSrvMountSdCard },
+ { ( "fsp-srv", 51), Service.FspSrvMountSaveData },
+ { ( "fsp-srv", 200), Service.FspSrvOpenDataStorageByCurrentProcess },
+ { ( "fsp-srv", 203), Service.FspSrvOpenRomStorage },
+ { ( "fsp-srv", 1005), Service.FspSrvGetGlobalAccessLogMode },
+ { ( "hid", 0), Service.HidCreateAppletResource },
+ { ( "hid", 11), Service.HidActivateTouchScreen },
+ { ( "hid", 100), Service.HidSetSupportedNpadStyleSet },
+ { ( "hid", 102), Service.HidSetSupportedNpadIdType },
+ { ( "hid", 103), Service.HidActivateNpad },
+ { ( "hid", 120), Service.HidSetNpadJoyHoldType },
+ { ( "lm", 0), Service.LmInitialize },
+ { ( "nvdrv", 0), Service.NvDrvOpen },
+ { ( "nvdrv", 1), Service.NvDrvIoctl },
+ { ( "nvdrv", 2), Service.NvDrvClose },
+ { ( "nvdrv", 3), Service.NvDrvInitialize },
+ { ( "nvdrv", 4), Service.NvDrvQueryEvent },
+ { ( "nvdrv", 8), Service.NvDrvSetClientPid },
+ { ( "nvdrv:a", 0), Service.NvDrvOpen },
+ { ( "nvdrv:a", 1), Service.NvDrvIoctl },
+ { ( "nvdrv:a", 2), Service.NvDrvClose },
+ { ( "nvdrv:a", 3), Service.NvDrvInitialize },
+ { ( "nvdrv:a", 4), Service.NvDrvQueryEvent },
+ { ( "nvdrv:a", 8), Service.NvDrvSetClientPid },
+ { ( "pctl:a", 0), Service.PctlCreateService },
+ { ( "pl:u", 1), Service.PlGetLoadState },
+ { ( "pl:u", 2), Service.PlGetFontSize },
+ { ( "pl:u", 3), Service.PlGetSharedMemoryAddressOffset },
+ { ( "pl:u", 4), Service.PlGetSharedMemoryNativeHandle },
+ { ( "set", 1), Service.SetGetAvailableLanguageCodes },
+ { ( "sm:", 0), Service.SmInitialize },
+ { ( "sm:", 1), Service.SmGetService },
+ { ( "time:u", 0), Service.TimeGetStandardUserSystemClock },
+ { ( "time:u", 1), Service.TimeGetStandardNetworkSystemClock },
+ { ( "time:u", 2), Service.TimeGetStandardSteadyClock },
+ { ( "time:u", 3), Service.TimeGetTimeZoneService },
+ { ( "time:u", 4), Service.TimeGetStandardLocalSystemClock },
+ { ( "time:s", 0), Service.TimeGetStandardUserSystemClock },
+ { ( "time:s", 1), Service.TimeGetStandardNetworkSystemClock },
+ { ( "time:s", 2), Service.TimeGetStandardSteadyClock },
+ { ( "time:s", 3), Service.TimeGetTimeZoneService },
+ { ( "time:s", 4), Service.TimeGetStandardLocalSystemClock },
+ { ( "vi:m", 2), Service.ViGetDisplayService },
+ };
+
+ private const long SfciMagic = 'S' << 0 | 'F' << 8 | 'C' << 16 | 'I' << 24;
+ private const long SfcoMagic = 'S' << 0 | 'F' << 8 | 'C' << 16 | 'O' << 24;
+
+ public static void IpcCall(
+ Switch Ns,
+ AMemory Memory,
+ HSession Session,
+ IpcMessage Request,
+ long CmdPtr,
+ int HndId)
+ {
+ IpcMessage Response = new IpcMessage(Request.IsDomain);
+
+ using (MemoryStream Raw = new MemoryStream(Request.RawData))
+ {
+ BinaryReader ReqReader = new BinaryReader(Raw);
+
+ if (Request.Type == IpcMessageType.Request)
+ {
+ string ServiceName = Session.ServiceName;
+
+ ServiceProcessRequest ProcReq = null;
+
+ bool IgnoreNullPR = false;
+
+ string DbgServiceName = string.Empty;
+
+ if (Session is HDomain Dom)
+ {
+ if (Request.DomCmd == IpcDomCmd.SendMsg)
+ {
+ long Magic = ReqReader.ReadInt64();
+ int CmdId = (int)ReqReader.ReadInt64();
+
+ object Obj = Dom.GetObject(Request.DomObjId);
+
+ if (Obj is HDomain)
+ {
+ ServiceCmds.TryGetValue((ServiceName, CmdId), out ProcReq);
+
+ DbgServiceName = $"{ServiceName} {ProcReq?.Method.Name ?? CmdId.ToString()}";
+ }
+ else if (Obj != null)
+ {
+ ((IIpcInterface)Obj).Commands.TryGetValue(CmdId, out ProcReq);
+
+ DbgServiceName = $"{ServiceName} {Obj.GetType().Name} {ProcReq?.Method.Name ?? CmdId.ToString()}";
+ }
+ }
+ else if (Request.DomCmd == IpcDomCmd.DeleteObj)
+ {
+ Dom.DeleteObject(Request.DomObjId);
+
+ Response = FillResponse(Response, 0);
+
+ IgnoreNullPR = true;
+ }
+ }
+ else
+ {
+ long Magic = ReqReader.ReadInt64();
+ int CmdId = (int)ReqReader.ReadInt64();
+
+ if (Session is HSessionObj)
+ {
+ object Obj = ((HSessionObj)Session).Obj;
+
+ ((IIpcInterface)Obj).Commands.TryGetValue(CmdId, out ProcReq);
+
+ DbgServiceName = $"{ServiceName} {Obj.GetType().Name} {ProcReq?.Method.Name ?? CmdId.ToString()}";
+ }
+ else
+ {
+ ServiceCmds.TryGetValue((ServiceName, CmdId), out ProcReq);
+
+ DbgServiceName = $"{ServiceName} {ProcReq?.Method.Name ?? CmdId.ToString()}";
+ }
+ }
+
+ Logging.Debug($"IpcMessage: {DbgServiceName}");
+
+ if (ProcReq != null)
+ {
+ using (MemoryStream ResMS = new MemoryStream())
+ {
+ BinaryWriter ResWriter = new BinaryWriter(ResMS);
+
+ ServiceCtx Context = new ServiceCtx(
+ Ns,
+ Memory,
+ Session,
+ Request,
+ Response,
+ ReqReader,
+ ResWriter);
+
+ long Result = ProcReq(Context);
+
+ Response = FillResponse(Response, Result, ResMS.ToArray());
+ }
+ }
+ else if (!IgnoreNullPR)
+ {
+ throw new NotImplementedException(DbgServiceName);
+ }
+ }
+ else if (Request.Type == IpcMessageType.Control)
+ {
+ long Magic = ReqReader.ReadInt64();
+ long CmdId = ReqReader.ReadInt64();
+
+ switch (CmdId)
+ {
+ case 0: Request = IpcConvertSessionToDomain(Ns, Session, Response, HndId); break;
+ case 3: Request = IpcQueryBufferPointerSize(Response); break;
+ case 4: Request = IpcDuplicateSessionEx(Ns, Session, Response, ReqReader); break;
+
+ default: throw new NotImplementedException(CmdId.ToString());
+ }
+ }
+ else if (Request.Type == IpcMessageType.Unknown2)
+ {
+ //TODO
+ }
+ else
+ {
+ throw new NotImplementedException(Request.Type.ToString());
+ }
+
+ AMemoryHelper.WriteBytes(Memory, CmdPtr, Response.GetBytes(CmdPtr));
+ }
+ }
+
+ private static IpcMessage IpcConvertSessionToDomain(
+ Switch Ns,
+ HSession Session,
+ IpcMessage Response,
+ int HndId)
+ {
+ HDomain Dom = new HDomain(Session);
+
+ Ns.Os.Handles.ReplaceData(HndId, Dom);
+
+ return FillResponse(Response, 0, Dom.GenerateObjectId(Dom));
+ }
+
+ private static IpcMessage IpcDuplicateSessionEx(
+ Switch Ns,
+ HSession Session,
+ IpcMessage Response,
+ BinaryReader ReqReader)
+ {
+ int Unknown = ReqReader.ReadInt32();
+
+ int Handle = Ns.Os.Handles.GenerateId(Session);
+
+ Response.HandleDesc = IpcHandleDesc.MakeMove(Handle);
+
+ return FillResponse(Response, 0);
+ }
+
+ private static IpcMessage IpcQueryBufferPointerSize(IpcMessage Response)
+ {
+ return FillResponse(Response, 0, 0x500);
+ }
+
+ 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(SfcoMagic);
+ Writer.Write(Result);
+
+ if (Data != null)
+ {
+ Writer.Write(Data);
+ }
+
+ Response.RawData = MS.ToArray();
+ }
+
+ return Response;
+ }
+ }
+} \ No newline at end of file