diff options
author | gdkchan <gab.dark.100@gmail.com> | 2023-01-04 19:15:45 -0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-01-04 23:15:45 +0100 |
commit | 08831eecf77cedd3c4192ebab5a9c485fb15d51e (patch) | |
tree | 6d95b921a18e9cfa477579fcecb9d041e03d682e /Ryujinx.Horizon/Sdk/Sf/Cmif/ServiceDispatchTableBase.cs | |
parent | c6a139a6e7e3ffe1591bc14dafafed60b9bef0dc (diff) |
IPC refactor part 3+4: New server HIPC message processor (#4188)1.1.506
* 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
Diffstat (limited to 'Ryujinx.Horizon/Sdk/Sf/Cmif/ServiceDispatchTableBase.cs')
-rw-r--r-- | Ryujinx.Horizon/Sdk/Sf/Cmif/ServiceDispatchTableBase.cs | 90 |
1 files changed, 90 insertions, 0 deletions
diff --git a/Ryujinx.Horizon/Sdk/Sf/Cmif/ServiceDispatchTableBase.cs b/Ryujinx.Horizon/Sdk/Sf/Cmif/ServiceDispatchTableBase.cs new file mode 100644 index 00000000..a0e28ca8 --- /dev/null +++ b/Ryujinx.Horizon/Sdk/Sf/Cmif/ServiceDispatchTableBase.cs @@ -0,0 +1,90 @@ +using Ryujinx.Common.Logging; +using Ryujinx.Horizon.Common; +using Ryujinx.Horizon.Sdk.Sf.Hipc; +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Sf.Cmif +{ + abstract class ServiceDispatchTableBase + { + private const uint MaxCmifVersion = 1; + + public abstract Result ProcessMessage(ref ServiceDispatchContext context, ReadOnlySpan<byte> inRawData); + + protected Result ProcessMessageImpl(ref ServiceDispatchContext context, ReadOnlySpan<byte> inRawData, IReadOnlyDictionary<int, CommandHandler> entries, string objectName) + { + if (inRawData.Length < Unsafe.SizeOf<CmifInHeader>()) + { + Logger.Warning?.Print(LogClass.KernelIpc, $"Request message size 0x{inRawData.Length:X} is invalid"); + + return SfResult.InvalidHeaderSize; + } + + CmifInHeader inHeader = MemoryMarshal.Cast<byte, CmifInHeader>(inRawData)[0]; + + if (inHeader.Magic != CmifMessage.CmifInHeaderMagic || inHeader.Version > MaxCmifVersion) + { + Logger.Warning?.Print(LogClass.KernelIpc, $"Request message header magic value 0x{inHeader.Magic:X} is invalid"); + + return SfResult.InvalidInHeader; + } + + ReadOnlySpan<byte> inMessageRawData = inRawData[Unsafe.SizeOf<CmifInHeader>()..]; + uint commandId = inHeader.CommandId; + + var outHeader = Span<CmifOutHeader>.Empty; + + 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); + CommandHandler.GetCmifOutHeaderPointer(ref outHeader, ref outRawData); + outHeader[0] = new CmifOutHeader() { Magic = CmifMessage.CmifOutHeaderMagic, Result = Result.Success }; + + return Result.Success; + } + + return SfResult.UnknownCommandId; + } + + Logger.Trace?.Print(LogClass.KernelIpc, $"{objectName}.{commandHandler.MethodName} called"); + + Result commandResult = commandHandler.Invoke(ref outHeader, ref context, inMessageRawData); + + if (commandResult.Module == SfResult.ModuleId || + commandResult.Module == HipcResult.ModuleId) + { + Logger.Warning?.Print(LogClass.KernelIpc, $"{commandHandler.MethodName} returned error {commandResult}"); + } + + if (SfResult.RequestContextChanged(commandResult)) + { + return commandResult; + } + + if (outHeader.IsEmpty) + { + commandResult.AbortOnSuccess(); + return commandResult; + } + + outHeader[0] = new CmifOutHeader() { Magic = CmifMessage.CmifOutHeaderMagic, Result = commandResult }; + + return Result.Success; + } + + private static HipcMessageData 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; + } + } +} |