Horizon: Impl Prepo, Fixes bugs, Clean things (#4220)

* Horizon: Impl Prepo, Fixes bugs, Clean things

* remove ToArray()

* resultCode > status

* Remove old services

* Addresses gdkchan's comments and more cleanup

* Addresses Gdkchan's feedback 2

* Reorganize services, make sure service are loaded before guest

Co-Authored-By: gdkchan <5624669+gdkchan@users.noreply.github.com>

* Create interfaces for lm and sm

Co-authored-by: gdkchan <5624669+gdkchan@users.noreply.github.com>
This commit is contained in:
Ac_K 2023-01-08 13:13:39 +01:00 committed by GitHub
parent 3ffceab1fb
commit 550747eac6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
83 changed files with 1106 additions and 880 deletions

View file

@ -3,10 +3,10 @@
struct CmifDomainInHeader
{
public CmifDomainRequestType Type;
public byte ObjectsCount;
public ushort DataSize;
public int ObjectId;
public uint Padding;
public uint Token;
public byte ObjectsCount;
public ushort DataSize;
public int ObjectId;
public uint Padding;
public uint Token;
}
}

View file

@ -2,8 +2,8 @@
{
enum CmifDomainRequestType : byte
{
Invalid = 0,
Invalid = 0,
SendMessage = 1,
Close = 2
Close = 2
}
}

View file

@ -8,7 +8,7 @@ namespace Ryujinx.Horizon.Sdk.Sf.Cmif
{
static class CmifMessage
{
public const uint CmifInHeaderMagic = 0x49434653; // SFCI
public const uint CmifInHeaderMagic = 0x49434653; // SFCI
public const uint CmifOutHeaderMagic = 0x4f434653; // SFCO
public static CmifRequest CreateRequest(Span<byte> output, CmifRequestFormat format)
@ -21,27 +21,31 @@ namespace Ryujinx.Horizon.Sdk.Sf.Cmif
}
totalSize += Unsafe.SizeOf<CmifInHeader>() + format.DataSize;
totalSize = (totalSize + 1) & ~1;
totalSize = (totalSize + 1) & ~1;
int outPointerSizeTableOffset = totalSize;
int outPointerSizeTableSize = format.OutAutoBuffersCount + format.OutPointersCount;
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()
CmifRequest request = new()
{
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
});
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;
@ -53,35 +57,36 @@ namespace Ryujinx.Horizon.Sdk.Sf.Cmif
domainHeader = new CmifDomainInHeader()
{
Type = CmifDomainRequestType.SendMessage,
Type = CmifDomainRequestType.SendMessage,
ObjectsCount = (byte)format.ObjectsCount,
DataSize = (ushort)payloadSize,
ObjectId = format.ObjectId,
Padding = 0,
Token = format.Context
DataSize = (ushort)payloadSize,
ObjectId = format.ObjectId,
Padding = 0,
Token = format.Context
};
data = data.Slice(Unsafe.SizeOf<CmifDomainInHeader>() / sizeof(uint));
data = data[(Unsafe.SizeOf<CmifDomainInHeader>() / sizeof(uint))..];
request.Objects = data.Slice((payloadSize + sizeof(uint) - 1) / sizeof(uint));
request.Objects = data[((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,
Magic = CmifInHeaderMagic,
Version = format.Context != 0 ? 1u : 0u,
CommandId = format.RequestId,
Token = format.ObjectId != 0 ? 0u : format.Context
Token = format.ObjectId != 0 ? 0u : format.Context
};
request.Data = MemoryMarshal.Cast<uint, byte>(data).Slice(Unsafe.SizeOf<CmifInHeader>());
request.Data = MemoryMarshal.Cast<uint, byte>(data)[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);
Span<byte> outPointerTable = MemoryMarshal.Cast<uint, byte>(request.Hipc.DataWords)[(outPointerSizeTableOffset - paddingSizeBefore)..];
request.OutPointerSizes = MemoryMarshal.Cast<byte, ushort>(outPointerTable);
request.ServerPointerSize = format.ServerPointerSize;
return request;
@ -89,15 +94,15 @@ namespace Ryujinx.Horizon.Sdk.Sf.Cmif
public static Result ParseResponse(out CmifResponse response, Span<byte> input, bool isDomain, int size)
{
HipcMessage responseMessage = new HipcMessage(input);
HipcMessage responseMessage = new(input);
Span<byte> data = MemoryMarshal.Cast<uint, byte>(responseMessage.Data.DataWords);
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));
data = data[Unsafe.SizeOf<CmifDomainOutHeader>()..];
objects = MemoryMarshal.Cast<byte, uint>(data[(Unsafe.SizeOf<CmifOutHeader>() + size)..]);
}
CmifOutHeader header = MemoryMarshal.Cast<byte, CmifOutHeader>(data)[0];
@ -105,19 +110,21 @@ namespace Ryujinx.Horizon.Sdk.Sf.Cmif
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,
Data = data[Unsafe.SizeOf<CmifOutHeader>()..],
Objects = objects,
CopyHandles = responseMessage.Data.CopyHandles,
MoveHandles = responseMessage.Data.MoveHandles
};
@ -125,4 +132,4 @@ namespace Ryujinx.Horizon.Sdk.Sf.Cmif
return Result.Success;
}
}
}
}

