aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Core/OsHle/Ipc/IpcMessage.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Ryujinx.Core/OsHle/Ipc/IpcMessage.cs')
-rw-r--r--Ryujinx.Core/OsHle/Ipc/IpcMessage.cs231
1 files changed, 231 insertions, 0 deletions
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