diff options
| author | TSR Berry <20988865+TSRBerry@users.noreply.github.com> | 2023-04-08 01:22:00 +0200 |
|---|---|---|
| committer | Mary <thog@protonmail.com> | 2023-04-27 23:51:14 +0200 |
| commit | cee712105850ac3385cd0091a923438167433f9f (patch) | |
| tree | 4a5274b21d8b7f938c0d0ce18736d3f2993b11b1 /src/Ryujinx.HLE/HOS/Ipc | |
| parent | cd124bda587ef09668a971fa1cac1c3f0cfc9f21 (diff) | |
Move solution and projects to src
Diffstat (limited to 'src/Ryujinx.HLE/HOS/Ipc')
| -rw-r--r-- | src/Ryujinx.HLE/HOS/Ipc/IpcBuffDesc.cs | 27 | ||||
| -rw-r--r-- | src/Ryujinx.HLE/HOS/Ipc/IpcHandleDesc.cs | 93 | ||||
| -rw-r--r-- | src/Ryujinx.HLE/HOS/Ipc/IpcMagic.cs | 8 | ||||
| -rw-r--r-- | src/Ryujinx.HLE/HOS/Ipc/IpcMessage.cs | 283 | ||||
| -rw-r--r-- | src/Ryujinx.HLE/HOS/Ipc/IpcMessageType.cs | 13 | ||||
| -rw-r--r-- | src/Ryujinx.HLE/HOS/Ipc/IpcPtrBuffDesc.cs | 58 | ||||
| -rw-r--r-- | src/Ryujinx.HLE/HOS/Ipc/IpcRecvListBuffDesc.cs | 23 | ||||
| -rw-r--r-- | src/Ryujinx.HLE/HOS/Ipc/ServiceProcessRequest.cs | 4 |
8 files changed, 509 insertions, 0 deletions
diff --git a/src/Ryujinx.HLE/HOS/Ipc/IpcBuffDesc.cs b/src/Ryujinx.HLE/HOS/Ipc/IpcBuffDesc.cs new file mode 100644 index 00000000..b61d5697 --- /dev/null +++ b/src/Ryujinx.HLE/HOS/Ipc/IpcBuffDesc.cs @@ -0,0 +1,27 @@ +using System.IO; + +namespace Ryujinx.HLE.HOS.Ipc +{ + struct IpcBuffDesc + { + public ulong Position { get; private set; } + public ulong Size { get; private set; } + public byte Flags { get; private set; } + + public IpcBuffDesc(BinaryReader reader) + { + ulong word0 = reader.ReadUInt32(); + ulong word1 = reader.ReadUInt32(); + ulong word2 = reader.ReadUInt32(); + + Position = word1; + Position |= (word2 << 4) & 0x0f00000000; + Position |= (word2 << 34) & 0x7000000000; + + Size = word0; + Size |= (word2 << 8) & 0xf00000000; + + Flags = (byte)(word2 & 3); + } + } +}
\ No newline at end of file diff --git a/src/Ryujinx.HLE/HOS/Ipc/IpcHandleDesc.cs b/src/Ryujinx.HLE/HOS/Ipc/IpcHandleDesc.cs new file mode 100644 index 00000000..c7ef7e9c --- /dev/null +++ b/src/Ryujinx.HLE/HOS/Ipc/IpcHandleDesc.cs @@ -0,0 +1,93 @@ +using Microsoft.IO; +using Ryujinx.Common; +using Ryujinx.Common.Memory; +using System; +using System.IO; + +namespace Ryujinx.HLE.HOS.Ipc +{ + class IpcHandleDesc + { + public bool HasPId { get; private set; } + + public ulong 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; + + PId = HasPId ? reader.ReadUInt64() : 0; + + int toCopySize = (word >> 1) & 0xf; + int[] toCopy = toCopySize == 0 ? Array.Empty<int>() : new int[toCopySize]; + + for (int index = 0; index < toCopy.Length; index++) + { + toCopy[index] = reader.ReadInt32(); + } + + ToCopy = toCopy; + + int toMoveSize = (word >> 5) & 0xf; + int[] toMove = toMoveSize == 0 ? Array.Empty<int>() : new int[toMoveSize]; + + for (int index = 0; index < toMove.Length; index++) + { + toMove[index] = reader.ReadInt32(); + } + + ToMove = toMove; + } + + 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, ulong pId) : this(copy, move) + { + PId = pId; + + HasPId = true; + } + + public static IpcHandleDesc MakeCopy(params int[] handles) + { + return new IpcHandleDesc(handles, Array.Empty<int>()); + } + + public static IpcHandleDesc MakeMove(params int[] handles) + { + return new IpcHandleDesc(Array.Empty<int>(), handles); + } + + public RecyclableMemoryStream GetStream() + { + RecyclableMemoryStream ms = MemoryStreamManager.Shared.GetStream(); + + int word = HasPId ? 1 : 0; + + word |= (ToCopy.Length & 0xf) << 1; + word |= (ToMove.Length & 0xf) << 5; + + ms.Write(word); + + if (HasPId) + { + ms.Write(PId); + } + + ms.Write(ToCopy); + ms.Write(ToMove); + + ms.Position = 0; + return ms; + } + } +}
\ No newline at end of file diff --git a/src/Ryujinx.HLE/HOS/Ipc/IpcMagic.cs b/src/Ryujinx.HLE/HOS/Ipc/IpcMagic.cs new file mode 100644 index 00000000..72770b90 --- /dev/null +++ b/src/Ryujinx.HLE/HOS/Ipc/IpcMagic.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Ipc +{ + abstract class IpcMagic + { + public const long Sfci = 'S' << 0 | 'F' << 8 | 'C' << 16 | 'I' << 24; + public const long Sfco = 'S' << 0 | 'F' << 8 | 'C' << 16 | 'O' << 24; + } +}
\ No newline at end of file diff --git a/src/Ryujinx.HLE/HOS/Ipc/IpcMessage.cs b/src/Ryujinx.HLE/HOS/Ipc/IpcMessage.cs new file mode 100644 index 00000000..21630c42 --- /dev/null +++ b/src/Ryujinx.HLE/HOS/Ipc/IpcMessage.cs @@ -0,0 +1,283 @@ +using Microsoft.IO; +using Ryujinx.Common; +using Ryujinx.Common.Memory; +using System; +using System.Buffers; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; + +namespace Ryujinx.HLE.HOS.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> ObjectIds { get; private set; } + + public byte[] RawData { get; set; } + + public IpcMessage() + { + PtrBuff = new List<IpcPtrBuffDesc>(0); + SendBuff = new List<IpcBuffDesc>(0); + ReceiveBuff = new List<IpcBuffDesc>(0); + ExchangeBuff = new List<IpcBuffDesc>(0); + RecvListBuff = new List<IpcRecvListBuffDesc>(0); + + ObjectIds = new List<int>(0); + } + + public IpcMessage(ReadOnlySpan<byte> data, long cmdPtr) + { + using (RecyclableMemoryStream ms = MemoryStreamManager.Shared.GetStream(data)) + { + BinaryReader reader = new BinaryReader(ms); + + 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); + } + + PtrBuff = new List<IpcPtrBuffDesc>(ptrBuffCount); + + for (int index = 0; index < ptrBuffCount; index++) + { + PtrBuff.Add(new IpcPtrBuffDesc(reader)); + } + + static List<IpcBuffDesc> ReadBuff(BinaryReader reader, int count) + { + List<IpcBuffDesc> buff = new List<IpcBuffDesc>(count); + + for (int index = 0; index < count; index++) + { + buff.Add(new IpcBuffDesc(reader)); + } + + return buff; + } + + SendBuff = ReadBuff(reader, sendBuffCount); + ReceiveBuff = ReadBuff(reader, recvBuffCount); + ExchangeBuff = ReadBuff(reader, xchgBuffCount); + + rawDataSize *= 4; + + long recvListPos = reader.BaseStream.Position + rawDataSize; + + // Only CMIF has the padding requirements. + if (Type < IpcMessageType.TipcCloseSession) + { + long pad0 = GetPadSize16(reader.BaseStream.Position + cmdPtr); + + if (rawDataSize != 0) + { + rawDataSize -= (int)pad0; + } + + reader.BaseStream.Seek(pad0, SeekOrigin.Current); + } + + int recvListCount = recvListFlags - 2; + + if (recvListCount == 0) + { + recvListCount = 1; + } + else if (recvListCount < 0) + { + recvListCount = 0; + } + + RawData = reader.ReadBytes(rawDataSize); + + reader.BaseStream.Seek(recvListPos, SeekOrigin.Begin); + + RecvListBuff = new List<IpcRecvListBuffDesc>(recvListCount); + + for (int index = 0; index < recvListCount; index++) + { + RecvListBuff.Add(new IpcRecvListBuffDesc(reader.ReadUInt64())); + } + + ObjectIds = new List<int>(0); + } + } + + public RecyclableMemoryStream GetStream(long cmdPtr, ulong recvListAddr) + { + RecyclableMemoryStream ms = MemoryStreamManager.Shared.GetStream(); + + 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; + + using RecyclableMemoryStream handleDataStream = HandleDesc?.GetStream(); + + int dataLength = RawData?.Length ?? 0; + + dataLength = (dataLength + 3) & ~3; + + int rawLength = dataLength; + + int pad0 = (int)GetPadSize16(cmdPtr + 8 + (handleDataStream?.Length ?? 0) + PtrBuff.Count * 8); + + // 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) / 4; + + word1 = (dataLength & 0x3ff) | (2 << 10); + + if (HandleDesc != null) + { + word1 |= 1 << 31; + } + + ms.Write(word0); + ms.Write(word1); + + if (handleDataStream != null) + { + ms.Write(handleDataStream); + } + + foreach (IpcPtrBuffDesc ptrBuffDesc in PtrBuff) + { + ms.Write(ptrBuffDesc.GetWord0()); + ms.Write(ptrBuffDesc.GetWord1()); + } + + ms.WriteByte(0, pad0); + + if (RawData != null) + { + ms.Write(RawData); + ms.WriteByte(0, rawLength - RawData.Length); + } + + ms.WriteByte(0, pad1); + + ms.Write(recvListAddr); + + ms.Position = 0; + + return ms; + } + + public RecyclableMemoryStream GetStreamTipc() + { + Debug.Assert(PtrBuff.Count == 0); + + RecyclableMemoryStream ms = MemoryStreamManager.Shared.GetStream(); + + int word0; + int word1; + + word0 = (int)Type; + word0 |= (SendBuff.Count & 0xf) << 20; + word0 |= (ReceiveBuff.Count & 0xf) << 24; + word0 |= (ExchangeBuff.Count & 0xf) << 28; + + using RecyclableMemoryStream handleDataStream = HandleDesc?.GetStream(); + + int dataLength = RawData?.Length ?? 0; + + dataLength = ((dataLength + 3) & ~3) / 4; + + word1 = (dataLength & 0x3ff); + + if (HandleDesc != null) + { + word1 |= 1 << 31; + } + + ms.Write(word0); + ms.Write(word1); + + if (handleDataStream != null) + { + ms.Write(handleDataStream); + } + + if (RawData != null) + { + ms.Write(RawData); + } + + return ms; + } + + private long GetPadSize16(long position) + { + if ((position & 0xf) != 0) + { + return 0x10 - (position & 0xf); + } + + return 0; + } + + // ReSharper disable once InconsistentNaming + public (ulong Position, ulong Size) GetBufferType0x21(int index = 0) + { + if (PtrBuff.Count > index && PtrBuff[index].Position != 0) + { + return (PtrBuff[index].Position, PtrBuff[index].Size); + } + + if (SendBuff.Count > index) + { + return (SendBuff[index].Position, SendBuff[index].Size); + } + + return (0, 0); + } + + // ReSharper disable once InconsistentNaming + public (ulong Position, ulong Size) GetBufferType0x22(int index = 0) + { + if (RecvListBuff.Count > index && RecvListBuff[index].Position != 0) + { + return (RecvListBuff[index].Position, RecvListBuff[index].Size); + } + + if (ReceiveBuff.Count > index) + { + return (ReceiveBuff[index].Position, ReceiveBuff[index].Size); + } + + return (0, 0); + } + } +} diff --git a/src/Ryujinx.HLE/HOS/Ipc/IpcMessageType.cs b/src/Ryujinx.HLE/HOS/Ipc/IpcMessageType.cs new file mode 100644 index 00000000..1c862248 --- /dev/null +++ b/src/Ryujinx.HLE/HOS/Ipc/IpcMessageType.cs @@ -0,0 +1,13 @@ +namespace Ryujinx.HLE.HOS.Ipc +{ + enum IpcMessageType + { + CmifResponse = 0, + CmifCloseSession = 2, + CmifRequest = 4, + CmifControl = 5, + CmifRequestWithContext = 6, + CmifControlWithContext = 7, + TipcCloseSession = 0xF + } +}
\ No newline at end of file diff --git a/src/Ryujinx.HLE/HOS/Ipc/IpcPtrBuffDesc.cs b/src/Ryujinx.HLE/HOS/Ipc/IpcPtrBuffDesc.cs new file mode 100644 index 00000000..05798fe1 --- /dev/null +++ b/src/Ryujinx.HLE/HOS/Ipc/IpcPtrBuffDesc.cs @@ -0,0 +1,58 @@ +using System.IO; + +namespace Ryujinx.HLE.HOS.Ipc +{ + struct IpcPtrBuffDesc + { + public ulong Position { get; private set; } + public uint Index { get; private set; } + public ulong Size { get; private set; } + + public IpcPtrBuffDesc(ulong position, uint index, ulong size) + { + Position = position; + Index = index; + Size = size; + } + + public IpcPtrBuffDesc(BinaryReader reader) + { + ulong word0 = reader.ReadUInt32(); + ulong word1 = reader.ReadUInt32(); + + Position = word1; + Position |= (word0 << 20) & 0x0f00000000; + Position |= (word0 << 30) & 0x7000000000; + + Index = ((uint)word0 >> 0) & 0x03f; + Index |= ((uint)word0 >> 3) & 0x1c0; + + Size = (ushort)(word0 >> 16); + } + + public IpcPtrBuffDesc WithSize(ulong size) + { + return new IpcPtrBuffDesc(Position, Index, size); + } + + public uint GetWord0() + { + uint word0; + + word0 = (uint)((Position & 0x0f00000000) >> 20); + word0 |= (uint)((Position & 0x7000000000) >> 30); + + word0 |= (Index & 0x03f) << 0; + word0 |= (Index & 0x1c0) << 3; + + word0 |= (uint)Size << 16; + + return word0; + } + + public uint GetWord1() + { + return (uint)Position; + } + } +}
\ No newline at end of file diff --git a/src/Ryujinx.HLE/HOS/Ipc/IpcRecvListBuffDesc.cs b/src/Ryujinx.HLE/HOS/Ipc/IpcRecvListBuffDesc.cs new file mode 100644 index 00000000..bcc9d8f8 --- /dev/null +++ b/src/Ryujinx.HLE/HOS/Ipc/IpcRecvListBuffDesc.cs @@ -0,0 +1,23 @@ +using System.IO; + +namespace Ryujinx.HLE.HOS.Ipc +{ + struct IpcRecvListBuffDesc + { + public ulong Position { get; private set; } + public ulong Size { get; private set; } + + public IpcRecvListBuffDesc(ulong position, ulong size) + { + Position = position; + Size = size; + } + + public IpcRecvListBuffDesc(ulong packedValue) + { + Position = packedValue & 0xffffffffffff; + + Size = (ushort)(packedValue >> 48); + } + } +}
\ No newline at end of file diff --git a/src/Ryujinx.HLE/HOS/Ipc/ServiceProcessRequest.cs b/src/Ryujinx.HLE/HOS/Ipc/ServiceProcessRequest.cs new file mode 100644 index 00000000..b3aaa219 --- /dev/null +++ b/src/Ryujinx.HLE/HOS/Ipc/ServiceProcessRequest.cs @@ -0,0 +1,4 @@ +namespace Ryujinx.HLE.HOS.Ipc +{ + delegate long ServiceProcessRequest(ServiceCtx context); +}
\ No newline at end of file |
