diff options
Diffstat (limited to 'Ryujinx.Horizon/Sdk/Sf/Hipc/HipcMessage.cs')
-rw-r--r-- | Ryujinx.Horizon/Sdk/Sf/Hipc/HipcMessage.cs | 222 |
1 files changed, 222 insertions, 0 deletions
diff --git a/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcMessage.cs b/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcMessage.cs new file mode 100644 index 00000000..3017f404 --- /dev/null +++ b/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcMessage.cs @@ -0,0 +1,222 @@ +using Ryujinx.Common; +using Ryujinx.Horizon.Sdk.Sf.Cmif; +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Sf.Hipc +{ + ref struct HipcMessage + { + public const int AutoReceiveStatic = byte.MaxValue; + + public HipcMetadata Meta; + public HipcMessageData Data; + public ulong Pid; + + public HipcMessage(Span<byte> data) + { + int initialLength = data.Length; + + Header header = MemoryMarshal.Cast<byte, Header>(data)[0]; + + data = data.Slice(Unsafe.SizeOf<Header>()); + + int receiveStaticsCount = 0; + ulong pid = 0; + + if (header.ReceiveStaticMode != 0) + { + if (header.ReceiveStaticMode == 2) + { + receiveStaticsCount = AutoReceiveStatic; + } + else if (header.ReceiveStaticMode > 2) + { + receiveStaticsCount = header.ReceiveStaticMode - 2; + } + } + + SpecialHeader specialHeader = default; + + if (header.HasSpecialHeader) + { + specialHeader = MemoryMarshal.Cast<byte, SpecialHeader>(data)[0]; + + data = data.Slice(Unsafe.SizeOf<SpecialHeader>()); + + if (specialHeader.SendPid) + { + pid = MemoryMarshal.Cast<byte, ulong>(data)[0]; + + data = data.Slice(sizeof(ulong)); + } + } + + Meta = new HipcMetadata() + { + Type = (int)header.Type, + SendStaticsCount = header.SendStaticsCount, + SendBuffersCount = header.SendBuffersCount, + ReceiveBuffersCount = header.ReceiveBuffersCount, + ExchangeBuffersCount = header.ExchangeBuffersCount, + DataWordsCount = header.DataWordsCount, + ReceiveStaticsCount = receiveStaticsCount, + SendPid = specialHeader.SendPid, + CopyHandlesCount = specialHeader.CopyHandlesCount, + MoveHandlesCount = specialHeader.MoveHandlesCount + }; + + Data = CreateMessageData(Meta, data, initialLength); + Pid = pid; + } + + public static HipcMessageData WriteResponse( + Span<byte> destination, + int sendStaticCount, + int dataWordsCount, + int copyHandlesCount, + int moveHandlesCount) + { + return WriteMessage(destination, new HipcMetadata() + { + SendStaticsCount = sendStaticCount, + DataWordsCount = dataWordsCount, + CopyHandlesCount = copyHandlesCount, + MoveHandlesCount = moveHandlesCount + }); + } + + public static HipcMessageData WriteMessage(Span<byte> destination, HipcMetadata meta) + { + int initialLength = destination.Length; + + bool hasSpecialHeader = meta.SendPid || meta.CopyHandlesCount != 0 || meta.MoveHandlesCount != 0; + + MemoryMarshal.Cast<byte, Header>(destination)[0] = new Header() + { + Type = (CommandType)meta.Type, + SendStaticsCount = meta.SendStaticsCount, + SendBuffersCount = meta.SendBuffersCount, + ReceiveBuffersCount = meta.ReceiveBuffersCount, + ExchangeBuffersCount = meta.ExchangeBuffersCount, + DataWordsCount = meta.DataWordsCount, + ReceiveStaticMode = meta.ReceiveStaticsCount != 0 ? (meta.ReceiveStaticsCount != AutoReceiveStatic ? meta.ReceiveStaticsCount + 2 : 2) : 0, + HasSpecialHeader = hasSpecialHeader + }; + + destination = destination.Slice(Unsafe.SizeOf<Header>()); + + if (hasSpecialHeader) + { + MemoryMarshal.Cast<byte, SpecialHeader>(destination)[0] = new SpecialHeader() + { + SendPid = meta.SendPid, + CopyHandlesCount = meta.CopyHandlesCount, + MoveHandlesCount = meta.MoveHandlesCount + }; + + destination = destination.Slice(Unsafe.SizeOf<SpecialHeader>()); + + if (meta.SendPid) + { + destination = destination.Slice(sizeof(ulong)); + } + } + + return CreateMessageData(meta, destination, initialLength); + } + + private static HipcMessageData CreateMessageData(HipcMetadata meta, Span<byte> data, int initialLength) + { + Span<int> copyHandles = Span<int>.Empty; + + if (meta.CopyHandlesCount != 0) + { + copyHandles = MemoryMarshal.Cast<byte, int>(data).Slice(0, meta.CopyHandlesCount); + + data = data.Slice(meta.CopyHandlesCount * sizeof(int)); + } + + Span<int> moveHandles = Span<int>.Empty; + + if (meta.MoveHandlesCount != 0) + { + moveHandles = MemoryMarshal.Cast<byte, int>(data).Slice(0, meta.MoveHandlesCount); + + data = data.Slice(meta.MoveHandlesCount * sizeof(int)); + } + + Span<HipcStaticDescriptor> sendStatics = Span<HipcStaticDescriptor>.Empty; + + if (meta.SendStaticsCount != 0) + { + sendStatics = MemoryMarshal.Cast<byte, HipcStaticDescriptor>(data).Slice(0, meta.SendStaticsCount); + + data = data.Slice(meta.SendStaticsCount * Unsafe.SizeOf<HipcStaticDescriptor>()); + } + + Span<HipcBufferDescriptor> sendBuffers = Span<HipcBufferDescriptor>.Empty; + + if (meta.SendBuffersCount != 0) + { + sendBuffers = MemoryMarshal.Cast<byte, HipcBufferDescriptor>(data).Slice(0, meta.SendBuffersCount); + + data = data.Slice(meta.SendBuffersCount * Unsafe.SizeOf<HipcBufferDescriptor>()); + } + + Span<HipcBufferDescriptor> receiveBuffers = Span<HipcBufferDescriptor>.Empty; + + if (meta.ReceiveBuffersCount != 0) + { + receiveBuffers = MemoryMarshal.Cast<byte, HipcBufferDescriptor>(data).Slice(0, meta.ReceiveBuffersCount); + + data = data.Slice(meta.ReceiveBuffersCount * Unsafe.SizeOf<HipcBufferDescriptor>()); + } + + Span<HipcBufferDescriptor> exchangeBuffers = Span<HipcBufferDescriptor>.Empty; + + if (meta.ExchangeBuffersCount != 0) + { + exchangeBuffers = MemoryMarshal.Cast<byte, HipcBufferDescriptor>(data).Slice(0, meta.ExchangeBuffersCount); + + data = data.Slice(meta.ExchangeBuffersCount * Unsafe.SizeOf<HipcBufferDescriptor>()); + } + + Span<uint> dataWords = Span<uint>.Empty; + + if (meta.DataWordsCount != 0) + { + int dataOffset = initialLength - data.Length; + int dataOffsetAligned = BitUtils.AlignUp(dataOffset, 0x10); + + int padding = (dataOffsetAligned - dataOffset) / sizeof(uint); + + dataWords = MemoryMarshal.Cast<byte, uint>(data).Slice(padding, meta.DataWordsCount - padding); + + data = data.Slice(meta.DataWordsCount * sizeof(uint)); + } + + Span<HipcReceiveListEntry> receiveList = Span<HipcReceiveListEntry>.Empty; + + if (meta.ReceiveStaticsCount != 0) + { + int receiveListSize = meta.ReceiveStaticsCount == AutoReceiveStatic ? 1 : meta.ReceiveStaticsCount; + + receiveList = MemoryMarshal.Cast<byte, HipcReceiveListEntry>(data).Slice(0, receiveListSize); + } + + return new HipcMessageData() + { + SendStatics = sendStatics, + SendBuffers = sendBuffers, + ReceiveBuffers = receiveBuffers, + ExchangeBuffers = exchangeBuffers, + DataWords = dataWords, + ReceiveList = receiveList, + CopyHandles = copyHandles, + MoveHandles = moveHandles + }; + } + } +} |