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[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[Unsafe.SizeOf<SpecialHeader>()..]; if (specialHeader.SendPid) { pid = MemoryMarshal.Cast<byte, ulong>(data)[0]; data = data[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[Unsafe.SizeOf<Header>()..]; if (hasSpecialHeader) { MemoryMarshal.Cast<byte, SpecialHeader>(destination)[0] = new SpecialHeader() { SendPid = meta.SendPid, CopyHandlesCount = meta.CopyHandlesCount, MoveHandlesCount = meta.MoveHandlesCount }; destination = destination[Unsafe.SizeOf<SpecialHeader>()..]; if (meta.SendPid) { destination = destination[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)[..meta.CopyHandlesCount]; data = data[(meta.CopyHandlesCount * sizeof(int))..]; } Span<int> moveHandles = Span<int>.Empty; if (meta.MoveHandlesCount != 0) { moveHandles = MemoryMarshal.Cast<byte, int>(data)[..meta.MoveHandlesCount]; data = data[(meta.MoveHandlesCount * sizeof(int))..]; } Span<HipcStaticDescriptor> sendStatics = Span<HipcStaticDescriptor>.Empty; if (meta.SendStaticsCount != 0) { sendStatics = MemoryMarshal.Cast<byte, HipcStaticDescriptor>(data)[..meta.SendStaticsCount]; data = data[(meta.SendStaticsCount * Unsafe.SizeOf<HipcStaticDescriptor>())..]; } Span<HipcBufferDescriptor> sendBuffers = Span<HipcBufferDescriptor>.Empty; if (meta.SendBuffersCount != 0) { sendBuffers = MemoryMarshal.Cast<byte, HipcBufferDescriptor>(data)[..meta.SendBuffersCount]; data = data[(meta.SendBuffersCount * Unsafe.SizeOf<HipcBufferDescriptor>())..]; } Span<HipcBufferDescriptor> receiveBuffers = Span<HipcBufferDescriptor>.Empty; if (meta.ReceiveBuffersCount != 0) { receiveBuffers = MemoryMarshal.Cast<byte, HipcBufferDescriptor>(data)[..meta.ReceiveBuffersCount]; data = data[(meta.ReceiveBuffersCount * Unsafe.SizeOf<HipcBufferDescriptor>())..]; } Span<HipcBufferDescriptor> exchangeBuffers = Span<HipcBufferDescriptor>.Empty; if (meta.ExchangeBuffersCount != 0) { exchangeBuffers = MemoryMarshal.Cast<byte, HipcBufferDescriptor>(data)[..meta.ExchangeBuffersCount]; data = data[(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)[padding..meta.DataWordsCount]; data = data[(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)[..receiveListSize]; } return new HipcMessageData() { SendStatics = sendStatics, SendBuffers = sendBuffers, ReceiveBuffers = receiveBuffers, ExchangeBuffers = exchangeBuffers, DataWords = dataWords, ReceiveList = receiveList, CopyHandles = copyHandles, MoveHandles = moveHandles }; } } }