aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Horizon/Sdk/Sf/Cmif/ServiceDispatchTableBase.cs
diff options
context:
space:
mode:
authorgdkchan <gab.dark.100@gmail.com>2023-01-04 19:15:45 -0300
committerGitHub <noreply@github.com>2023-01-04 23:15:45 +0100
commit08831eecf77cedd3c4192ebab5a9c485fb15d51e (patch)
tree6d95b921a18e9cfa477579fcecb9d041e03d682e /Ryujinx.Horizon/Sdk/Sf/Cmif/ServiceDispatchTableBase.cs
parentc6a139a6e7e3ffe1591bc14dafafed60b9bef0dc (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.cs90
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;
+ }
+ }
+}