129 lines
5 KiB
C#
129 lines
5 KiB
C#
|
using Ryujinx.Horizon.Common;
|
|||
|
using Ryujinx.Horizon.Sdk.Sf.Hipc;
|
|||
|
using System;
|
|||
|
using System.Runtime.CompilerServices;
|
|||
|
using System.Runtime.InteropServices;
|
|||
|
|
|||
|
namespace Ryujinx.Horizon.Sdk.Sf.Cmif
|
|||
|
{
|
|||
|
static class CmifMessage
|
|||
|
{
|
|||
|
public const uint CmifInHeaderMagic = 0x49434653; // SFCI
|
|||
|
public const uint CmifOutHeaderMagic = 0x4f434653; // SFCO
|
|||
|
|
|||
|
public static CmifRequest CreateRequest(Span<byte> output, CmifRequestFormat format)
|
|||
|
{
|
|||
|
int totalSize = 16;
|
|||
|
|
|||
|
if (format.ObjectId != 0)
|
|||
|
{
|
|||
|
totalSize += Unsafe.SizeOf<CmifDomainInHeader>() + format.ObjectsCount * sizeof(int);
|
|||
|
}
|
|||
|
|
|||
|
totalSize += Unsafe.SizeOf<CmifInHeader>() + format.DataSize;
|
|||
|
totalSize = (totalSize + 1) & ~1;
|
|||
|
int outPointerSizeTableOffset = totalSize;
|
|||
|
int outPointerSizeTableSize = format.OutAutoBuffersCount + format.OutPointersCount;
|
|||
|
totalSize += sizeof(ushort) * outPointerSizeTableSize;
|
|||
|
int rawDataSizeInWords = (totalSize + sizeof(uint) - 1) / sizeof(uint);
|
|||
|
|
|||
|
CmifRequest request = new CmifRequest();
|
|||
|
|
|||
|
request.Hipc = HipcMessage.WriteMessage(output, new HipcMetadata()
|
|||
|
{
|
|||
|
Type = format.Context != 0 ? (int)CommandType.RequestWithContext : (int)CommandType.Request,
|
|||
|
SendStaticsCount = format.InAutoBuffersCount + format.InPointersCount,
|
|||
|
SendBuffersCount = format.InAutoBuffersCount + format.InBuffersCount,
|
|||
|
ReceiveBuffersCount = format.OutAutoBuffersCount + format.OutBuffersCount,
|
|||
|
ExchangeBuffersCount = format.InOutBuffersCount,
|
|||
|
DataWordsCount = rawDataSizeInWords,
|
|||
|
ReceiveStaticsCount = outPointerSizeTableSize + format.OutFixedPointersCount,
|
|||
|
SendPid = format.SendPid,
|
|||
|
CopyHandlesCount = format.HandlesCount,
|
|||
|
MoveHandlesCount = 0
|
|||
|
});
|
|||
|
|
|||
|
Span<uint> data = request.Hipc.DataWords;
|
|||
|
|
|||
|
if (format.ObjectId != 0)
|
|||
|
{
|
|||
|
ref CmifDomainInHeader domainHeader = ref MemoryMarshal.Cast<uint, CmifDomainInHeader>(data)[0];
|
|||
|
|
|||
|
int payloadSize = Unsafe.SizeOf<CmifInHeader>() + format.DataSize;
|
|||
|
|
|||
|
domainHeader = new CmifDomainInHeader()
|
|||
|
{
|
|||
|
Type = CmifDomainRequestType.SendMessage,
|
|||
|
ObjectsCount = (byte)format.ObjectsCount,
|
|||
|
DataSize = (ushort)payloadSize,
|
|||
|
ObjectId = format.ObjectId,
|
|||
|
Padding = 0,
|
|||
|
Token = format.Context
|
|||
|
};
|
|||
|
|
|||
|
data = data.Slice(Unsafe.SizeOf<CmifDomainInHeader>() / sizeof(uint));
|
|||
|
|
|||
|
request.Objects = data.Slice((payloadSize + sizeof(uint) - 1) / sizeof(uint));
|
|||
|
}
|
|||
|
|
|||
|
ref CmifInHeader header = ref MemoryMarshal.Cast<uint, CmifInHeader>(data)[0];
|
|||
|
|
|||
|
header = new CmifInHeader()
|
|||
|
{
|
|||
|
Magic = CmifInHeaderMagic,
|
|||
|
Version = format.Context != 0 ? 1u : 0u,
|
|||
|
CommandId = format.RequestId,
|
|||
|
Token = format.ObjectId != 0 ? 0u : format.Context
|
|||
|
};
|
|||
|
|
|||
|
request.Data = MemoryMarshal.Cast<uint, byte>(data).Slice(Unsafe.SizeOf<CmifInHeader>());
|
|||
|
|
|||
|
int paddingSizeBefore = (rawDataSizeInWords - request.Hipc.DataWords.Length) * sizeof(uint);
|
|||
|
|
|||
|
Span<byte> outPointerTable = MemoryMarshal.Cast<uint, byte>(request.Hipc.DataWords).Slice(outPointerSizeTableOffset - paddingSizeBefore);
|
|||
|
request.OutPointerSizes = MemoryMarshal.Cast<byte, ushort>(outPointerTable);
|
|||
|
request.ServerPointerSize = format.ServerPointerSize;
|
|||
|
|
|||
|
return request;
|
|||
|
}
|
|||
|
|
|||
|
public static Result ParseResponse(out CmifResponse response, Span<byte> input, bool isDomain, int size)
|
|||
|
{
|
|||
|
HipcMessage responseMessage = new HipcMessage(input);
|
|||
|
|
|||
|
Span<byte> data = MemoryMarshal.Cast<uint, byte>(responseMessage.Data.DataWords);
|
|||
|
Span<uint> objects = Span<uint>.Empty;
|
|||
|
|
|||
|
if (isDomain)
|
|||
|
{
|
|||
|
data = data.Slice(Unsafe.SizeOf<CmifDomainOutHeader>());
|
|||
|
objects = MemoryMarshal.Cast<byte, uint>(data.Slice(Unsafe.SizeOf<CmifOutHeader>() + size));
|
|||
|
}
|
|||
|
|
|||
|
CmifOutHeader header = MemoryMarshal.Cast<byte, CmifOutHeader>(data)[0];
|
|||
|
|
|||
|
if (header.Magic != CmifOutHeaderMagic)
|
|||
|
{
|
|||
|
response = default;
|
|||
|
return SfResult.InvalidOutHeader;
|
|||
|
}
|
|||
|
|
|||
|
if (header.Result.IsFailure)
|
|||
|
{
|
|||
|
response = default;
|
|||
|
return header.Result;
|
|||
|
}
|
|||
|
|
|||
|
response = new CmifResponse()
|
|||
|
{
|
|||
|
Data = data.Slice(Unsafe.SizeOf<CmifOutHeader>()),
|
|||
|
Objects = objects,
|
|||
|
CopyHandles = responseMessage.Data.CopyHandles,
|
|||
|
MoveHandles = responseMessage.Data.MoveHandles
|
|||
|
};
|
|||
|
|
|||
|
return Result.Success;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|