aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcMessage.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Ryujinx.Horizon/Sdk/Sf/Hipc/HipcMessage.cs')
-rw-r--r--Ryujinx.Horizon/Sdk/Sf/Hipc/HipcMessage.cs222
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
+ };
+ }
+ }
+}