08831eecf7
* IPC refactor part 3 + 4: New server HIPC message processor with source generator based serialization * Make types match on calls to AlignUp/AlignDown * Formatting * Address some PR feedback * Move BitfieldExtensions to Ryujinx.Common.Utilities and consolidate implementations * Rename Reader/Writer to SpanReader/SpanWriter and move to Ryujinx.Common.Memory * Implement EventType * Address more PR feedback * Log request processing errors since they are not normal * Rename waitable to multiwait and add missing lock * PR feedback * Ac_K PR feedback
128 lines
5 KiB
C#
128 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;
|
|
}
|
|
}
|
|
}
|