aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Core/OsHle/Ipc
diff options
context:
space:
mode:
authoremmauss <emmausssss@gmail.com>2018-02-20 22:09:23 +0200
committergdkchan <gab.dark.100@gmail.com>2018-02-20 17:09:23 -0300
commit62b827f474f0aa2152dd339fcc7cf31084e16a0b (patch)
tree0e5c55b341aee4db0ccb841a084f253ec5e05657 /Ryujinx.Core/OsHle/Ipc
parentcb665bb715834526d73c9469d16114b287faaecd (diff)
Split main project into core,graphics and chocolarm4 subproject (#29)
Diffstat (limited to 'Ryujinx.Core/OsHle/Ipc')
-rw-r--r--Ryujinx.Core/OsHle/Ipc/IpcBuffDesc.cs27
-rw-r--r--Ryujinx.Core/OsHle/Ipc/IpcDomCmd.cs8
-rw-r--r--Ryujinx.Core/OsHle/Ipc/IpcHandleDesc.cs90
-rw-r--r--Ryujinx.Core/OsHle/Ipc/IpcHandler.cs277
-rw-r--r--Ryujinx.Core/OsHle/Ipc/IpcMessage.cs231
-rw-r--r--Ryujinx.Core/OsHle/Ipc/IpcMessageType.cs10
-rw-r--r--Ryujinx.Core/OsHle/Ipc/IpcPtrBuffDesc.cs26
-rw-r--r--Ryujinx.Core/OsHle/Ipc/IpcRecvListBuffDesc.cs19
-rw-r--r--Ryujinx.Core/OsHle/Ipc/ServiceProcessRequest.cs4
9 files changed, 692 insertions, 0 deletions
diff --git a/Ryujinx.Core/OsHle/Ipc/IpcBuffDesc.cs b/Ryujinx.Core/OsHle/Ipc/IpcBuffDesc.cs
new file mode 100644
index 00000000..01bb1539
--- /dev/null
+++ b/Ryujinx.Core/OsHle/Ipc/IpcBuffDesc.cs
@@ -0,0 +1,27 @@
+using System.IO;
+
+namespace Ryujinx.Core.OsHle.Ipc
+{
+ struct IpcBuffDesc
+ {
+ public long Position { get; private set; }
+ public long Size { get; private set; }
+ public int Flags { get; private set; }
+
+ public IpcBuffDesc(BinaryReader Reader)
+ {
+ long Word0 = Reader.ReadUInt32();
+ long Word1 = Reader.ReadUInt32();
+ long Word2 = Reader.ReadUInt32();
+
+ Position = Word1;
+ Position |= (Word2 << 4) & 0x0f00000000;
+ Position |= (Word2 << 34) & 0x7000000000;
+
+ Size = Word0;
+ Size |= (Word2 << 8) & 0xf00000000;
+
+ Flags = (int)Word2 & 3;
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Core/OsHle/Ipc/IpcDomCmd.cs b/Ryujinx.Core/OsHle/Ipc/IpcDomCmd.cs
new file mode 100644
index 00000000..1ef0c408
--- /dev/null
+++ b/Ryujinx.Core/OsHle/Ipc/IpcDomCmd.cs
@@ -0,0 +1,8 @@
+namespace Ryujinx.Core.OsHle.Ipc
+{
+ enum IpcDomCmd
+ {
+ SendMsg = 1,
+ DeleteObj = 2
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Core/OsHle/Ipc/IpcHandleDesc.cs b/Ryujinx.Core/OsHle/Ipc/IpcHandleDesc.cs
new file mode 100644
index 00000000..572c0e64
--- /dev/null
+++ b/Ryujinx.Core/OsHle/Ipc/IpcHandleDesc.cs
@@ -0,0 +1,90 @@
+using System;
+using System.IO;
+
+namespace Ryujinx.Core.OsHle.Ipc
+{
+ class IpcHandleDesc
+ {
+ public bool HasPId { get; private set; }
+
+ public long PId { get; private set; }
+
+ public int[] ToCopy { get; private set; }
+ public int[] ToMove { get; private set; }
+
+ public IpcHandleDesc(BinaryReader Reader)
+ {
+ int Word = Reader.ReadInt32();
+
+ HasPId = (Word & 1) != 0;
+
+ ToCopy = new int[(Word >> 1) & 0xf];
+ ToMove = new int[(Word >> 5) & 0xf];
+
+ PId = HasPId ? Reader.ReadInt64() : 0;
+
+ for (int Index = 0; Index < ToCopy.Length; Index++)
+ {
+ ToCopy[Index] = Reader.ReadInt32();
+ }
+
+ for (int Index = 0; Index < ToMove.Length; Index++)
+ {
+ ToMove[Index] = Reader.ReadInt32();
+ }
+ }
+
+ public IpcHandleDesc(int[] Copy, int[] Move)
+ {
+ ToCopy = Copy ?? throw new ArgumentNullException(nameof(Copy));
+ ToMove = Move ?? throw new ArgumentNullException(nameof(Move));
+ }
+
+ public IpcHandleDesc(int[] Copy, int[] Move, long PId) : this(Copy, Move)
+ {
+ this.PId = PId;
+
+ HasPId = true;
+ }
+
+ public static IpcHandleDesc MakeCopy(int Handle) => new IpcHandleDesc(
+ new int[] { Handle },
+ new int[0]);
+
+ public static IpcHandleDesc MakeMove(int Handle) => new IpcHandleDesc(
+ new int[0],
+ new int[] { Handle });
+
+ public byte[] GetBytes()
+ {
+ using (MemoryStream MS = new MemoryStream())
+ {
+ BinaryWriter Writer = new BinaryWriter(MS);
+
+ int Word = HasPId ? 1 : 0;
+
+ Word |= (ToCopy.Length & 0xf) << 1;
+ Word |= (ToMove.Length & 0xf) << 5;
+
+ Writer.Write(Word);
+
+ if (HasPId)
+ {
+ Writer.Write((long)PId);
+ }
+
+ foreach (int Handle in ToCopy)
+ {
+ Writer.Write(Handle);
+ }
+
+ foreach (int Handle in ToMove)
+ {
+ Writer.Write(Handle);
+ }
+
+ return MS.ToArray();
+ }
+ }
+ }
+} \ No newline at end of file
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
diff --git a/Ryujinx.Core/OsHle/Ipc/IpcMessage.cs b/Ryujinx.Core/OsHle/Ipc/IpcMessage.cs
new file mode 100644
index 00000000..3b38c451
--- /dev/null
+++ b/Ryujinx.Core/OsHle/Ipc/IpcMessage.cs
@@ -0,0 +1,231 @@
+using System.Collections.Generic;
+using System.IO;
+
+namespace Ryujinx.Core.OsHle.Ipc
+{
+ class IpcMessage
+ {
+ public IpcMessageType Type { get; set; }
+
+ public IpcHandleDesc HandleDesc { get; set; }
+
+ public List<IpcPtrBuffDesc> PtrBuff { get; private set; }
+ public List<IpcBuffDesc> SendBuff { get; private set; }
+ public List<IpcBuffDesc> ReceiveBuff { get; private set; }
+ public List<IpcBuffDesc> ExchangeBuff { get; private set; }
+ public List<IpcRecvListBuffDesc> RecvListBuff { get; private set; }
+
+ public List<int> ResponseObjIds { get; private set; }
+
+ public bool IsDomain { get; private set; }
+ public IpcDomCmd DomCmd { get; private set; }
+ public int DomObjId { get; private set; }
+
+ public byte[] RawData { get; set; }
+
+ public IpcMessage()
+ {
+ PtrBuff = new List<IpcPtrBuffDesc>();
+ SendBuff = new List<IpcBuffDesc>();
+ ReceiveBuff = new List<IpcBuffDesc>();
+ ExchangeBuff = new List<IpcBuffDesc>();
+ RecvListBuff = new List<IpcRecvListBuffDesc>();
+
+ ResponseObjIds = new List<int>();
+ }
+
+ public IpcMessage(bool Domain) : this()
+ {
+ IsDomain = Domain;
+ }
+
+ public IpcMessage(byte[] Data, long CmdPtr, bool Domain) : this()
+ {
+ using (MemoryStream MS = new MemoryStream(Data))
+ {
+ BinaryReader Reader = new BinaryReader(MS);
+
+ Initialize(Reader, CmdPtr, Domain);
+ }
+ }
+
+ private void Initialize(BinaryReader Reader, long CmdPtr, bool Domain)
+ {
+ IsDomain = Domain;
+
+ int Word0 = Reader.ReadInt32();
+ int Word1 = Reader.ReadInt32();
+
+ Type = (IpcMessageType)(Word0 & 0xffff);
+
+ int PtrBuffCount = (Word0 >> 16) & 0xf;
+ int SendBuffCount = (Word0 >> 20) & 0xf;
+ int RecvBuffCount = (Word0 >> 24) & 0xf;
+ int XchgBuffCount = (Word0 >> 28) & 0xf;
+
+ int RawDataSize = (Word1 >> 0) & 0x3ff;
+ int RecvListFlags = (Word1 >> 10) & 0xf;
+ bool HndDescEnable = ((Word1 >> 31) & 0x1) != 0;
+
+ if (HndDescEnable)
+ {
+ HandleDesc = new IpcHandleDesc(Reader);
+ }
+
+ for (int Index = 0; Index < PtrBuffCount; Index++)
+ {
+ PtrBuff.Add(new IpcPtrBuffDesc(Reader));
+ }
+
+ void ReadBuff(List<IpcBuffDesc> Buff, int Count)
+ {
+ for (int Index = 0; Index < Count; Index++)
+ {
+ Buff.Add(new IpcBuffDesc(Reader));
+ }
+ }
+
+ ReadBuff(SendBuff, SendBuffCount);
+ ReadBuff(ReceiveBuff, RecvBuffCount);
+ ReadBuff(ExchangeBuff, XchgBuffCount);
+
+ RawDataSize *= 4;
+
+ long RecvListPos = Reader.BaseStream.Position + RawDataSize;
+
+ long Pad0 = GetPadSize16(Reader.BaseStream.Position + CmdPtr);
+
+ Reader.BaseStream.Seek(Pad0, SeekOrigin.Current);
+
+ int RecvListCount = RecvListFlags - 2;
+
+ if (RecvListCount == 0)
+ {
+ RecvListCount = 1;
+ }
+ else if (RecvListCount < 0)
+ {
+ RecvListCount = 0;
+ }
+
+ if (Domain)
+ {
+ int DomWord0 = Reader.ReadInt32();
+
+ DomCmd = (IpcDomCmd)(DomWord0 & 0xff);
+
+ RawDataSize = (DomWord0 >> 16) & 0xffff;
+
+ DomObjId = Reader.ReadInt32();
+
+ Reader.ReadInt64(); //Padding
+ }
+
+ RawData = Reader.ReadBytes(RawDataSize);
+
+ Reader.BaseStream.Seek(RecvListPos, SeekOrigin.Begin);
+
+ for (int Index = 0; Index < RecvListCount; Index++)
+ {
+ RecvListBuff.Add(new IpcRecvListBuffDesc(Reader));
+ }
+ }
+
+ public byte[] GetBytes(long CmdPtr)
+ {
+ //todo
+ using (MemoryStream MS = new MemoryStream())
+ {
+ BinaryWriter Writer = new BinaryWriter(MS);
+
+ int Word0;
+ int Word1;
+
+ Word0 = (int)Type;
+ Word0 |= (PtrBuff.Count & 0xf) << 16;
+ Word0 |= (SendBuff.Count & 0xf) << 20;
+ Word0 |= (ReceiveBuff.Count & 0xf) << 24;
+ Word0 |= (ExchangeBuff.Count & 0xf) << 28;
+
+ byte[] HandleData = new byte[0];
+
+ if (HandleDesc != null)
+ {
+ HandleData = HandleDesc.GetBytes();
+ }
+
+ int DataLength = RawData?.Length ?? 0;
+
+ int Pad0 = (int)GetPadSize16(CmdPtr + 8 + HandleData.Length);
+
+ //Apparently, padding after Raw Data is 16 bytes, however when there is
+ //padding before Raw Data too, we need to subtract the size of this padding.
+ //This is the weirdest padding I've seen so far...
+ int Pad1 = 0x10 - Pad0;
+
+ DataLength = (DataLength + Pad0 + Pad1 + (IsDomain ? 0x10 : 0)) / 4;
+
+ DataLength += ResponseObjIds.Count;
+
+ Word1 = DataLength & 0x3ff;
+
+ if (HandleDesc != null)
+ {
+ Word1 |= 1 << 31;
+ }
+
+ Writer.Write(Word0);
+ Writer.Write(Word1);
+ Writer.Write(HandleData);
+
+ MS.Seek(Pad0, SeekOrigin.Current);
+
+ if (IsDomain)
+ {
+ Writer.Write(ResponseObjIds.Count);
+ Writer.Write(0);
+ Writer.Write(0L);
+ }
+
+ if (RawData != null)
+ {
+ Writer.Write(RawData);
+ }
+
+ foreach (int Id in ResponseObjIds)
+ {
+ Writer.Write(Id);
+ }
+
+ Writer.Write(new byte[Pad1]);
+
+ return MS.ToArray();
+ }
+ }
+
+ private long GetPadSize16(long Position)
+ {
+ if ((Position & 0xf) != 0)
+ {
+ return 0x10 - (Position & 0xf);
+ }
+
+ return 0;
+ }
+
+ public long GetSendBuffPtr()
+ {
+ if (SendBuff.Count > 0 && SendBuff[0].Position != 0)
+ {
+ return SendBuff[0].Position;
+ }
+
+ if (PtrBuff.Count > 0 && PtrBuff[0].Position != 0)
+ {
+ return PtrBuff[0].Position;
+ }
+
+ return -1;
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Core/OsHle/Ipc/IpcMessageType.cs b/Ryujinx.Core/OsHle/Ipc/IpcMessageType.cs
new file mode 100644
index 00000000..8027508d
--- /dev/null
+++ b/Ryujinx.Core/OsHle/Ipc/IpcMessageType.cs
@@ -0,0 +1,10 @@
+namespace Ryujinx.Core.OsHle.Ipc
+{
+ enum IpcMessageType
+ {
+ Response = 0,
+ Unknown2 = 2,
+ Request = 4,
+ Control = 5
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Core/OsHle/Ipc/IpcPtrBuffDesc.cs b/Ryujinx.Core/OsHle/Ipc/IpcPtrBuffDesc.cs
new file mode 100644
index 00000000..d39f78db
--- /dev/null
+++ b/Ryujinx.Core/OsHle/Ipc/IpcPtrBuffDesc.cs
@@ -0,0 +1,26 @@
+using System.IO;
+
+namespace Ryujinx.Core.OsHle.Ipc
+{
+ struct IpcPtrBuffDesc
+ {
+ public long Position { get; private set; }
+ public int Index { get; private set; }
+ public short Size { get; private set; }
+
+ public IpcPtrBuffDesc(BinaryReader Reader)
+ {
+ long Word0 = Reader.ReadUInt32();
+ long Word1 = Reader.ReadUInt32();
+
+ Position = Word1;
+ Position |= (Word0 << 20) & 0x0f00000000;
+ Position |= (Word0 << 30) & 0x7000000000;
+
+ Index = ((int)Word0 >> 0) & 0x03f;
+ Index |= ((int)Word0 >> 3) & 0x1c0;
+
+ Size = (short)(Word0 >> 16);
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Core/OsHle/Ipc/IpcRecvListBuffDesc.cs b/Ryujinx.Core/OsHle/Ipc/IpcRecvListBuffDesc.cs
new file mode 100644
index 00000000..c647208f
--- /dev/null
+++ b/Ryujinx.Core/OsHle/Ipc/IpcRecvListBuffDesc.cs
@@ -0,0 +1,19 @@
+using System.IO;
+
+namespace Ryujinx.Core.OsHle.Ipc
+{
+ struct IpcRecvListBuffDesc
+ {
+ public long Position { get; private set; }
+ public short Size { get; private set; }
+
+ public IpcRecvListBuffDesc(BinaryReader Reader)
+ {
+ long Value = Reader.ReadInt64();
+
+ Position = Value & 0xffffffffffff;
+
+ Size = (short)(Value >> 48);
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Core/OsHle/Ipc/ServiceProcessRequest.cs b/Ryujinx.Core/OsHle/Ipc/ServiceProcessRequest.cs
new file mode 100644
index 00000000..ea758074
--- /dev/null
+++ b/Ryujinx.Core/OsHle/Ipc/ServiceProcessRequest.cs
@@ -0,0 +1,4 @@
+namespace Ryujinx.Core.OsHle.Ipc
+{
+ delegate long ServiceProcessRequest(ServiceCtx Context);
+} \ No newline at end of file