View file

@ -5,10 +5,10 @@ namespace Ryujinx.Horizon.Sdk.Sf.Cmif
struct CmifOutHeader
{
#pragma warning disable CS0649
public uint Magic;
public uint Version;
public uint Magic;
public uint Version;
public Result Result;
public uint Token;
public uint Token;
#pragma warning restore CS0649
}
}

View file

@ -6,9 +6,9 @@ namespace Ryujinx.Horizon.Sdk.Sf.Cmif
ref struct CmifRequest
{
public HipcMessageData Hipc;
public Span<byte> Data;
public Span<ushort> OutPointerSizes;
public Span<uint> Objects;
public int ServerPointerSize;
public Span<byte> Data;
public Span<ushort> OutPointerSizes;
public Span<uint> Objects;
public int ServerPointerSize;
}
}

View file

@ -3,21 +3,21 @@
struct CmifRequestFormat
{
#pragma warning disable CS0649
public int ObjectId;
public int ObjectId;
public uint RequestId;
public uint Context;
public int DataSize;
public int ServerPointerSize;
public int InAutoBuffersCount;
public int OutAutoBuffersCount;
public int InBuffersCount;
public int OutBuffersCount;
public int InOutBuffersCount;
public int InPointersCount;
public int OutPointersCount;
public int OutFixedPointersCount;
public int ObjectsCount;
public int HandlesCount;
public int DataSize;
public int ServerPointerSize;
public int InAutoBuffersCount;
public int OutAutoBuffersCount;
public int InBuffersCount;
public int OutBuffersCount;
public int InOutBuffersCount;
public int InPointersCount;
public int OutPointersCount;
public int OutFixedPointersCount;
public int ObjectsCount;
public int HandlesCount;
public bool SendPid;
#pragma warning restore CS0649
}

View file

@ -6,7 +6,7 @@ namespace Ryujinx.Horizon.Sdk.Sf.Cmif
{
public ReadOnlySpan<byte> Data;
public ReadOnlySpan<uint> Objects;
public ReadOnlySpan<int> CopyHandles;
public ReadOnlySpan<int> MoveHandles;
public ReadOnlySpan<int> CopyHandles;
public ReadOnlySpan<int> MoveHandles;
}
}

View file

