ryujinx/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcMessage.cs

223 lines
7.9 KiB
C#
Raw Normal View History

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
};
}
}
}