@ -2,12 +2,12 @@ namespace Ryujinx.Horizon.Sdk.Sf.Cmif
{
enum CommandType
{
Invalid = 0,
LegacyRequest = 1,
Close = 2,
LegacyControl = 3,
Request = 4,
Control = 5,
Invalid = 0,
LegacyRequest = 1,
Close = 2,
LegacyControl = 3,
Request = 4,
Control = 5,
RequestWithContext = 6,
ControlWithContext = 7
}

View file

@ -21,7 +21,7 @@ namespace Ryujinx.Horizon.Sdk.Sf.Cmif
var inHeader = MemoryMarshal.Cast<byte, CmifDomainInHeader>(inRawData)[0];
ReadOnlySpan<byte> inDomainRawData = inRawData.Slice(Unsafe.SizeOf<CmifDomainInHeader>());
ReadOnlySpan<byte> inDomainRawData = inRawData[Unsafe.SizeOf<CmifDomainInHeader>()..];
int targetObjectId = inHeader.ObjectId;
@ -39,7 +39,7 @@ namespace Ryujinx.Horizon.Sdk.Sf.Cmif
return SfResult.InvalidHeaderSize;
}
ReadOnlySpan<byte> inMessageRawData = inDomainRawData.Slice(0, inHeader.DataSize);
ReadOnlySpan<byte> inMessageRawData = inDomainRawData[..inHeader.DataSize];
if (inHeader.ObjectsCount > DomainServiceObjectProcessor.MaximumObjects)
{

View file

@ -63,7 +63,7 @@ namespace Ryujinx.Horizon.Sdk.Sf.Cmif
return SfResult.InvalidInObjectsCount;
}
Result result = _domain.ReserveIds(new Span<int>(_reservedObjectIds).Slice(0, OutObjectsCount));
Result result = _domain.ReserveIds(new Span<int>(_reservedObjectIds)[..OutObjectsCount]);
if (result.IsFailure)
{
@ -92,7 +92,7 @@ namespace Ryujinx.Horizon.Sdk.Sf.Cmif
DebugUtil.Assert(outHeaderSize + implOutDataTotalSize + OutObjectsCount * sizeof(int) <= outRawData.Length);
outRawData = outRawData.Slice(outHeaderSize);
outRawData = outRawData[outHeaderSize..];
_outObjectIdsOffset = (response.DataWords.Length * sizeof(uint) - outRawData.Length) + implOutDataTotalSize;
return response;
@ -107,9 +107,9 @@ namespace Ryujinx.Horizon.Sdk.Sf.Cmif
DebugUtil.Assert(outHeaderSize + implOutDataTotalSize <= outRawData.Length);
outRawData = outRawData.Slice(outHeaderSize);
outRawData = outRawData[outHeaderSize..];
_domain.UnreserveIds(new Span<int>(_reservedObjectIds).Slice(0, OutObjectsCount));
_domain.UnreserveIds(new Span<int>(_reservedObjectIds)[..OutObjectsCount]);
}
public override void SetOutObjects(scoped ref ServiceDispatchContext context, HipcMessageData response, Span<ServiceObjectHolder> outObjects)
@ -129,7 +129,7 @@ namespace Ryujinx.Horizon.Sdk.Sf.Cmif
_domain.RegisterObject(objectIds[i], outObjects[i]);
}
Span<int> outObjectIds = MemoryMarshal.Cast<byte, int>(MemoryMarshal.Cast<uint, byte>(response.DataWords).Slice(_outObjectIdsOffset));
Span<int> outObjectIds = MemoryMarshal.Cast<byte, int>(MemoryMarshal.Cast<uint, byte>(response.DataWords)[_outObjectIdsOffset..]);
for (int i = 0; i < outObjectsCount; i++)
{

View file

@ -2,7 +2,7 @@ namespace Ryujinx.Horizon.Sdk.Sf.Cmif
{
struct PointerAndSize
{
public static PointerAndSize Empty => new PointerAndSize(0UL, 0UL);
public static PointerAndSize Empty => new(0UL, 0UL);
public ulong Address { get; }
public ulong Size { get; }
@ -11,7 +11,7 @@ namespace Ryujinx.Horizon.Sdk.Sf.Cmif
public PointerAndSize(ulong address, ulong size)
{
Address = address;
Size = size;
Size = size;
}
}
}

View file

@ -2,28 +2,29 @@
{
struct ServerMessageRuntimeMetadata
{
public ushort InDataSize { get; }
public ushort OutDataSize { get; }
public byte InHeadersSize { get; }
public byte OutHeadersSize { get; }
public byte InObjectsCount { get; }
public byte OutObjectsCount { get; }
public ushort InDataSize { get; }
public ushort OutDataSize { get; }
public byte InHeadersSize { get; }
public byte OutHeadersSize { get; }
public byte InObjectsCount { get; }
public byte OutObjectsCount { get; }
public int UnfixedOutPointerSizeOffset => InDataSize + InHeadersSize + 0x10;
public ServerMessageRuntimeMetadata(
ushort inDataSize,
ushort outDataSize,
byte inHeadersSize,
byte outHeadersSize,
byte inObjectsCount,
byte outObjectsCount)
byte inHeadersSize,
byte outHeadersSize,
byte inObjectsCount,
byte outObjectsCount)
{
InDataSize = inDataSize;
OutDataSize = outDataSize;
InHeadersSize = inHeadersSize;
OutHeadersSize = outHeadersSize;
InObjectsCount = inObjectsCount;
InDataSize = inDataSize;
OutDataSize = outDataSize;
InHeadersSize = inHeadersSize;
OutHeadersSize = outHeadersSize;
InObjectsCount = inObjectsCount;
OutObjectsCount = outObjectsCount;
}
}
}
}

View file

@ -5,14 +5,14 @@ namespace Ryujinx.Horizon.Sdk.Sf.Cmif
{
ref struct ServiceDispatchContext
{
public IServiceObject ServiceObject;
public ServerSessionManager Manager;
public ServerSession Session;
public IServiceObject ServiceObject;
public ServerSessionManager Manager;
public ServerSession Session;
public ServerMessageProcessor Processor;
public HandlesToClose HandlesToClose;
public PointerAndSize PointerBuffer;
public ReadOnlySpan<byte> InMessageBuffer;
public Span<byte> OutMessageBuffer;
public HipcMessage Request;
public HandlesToClose HandlesToClose;
public PointerAndSize PointerBuffer;
public ReadOnlySpan<byte> InMessageBuffer;
public Span<byte> OutMessageBuffer;
public HipcMessage Request;
}
}
}

View file

@ -12,7 +12,7 @@ namespace Ryujinx.Horizon.Sdk.Sf.Cmif
public ServiceDispatchTable(string objectName, IReadOnlyDictionary<int, CommandHandler> entries)
{
_objectName = objectName;
_entries = entries;
_entries = entries;
}
public override Result ProcessMessage(ref ServiceDispatchContext context, ReadOnlySpan<byte> inRawData)
@ -30,4 +30,4 @@ namespace Ryujinx.Horizon.Sdk.Sf.Cmif
return new ServiceDispatchTable(instance.GetType().Name, instance.GetCommandHandlers());
}
}
}
}

View file

@ -39,17 +39,21 @@ namespace Ryujinx.Horizon.Sdk.Sf.Cmif
if (!entries.TryGetValue((int)commandId, out var commandHandler))
{
Logger.Warning?.Print(LogClass.KernelIpc, $"{objectName} command ID 0x{commandId:X} is not implemented");
if (HorizonStatic.Options.IgnoreMissingServices)
{
// If ignore missing services is enabled, just pretend that everything is fine.
var response = PrepareForStubReply(ref context, out Span<byte> outRawData);
PrepareForStubReply(ref context, out Span<byte> outRawData);
CommandHandler.GetCmifOutHeaderPointer(ref outHeader, ref outRawData);
outHeader[0] = new CmifOutHeader() { Magic = CmifMessage.CmifOutHeaderMagic, Result = Result.Success };
Logger.Warning?.Print(LogClass.Service, $"Missing service {objectName} (command ID: {commandId}) ignored");
return Result.Success;
}
else if (HorizonStatic.Options.ThrowOnInvalidCommandIds)
{
throw new NotImplementedException($"{objectName} command ID: {commandId} is not implemented");
}
return SfResult.UnknownCommandId;
}
@ -72,6 +76,7 @@ namespace Ryujinx.Horizon.Sdk.Sf.Cmif
if (outHeader.IsEmpty)
{
commandResult.AbortOnSuccess();
return commandResult;
}
@ -80,11 +85,10 @@ namespace Ryujinx.Horizon.Sdk.Sf.Cmif
return Result.Success;
}
private static HipcMessageData PrepareForStubReply(scoped ref ServiceDispatchContext context, out Span<byte> outRawData)
private static void PrepareForStubReply(scoped ref ServiceDispatchContext context, out Span<byte> outRawData)
{
var response = HipcMessage.WriteResponse(context.OutMessageBuffer, 0, 0x20 / sizeof(uint), 0, 0);
outRawData = MemoryMarshal.Cast<uint, byte>(response.DataWords);
return response;
}
}
}
}