aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Ryujinx.Common/Memory/SpanReader.cs51
-rw-r--r--Ryujinx.Common/Memory/SpanWriter.cs45
-rw-r--r--Ryujinx.Common/Utilities/BitfieldExtensions.cs57
-rw-r--r--Ryujinx.Graphics.Shader/Decoders/BitfieldExtensions.cs15
-rw-r--r--Ryujinx.Graphics.Shader/Translation/Optimizations/ConstantFolding.cs2
-rw-r--r--Ryujinx.Graphics.Shader/Translation/ShaderHeader.cs2
-rw-r--r--Ryujinx.Graphics.Vic/Types/BitfieldExtensions.cs39
-rw-r--r--Ryujinx.Graphics.Vic/Types/BlendingSlotStruct.cs24
-rw-r--r--Ryujinx.Graphics.Vic/Types/ClearRectStruct.cs20
-rw-r--r--Ryujinx.Graphics.Vic/Types/LumaKeyStruct.cs18
-rw-r--r--Ryujinx.Graphics.Vic/Types/MatrixStruct.cs30
-rw-r--r--Ryujinx.Graphics.Vic/Types/OutputConfig.cs26
-rw-r--r--Ryujinx.Graphics.Vic/Types/OutputSurfaceConfig.cs24
-rw-r--r--Ryujinx.Graphics.Vic/Types/PipeConfig.cs8
-rw-r--r--Ryujinx.Graphics.Vic/Types/SlotConfig.cs58
-rw-r--r--Ryujinx.Graphics.Vic/Types/SlotSurfaceConfig.cs26
-rw-r--r--Ryujinx.HLE/HOS/Horizon.cs37
-rw-r--r--Ryujinx.HLE/HOS/Kernel/Common/KAutoObject.cs9
-rw-r--r--Ryujinx.HLE/HOS/Kernel/Common/KResourceLimit.cs5
-rw-r--r--Ryujinx.HLE/HOS/Kernel/Common/KernelInit.cs5
-rw-r--r--Ryujinx.HLE/HOS/Kernel/Common/KernelResult.cs37
-rw-r--r--Ryujinx.HLE/HOS/Kernel/Common/OnScopeExit.cs11
-rw-r--r--Ryujinx.HLE/HOS/Kernel/Ipc/KBufferDescriptorTable.cs62
-rw-r--r--Ryujinx.HLE/HOS/Kernel/Ipc/KClientPort.cs15
-rw-r--r--Ryujinx.HLE/HOS/Kernel/Ipc/KClientSession.cs13
-rw-r--r--Ryujinx.HLE/HOS/Kernel/Ipc/KPort.cs21
-rw-r--r--Ryujinx.HLE/HOS/Kernel/Ipc/KServerSession.cs77
-rw-r--r--Ryujinx.HLE/HOS/Kernel/KernelStatic.cs7
-rw-r--r--Ryujinx.HLE/HOS/Kernel/Memory/KCodeMemory.cs43
-rw-r--r--Ryujinx.HLE/HOS/Kernel/Memory/KMemoryBlockManager.cs6
-rw-r--r--Ryujinx.HLE/HOS/Kernel/Memory/KMemoryRegionManager.cs18
-rw-r--r--Ryujinx.HLE/HOS/Kernel/Memory/KPageList.cs6
-rw-r--r--Ryujinx.HLE/HOS/Kernel/Memory/KPageTable.cs46
-rw-r--r--Ryujinx.HLE/HOS/Kernel/Memory/KPageTableBase.cs261
-rw-r--r--Ryujinx.HLE/HOS/Kernel/Memory/KSharedMemory.cs5
-rw-r--r--Ryujinx.HLE/HOS/Kernel/Memory/KTransferMemory.cs21
-rw-r--r--Ryujinx.HLE/HOS/Kernel/Process/KHandleTable.cs13
-rw-r--r--Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs93
-rw-r--r--Ryujinx.HLE/HOS/Kernel/Process/KProcessCapabilities.cs23
-rw-r--r--Ryujinx.HLE/HOS/Kernel/Process/ProcessExecutionContext.cs18
-rw-r--r--Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs392
-rw-r--r--Ryujinx.HLE/HOS/Kernel/Threading/KAddressArbiter.cs37
-rw-r--r--Ryujinx.HLE/HOS/Kernel/Threading/KReadableEvent.cs11
-rw-r--r--Ryujinx.HLE/HOS/Kernel/Threading/KSynchronization.cs9
-rw-r--r--Ryujinx.HLE/HOS/Kernel/Threading/KThread.cs45
-rw-r--r--Ryujinx.HLE/HOS/Kernel/Threading/KThreadContext.cs18
-rw-r--r--Ryujinx.HLE/HOS/Kernel/Threading/KWritableEvent.cs3
-rw-r--r--Ryujinx.HLE/HOS/ProgramLoader.cs69
-rw-r--r--Ryujinx.HLE/HOS/Services/Account/Acc/IAsyncContext.cs4
-rw-r--r--Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/LibraryAppletCreator/ILibraryAppletAccessor.cs8
-rw-r--r--Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/ICommonStateGetter.cs6
-rw-r--r--Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/IDisplayController.cs6
-rw-r--r--Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/IHomeMenuFunctions.cs4
-rw-r--r--Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/ISelfController.cs6
-rw-r--r--Ryujinx.HLE/HOS/Services/Am/AppletOE/ApplicationProxyService/ApplicationProxy/IApplicationFunctions.cs21
-rw-r--r--Ryujinx.HLE/HOS/Services/Audio/AudioIn/AudioInServer.cs4
-rw-r--r--Ryujinx.HLE/HOS/Services/Audio/AudioOut/AudioOutServer.cs4
-rw-r--r--Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/AudioDeviceServer.cs8
-rw-r--r--Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/AudioRendererServer.cs4
-rw-r--r--Ryujinx.HLE/HOS/Services/Bcat/ServiceCreator/IDeliveryCacheProgressService.cs4
-rw-r--r--Ryujinx.HLE/HOS/Services/Bluetooth/IBluetoothDriver.cs14
-rw-r--r--Ryujinx.HLE/HOS/Services/BluetoothManager/BtmUser/IBtmUserCore.cs26
-rw-r--r--Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/IFriendService.cs5
-rw-r--r--Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/INotificationService.cs4
-rw-r--r--Ryujinx.HLE/HOS/Services/Hid/HidServer/IAppletResource.cs4
-rw-r--r--Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs10
-rw-r--r--Ryujinx.HLE/HOS/Services/Hid/Irs/IIrSensorServer.cs10
-rw-r--r--Ryujinx.HLE/HOS/Services/Ldn/UserServiceCreator/IUserLocalCommunicationService.cs4
-rw-r--r--Ryujinx.HLE/HOS/Services/Nfc/Nfp/NfpManager/INfp.cs8
-rw-r--r--Ryujinx.HLE/HOS/Services/Nifm/StaticService/IRequest.cs6
-rw-r--r--Ryujinx.HLE/HOS/Services/Nim/IShopServiceAccessor.cs4
-rw-r--r--Ryujinx.HLE/HOS/Services/Nim/Ntc/StaticService/IEnsureNetworkClockAvailabilityService.cs6
-rw-r--r--Ryujinx.HLE/HOS/Services/Ns/Aoc/IAddOnContentManager.cs6
-rw-r--r--Ryujinx.HLE/HOS/Services/Ns/Aoc/IPurchaseEventManager.cs4
-rw-r--r--Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/NvHostGpuDeviceFile.cs6
-rw-r--r--Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrl/Types/NvHostEvent.cs4
-rw-r--r--Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrlGpu/NvHostCtrlGpuDeviceFile.cs4
-rw-r--r--Ryujinx.HLE/HOS/Services/Pcv/Clkrst/IClkrstManager.cs4
-rw-r--r--Ryujinx.HLE/HOS/Services/Pm/IDebugMonitorInterface.cs4
-rw-r--r--Ryujinx.HLE/HOS/Services/Ptm/Psm/IPsmSession.cs8
-rw-r--r--Ryujinx.HLE/HOS/Services/Ro/IRoInterface.cs38
-rw-r--r--Ryujinx.HLE/HOS/Services/Sdb/Pl/ISharedFontManager.cs6
-rw-r--r--Ryujinx.HLE/HOS/Services/ServerBase.cs8
-rw-r--r--Ryujinx.HLE/HOS/Services/Sm/IUserInterface.cs14
-rw-r--r--Ryujinx.HLE/HOS/Services/SurfaceFlinger/IHOSBinderDriver.cs4
-rw-r--r--Ryujinx.HLE/HOS/Services/Time/IStaticServiceForPsc.cs4
-rw-r--r--Ryujinx.HLE/HOS/Services/Time/ITimeServiceManager.cs4
-rw-r--r--Ryujinx.HLE/HOS/Services/Time/StaticService/ISystemClock.cs4
-rw-r--r--Ryujinx.HLE/HOS/Services/Vi/RootService/IApplicationDisplayService.cs3
-rw-r--r--Ryujinx.HLE/Ryujinx.HLE.csproj4
-rw-r--r--Ryujinx.HLE/Switch.cs4
-rw-r--r--Ryujinx.Horizon.Common/ISyscallApi.cs33
-rw-r--r--Ryujinx.Horizon.Common/IThreadContext.cs11
-rw-r--r--Ryujinx.Horizon.Common/InvalidResultException.cs23
-rw-r--r--Ryujinx.Horizon.Common/KernelResult.cs39
-rw-r--r--Ryujinx.Horizon.Common/OnScopeExit.cs19
-rw-r--r--Ryujinx.Horizon.Common/Result.cs118
-rw-r--r--Ryujinx.Horizon.Common/ResultNames.cs1701
-rw-r--r--Ryujinx.Horizon.Common/Ryujinx.Horizon.Common.csproj11
-rw-r--r--Ryujinx.Horizon.Common/ThreadTerminatedException.cs19
-rw-r--r--Ryujinx.Horizon.Generators/CodeGenerator.cs4
-rw-r--r--Ryujinx.Horizon.Generators/Hipc/CommandArgType.cs18
-rw-r--r--Ryujinx.Horizon.Generators/Hipc/CommandInterface.cs17
-rw-r--r--Ryujinx.Horizon.Generators/Hipc/HipcGenerator.cs749
-rw-r--r--Ryujinx.Horizon.Generators/Hipc/HipcSyntaxReceiver.cs58
-rw-r--r--Ryujinx.Horizon.Kernel.Generators/CodeGenerator.cs58
-rw-r--r--Ryujinx.Horizon.Kernel.Generators/Kernel/SyscallGenerator.cs (renamed from Ryujinx.Horizon.Generators/Kernel/SyscallGenerator.cs)36
-rw-r--r--Ryujinx.Horizon.Kernel.Generators/Kernel/SyscallSyntaxReceiver.cs (renamed from Ryujinx.Horizon.Generators/Kernel/SyscallSyntaxReceiver.cs)0
-rw-r--r--Ryujinx.Horizon.Kernel.Generators/Ryujinx.Horizon.Kernel.Generators.csproj15
-rw-r--r--Ryujinx.Horizon/HeapAllocator.cs143
-rw-r--r--Ryujinx.Horizon/HorizonOptions.cs12
-rw-r--r--Ryujinx.Horizon/HorizonStatic.cs44
-rw-r--r--Ryujinx.Horizon/IService.cs7
-rw-r--r--Ryujinx.Horizon/LogManager/LmIpcServer.cs54
-rw-r--r--Ryujinx.Horizon/LogManager/LmLog.cs19
-rw-r--r--Ryujinx.Horizon/LogManager/LmLogger.cs139
-rw-r--r--Ryujinx.Horizon/LogManager/LmMain.cs14
-rw-r--r--Ryujinx.Horizon/Ryujinx.Horizon.csproj14
-rw-r--r--Ryujinx.Horizon/Sdk/DebugUtil.cs12
-rw-r--r--Ryujinx.Horizon/Sdk/Diag/LogSeverity.cs11
-rw-r--r--Ryujinx.Horizon/Sdk/Lm/LogDataChunkKey.cs19
-rw-r--r--Ryujinx.Horizon/Sdk/Lm/LogDestination.cs14
-rw-r--r--Ryujinx.Horizon/Sdk/Lm/LogPacketFlags.cs12
-rw-r--r--Ryujinx.Horizon/Sdk/Lm/LogPacketHeader.cs15
-rw-r--r--Ryujinx.Horizon/Sdk/OsTypes/Event.cs61
-rw-r--r--Ryujinx.Horizon/Sdk/OsTypes/EventClearMode.cs8
-rw-r--r--Ryujinx.Horizon/Sdk/OsTypes/EventType.cs15
-rw-r--r--Ryujinx.Horizon/Sdk/OsTypes/Impl/InterProcessEvent.cs89
-rw-r--r--Ryujinx.Horizon/Sdk/OsTypes/Impl/InterProcessEventImpl.cs136
-rw-r--r--Ryujinx.Horizon/Sdk/OsTypes/Impl/MultiWaitImpl.cs250
-rw-r--r--Ryujinx.Horizon/Sdk/OsTypes/InitializationState.cs8
-rw-r--r--Ryujinx.Horizon/Sdk/OsTypes/InterProcessEventType.cs27
-rw-r--r--Ryujinx.Horizon/Sdk/OsTypes/MultiWait.cs43
-rw-r--r--Ryujinx.Horizon/Sdk/OsTypes/MultiWaitHolder.cs16
-rw-r--r--Ryujinx.Horizon/Sdk/OsTypes/MultiWaitHolderBase.cs39
-rw-r--r--Ryujinx.Horizon/Sdk/OsTypes/MultiWaitHolderOfEvent.cs45
-rw-r--r--Ryujinx.Horizon/Sdk/OsTypes/MultiWaitHolderOfHandle.cs14
-rw-r--r--Ryujinx.Horizon/Sdk/OsTypes/OsEvent.cs130
-rw-r--r--Ryujinx.Horizon/Sdk/OsTypes/OsMultiWait.cs10
-rw-r--r--Ryujinx.Horizon/Sdk/OsTypes/OsProcessHandle.cs33
-rw-r--r--Ryujinx.Horizon/Sdk/OsTypes/OsResult.cs11
-rw-r--r--Ryujinx.Horizon/Sdk/OsTypes/OsSystemEvent.cs85
-rw-r--r--Ryujinx.Horizon/Sdk/OsTypes/OsThreadManager.cs10
-rw-r--r--Ryujinx.Horizon/Sdk/OsTypes/SystemEventType.cs17
-rw-r--r--Ryujinx.Horizon/Sdk/OsTypes/TriBool.cs9
-rw-r--r--Ryujinx.Horizon/Sdk/ServiceUtil.cs38
-rw-r--r--Ryujinx.Horizon/Sdk/Sf/Cmif/CmifDomainInHeader.cs12
-rw-r--r--Ryujinx.Horizon/Sdk/Sf/Cmif/CmifDomainOutHeader.cs12
-rw-r--r--Ryujinx.Horizon/Sdk/Sf/Cmif/CmifDomainRequestType.cs9
-rw-r--r--Ryujinx.Horizon/Sdk/Sf/Cmif/CmifInHeader.cs10
-rw-r--r--Ryujinx.Horizon/Sdk/Sf/Cmif/CmifMessage.cs128
-rw-r--r--Ryujinx.Horizon/Sdk/Sf/Cmif/CmifOutHeader.cs14
-rw-r--r--Ryujinx.Horizon/Sdk/Sf/Cmif/CmifRequest.cs14
-rw-r--r--Ryujinx.Horizon/Sdk/Sf/Cmif/CmifRequestFormat.cs24
-rw-r--r--Ryujinx.Horizon/Sdk/Sf/Cmif/CmifResponse.cs12
-rw-r--r--Ryujinx.Horizon/Sdk/Sf/Cmif/CommandType.cs14
-rw-r--r--Ryujinx.Horizon/Sdk/Sf/Cmif/DomainServiceObject.cs7
-rw-r--r--Ryujinx.Horizon/Sdk/Sf/Cmif/DomainServiceObjectDispatchTable.cs75
-rw-r--r--Ryujinx.Horizon/Sdk/Sf/Cmif/DomainServiceObjectProcessor.cs140
-rw-r--r--Ryujinx.Horizon/Sdk/Sf/Cmif/HandlesToClose.cs52
-rw-r--r--Ryujinx.Horizon/Sdk/Sf/Cmif/InlineContext.cs11
-rw-r--r--Ryujinx.Horizon/Sdk/Sf/Cmif/PointerAndSize.cs17
-rw-r--r--Ryujinx.Horizon/Sdk/Sf/Cmif/ScopedInlineContextChange.cs19
-rw-r--r--Ryujinx.Horizon/Sdk/Sf/Cmif/ServerDomainBase.cs15
-rw-r--r--Ryujinx.Horizon/Sdk/Sf/Cmif/ServerDomainManager.cs246
-rw-r--r--Ryujinx.Horizon/Sdk/Sf/Cmif/ServerMessageProcessor.cs18
-rw-r--r--Ryujinx.Horizon/Sdk/Sf/Cmif/ServerMessageRuntimeMetadata.cs29
-rw-r--r--Ryujinx.Horizon/Sdk/Sf/Cmif/ServiceDispatchContext.cs18
-rw-r--r--Ryujinx.Horizon/Sdk/Sf/Cmif/ServiceDispatchMeta.cs12
-rw-r--r--Ryujinx.Horizon/Sdk/Sf/Cmif/ServiceDispatchTable.cs33
-rw-r--r--Ryujinx.Horizon/Sdk/Sf/Cmif/ServiceDispatchTableBase.cs90
-rw-r--r--Ryujinx.Horizon/Sdk/Sf/Cmif/ServiceObjectHolder.cs34
-rw-r--r--Ryujinx.Horizon/Sdk/Sf/CmifCommandAttribute.cs15
-rw-r--r--Ryujinx.Horizon/Sdk/Sf/CommandArg.cs56
-rw-r--r--Ryujinx.Horizon/Sdk/Sf/CommandArgAttributes.cs38
-rw-r--r--Ryujinx.Horizon/Sdk/Sf/CommandHandler.cs57
-rw-r--r--Ryujinx.Horizon/Sdk/Sf/CommandSerialization.cs68
-rw-r--r--Ryujinx.Horizon/Sdk/Sf/Hipc/Api.cs89
-rw-r--r--Ryujinx.Horizon/Sdk/Sf/Hipc/Header.cs65
-rw-r--r--Ryujinx.Horizon/Sdk/Sf/Hipc/HipcBufferDescriptor.cs15
-rw-r--r--Ryujinx.Horizon/Sdk/Sf/Hipc/HipcBufferFlags.cs17
-rw-r--r--Ryujinx.Horizon/Sdk/Sf/Hipc/HipcBufferMode.cs10
-rw-r--r--Ryujinx.Horizon/Sdk/Sf/Hipc/HipcManager.cs115
-rw-r--r--Ryujinx.Horizon/Sdk/Sf/Hipc/HipcMessage.cs222
-rw-r--r--Ryujinx.Horizon/Sdk/Sf/Hipc/HipcMessageData.cs16
-rw-r--r--Ryujinx.Horizon/Sdk/Sf/Hipc/HipcMetadata.cs16
-rw-r--r--Ryujinx.Horizon/Sdk/Sf/Hipc/HipcReceiveListEntry.cs14
-rw-r--r--Ryujinx.Horizon/Sdk/Sf/Hipc/HipcResult.cs22
-rw-r--r--Ryujinx.Horizon/Sdk/Sf/Hipc/HipcStaticDescriptor.cs22
-rw-r--r--Ryujinx.Horizon/Sdk/Sf/Hipc/ManagerOptions.cs20
-rw-r--r--Ryujinx.Horizon/Sdk/Sf/Hipc/ReceiveResult.cs9
-rw-r--r--Ryujinx.Horizon/Sdk/Sf/Hipc/Server.cs36
-rw-r--r--Ryujinx.Horizon/Sdk/Sf/Hipc/ServerDomainSessionManager.cs23
-rw-r--r--Ryujinx.Horizon/Sdk/Sf/Hipc/ServerManager.cs198
-rw-r--r--Ryujinx.Horizon/Sdk/Sf/Hipc/ServerManagerBase.cs307
-rw-r--r--Ryujinx.Horizon/Sdk/Sf/Hipc/ServerSession.cs23
-rw-r--r--Ryujinx.Horizon/Sdk/Sf/Hipc/ServerSessionManager.cs335
-rw-r--r--Ryujinx.Horizon/Sdk/Sf/Hipc/SpecialHeader.cs27
-rw-r--r--Ryujinx.Horizon/Sdk/Sf/HipcCommandProcessor.cs421
-rw-r--r--Ryujinx.Horizon/Sdk/Sf/IServiceObject.cs9
-rw-r--r--Ryujinx.Horizon/Sdk/Sf/RawDataOffsetCalculator.cs51
-rw-r--r--Ryujinx.Horizon/Sdk/Sf/SfResult.cs31
-rw-r--r--Ryujinx.Horizon/Sdk/Sm/ServiceName.cs98
-rw-r--r--Ryujinx.Horizon/Sdk/Sm/SmApi.cs107
-rw-r--r--Ryujinx.Horizon/ServiceEntry.cs25
-rw-r--r--Ryujinx.Horizon/ServiceTable.cs22
-rw-r--r--Ryujinx.Horizon/Sm/Impl/ServiceInfo.cs20
-rw-r--r--Ryujinx.Horizon/Sm/Impl/ServiceManager.cs197
-rw-r--r--Ryujinx.Horizon/Sm/ManagerService.cs8
-rw-r--r--Ryujinx.Horizon/Sm/SmMain.cs30
-rw-r--r--Ryujinx.Horizon/Sm/SmResult.cs19
-rw-r--r--Ryujinx.Horizon/Sm/UserService.cs66
-rw-r--r--Ryujinx.sln22
213 files changed, 9762 insertions, 1010 deletions
diff --git a/Ryujinx.Common/Memory/SpanReader.cs b/Ryujinx.Common/Memory/SpanReader.cs
new file mode 100644
index 00000000..e46649e1
--- /dev/null
+++ b/Ryujinx.Common/Memory/SpanReader.cs
@@ -0,0 +1,51 @@
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.Common.Memory
+{
+ public ref struct SpanReader
+ {
+ private ReadOnlySpan<byte> _input;
+
+ public int Length => _input.Length;
+
+ public SpanReader(ReadOnlySpan<byte> input)
+ {
+ _input = input;
+ }
+
+ public T Read<T>() where T : unmanaged
+ {
+ T value = MemoryMarshal.Cast<byte, T>(_input)[0];
+
+ _input = _input.Slice(Unsafe.SizeOf<T>());
+
+ return value;
+ }
+
+ public ReadOnlySpan<byte> GetSpan(int size)
+ {
+ ReadOnlySpan<byte> data = _input.Slice(0, size);
+
+ _input = _input.Slice(size);
+
+ return data;
+ }
+
+ public T ReadAt<T>(int offset) where T : unmanaged
+ {
+ return MemoryMarshal.Cast<byte, T>(_input.Slice(offset))[0];
+ }
+
+ public ReadOnlySpan<byte> GetSpanAt(int offset, int size)
+ {
+ return _input.Slice(offset, size);
+ }
+
+ public void Skip(int size)
+ {
+ _input = _input.Slice(size);
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Common/Memory/SpanWriter.cs b/Ryujinx.Common/Memory/SpanWriter.cs
new file mode 100644
index 00000000..5c35569d
--- /dev/null
+++ b/Ryujinx.Common/Memory/SpanWriter.cs
@@ -0,0 +1,45 @@
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.Common.Memory
+{
+ public ref struct SpanWriter
+ {
+ private Span<byte> _output;
+
+ public int Length => _output.Length;
+
+ public SpanWriter(Span<byte> output)
+ {
+ _output = output;
+ }
+
+ public void Write<T>(T value) where T : unmanaged
+ {
+ MemoryMarshal.Cast<byte, T>(_output)[0] = value;
+ _output = _output.Slice(Unsafe.SizeOf<T>());
+ }
+
+ public void Write(ReadOnlySpan<byte> data)
+ {
+ data.CopyTo(_output.Slice(0, data.Length));
+ _output = _output.Slice(data.Length);
+ }
+
+ public void WriteAt<T>(int offset, T value) where T : unmanaged
+ {
+ MemoryMarshal.Cast<byte, T>(_output.Slice(offset))[0] = value;
+ }
+
+ public void WriteAt(int offset, ReadOnlySpan<byte> data)
+ {
+ data.CopyTo(_output.Slice(offset, data.Length));
+ }
+
+ public void Skip(int size)
+ {
+ _output = _output.Slice(size);
+ }
+ }
+}
diff --git a/Ryujinx.Common/Utilities/BitfieldExtensions.cs b/Ryujinx.Common/Utilities/BitfieldExtensions.cs
new file mode 100644
index 00000000..ca429944
--- /dev/null
+++ b/Ryujinx.Common/Utilities/BitfieldExtensions.cs
@@ -0,0 +1,57 @@
+using System.Numerics;
+using System.Runtime.CompilerServices;
+
+namespace Ryujinx.Common.Utilities
+{
+ public static class BitfieldExtensions
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static bool Extract<T>(this T value, int lsb) where T : IBinaryInteger<T>
+ {
+ int bitSize = Unsafe.SizeOf<T>() * 8;
+ lsb &= bitSize - 1;
+
+ return !T.IsZero((value >>> lsb) & T.One);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static T Extract<T>(this T value, int lsb, int length) where T : IBinaryInteger<T>
+ {
+ int bitSize = Unsafe.SizeOf<T>() * 8;
+ lsb &= bitSize - 1;
+
+ return (value >>> lsb) & (~T.Zero >>> (bitSize - length));
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static T ExtractSx<T>(this T value, int lsb, int length) where T : IBinaryInteger<T>
+ {
+ int bitSize = Unsafe.SizeOf<T>() * 8;
+ int shift = lsb & (bitSize - 1);
+
+ return (value << (bitSize - (shift + length))) >> (bitSize - length);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static T Insert<T>(this T value, int lsb, bool toInsert) where T : IBinaryInteger<T>
+ {
+ int bitSize = Unsafe.SizeOf<T>() * 8;
+ lsb &= bitSize - 1;
+
+ T mask = T.One << lsb;
+
+ return (value & ~mask) | (toInsert ? mask : T.Zero);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static T Insert<T>(this T value, int lsb, int length, T toInsert) where T : IBinaryInteger<T>
+ {
+ int bitSize = Unsafe.SizeOf<T>() * 8;
+ lsb &= bitSize - 1;
+
+ T mask = (~T.Zero >>> (bitSize - length)) << lsb;
+
+ return (value & ~mask) | ((toInsert << lsb) & mask);
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Graphics.Shader/Decoders/BitfieldExtensions.cs b/Ryujinx.Graphics.Shader/Decoders/BitfieldExtensions.cs
deleted file mode 100644
index 79e0a5c0..00000000
--- a/Ryujinx.Graphics.Shader/Decoders/BitfieldExtensions.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-namespace Ryujinx.Graphics.Shader.Decoders
-{
- static class BitfieldExtensions
- {
- public static bool Extract(this int value, int lsb)
- {
- return ((value >> lsb) & 1) != 0;
- }
-
- public static int Extract(this int value, int lsb, int length)
- {
- return (value >> lsb) & (int)(uint.MaxValue >> (32 - length));
- }
- }
-} \ No newline at end of file
diff --git a/Ryujinx.Graphics.Shader/Translation/Optimizations/ConstantFolding.cs b/Ryujinx.Graphics.Shader/Translation/Optimizations/ConstantFolding.cs
index ab33da19..6729f077 100644
--- a/Ryujinx.Graphics.Shader/Translation/Optimizations/ConstantFolding.cs
+++ b/Ryujinx.Graphics.Shader/Translation/Optimizations/ConstantFolding.cs
@@ -1,4 +1,4 @@
-using Ryujinx.Graphics.Shader.Decoders;
+using Ryujinx.Common.Utilities;
using Ryujinx.Graphics.Shader.IntermediateRepresentation;
using System;
diff --git a/Ryujinx.Graphics.Shader/Translation/ShaderHeader.cs b/Ryujinx.Graphics.Shader/Translation/ShaderHeader.cs
index b643262f..01f7f08a 100644
--- a/Ryujinx.Graphics.Shader/Translation/ShaderHeader.cs
+++ b/Ryujinx.Graphics.Shader/Translation/ShaderHeader.cs
@@ -1,4 +1,4 @@
-using Ryujinx.Graphics.Shader.Decoders;
+using Ryujinx.Common.Utilities;
using System;
using System.Runtime.InteropServices;
diff --git a/Ryujinx.Graphics.Vic/Types/BitfieldExtensions.cs b/Ryujinx.Graphics.Vic/Types/BitfieldExtensions.cs
deleted file mode 100644
index 06d0f006..00000000
--- a/Ryujinx.Graphics.Vic/Types/BitfieldExtensions.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-using System.Runtime.CompilerServices;
-
-namespace Ryujinx.Graphics.Vic.Types
-{
- static class BitfieldExtensions
- {
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static bool Extract(this int value, int lsb)
- {
- return ((value >> (lsb & 0x1f)) & 1) != 0;
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static int Extract(this int value, int lsb, int length)
- {
- return (value >> (lsb & 0x1f)) & (int)(uint.MaxValue >> (32 - length));
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static bool Extract(this long value, int lsb)
- {
- return ((int)(value >> (lsb & 0x3f)) & 1) != 0;
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static int Extract(this long value, int lsb, int length)
- {
- return (int)(value >> (lsb & 0x3f)) & (int)(uint.MaxValue >> (32 - length));
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static int ExtractSx(this long value, int lsb, int length)
- {
- int shift = lsb & 0x3f;
-
- return (int)((value << (64 - (shift + length))) >> (64 - length));
- }
- }
-}
diff --git a/Ryujinx.Graphics.Vic/Types/BlendingSlotStruct.cs b/Ryujinx.Graphics.Vic/Types/BlendingSlotStruct.cs
index fc5d315e..86da41d2 100644
--- a/Ryujinx.Graphics.Vic/Types/BlendingSlotStruct.cs
+++ b/Ryujinx.Graphics.Vic/Types/BlendingSlotStruct.cs
@@ -1,20 +1,22 @@
-namespace Ryujinx.Graphics.Vic.Types
+using Ryujinx.Common.Utilities;
+
+namespace Ryujinx.Graphics.Vic.Types
{
struct BlendingSlotStruct
{
private long _word0;
private long _word1;
- public int AlphaK1 => _word0.Extract(0, 10);
- public int AlphaK2 => _word0.Extract(16, 10);
- public int SrcFactCMatchSelect => _word0.Extract(32, 3);
- public int DstFactCMatchSelect => _word0.Extract(36, 3);
- public int SrcFactAMatchSelect => _word0.Extract(40, 3);
- public int DstFactAMatchSelect => _word0.Extract(44, 3);
- public int OverrideR => _word1.Extract(66, 10);
- public int OverrideG => _word1.Extract(76, 10);
- public int OverrideB => _word1.Extract(86, 10);
- public int OverrideA => _word1.Extract(96, 10);
+ public int AlphaK1 => (int)_word0.Extract(0, 10);
+ public int AlphaK2 => (int)_word0.Extract(16, 10);
+ public int SrcFactCMatchSelect => (int)_word0.Extract(32, 3);
+ public int DstFactCMatchSelect => (int)_word0.Extract(36, 3);
+ public int SrcFactAMatchSelect => (int)_word0.Extract(40, 3);
+ public int DstFactAMatchSelect => (int)_word0.Extract(44, 3);
+ public int OverrideR => (int)_word1.Extract(66, 10);
+ public int OverrideG => (int)_word1.Extract(76, 10);
+ public int OverrideB => (int)_word1.Extract(86, 10);
+ public int OverrideA => (int)_word1.Extract(96, 10);
public bool UseOverrideR => _word1.Extract(108);
public bool UseOverrideG => _word1.Extract(109);
public bool UseOverrideB => _word1.Extract(110);
diff --git a/Ryujinx.Graphics.Vic/Types/ClearRectStruct.cs b/Ryujinx.Graphics.Vic/Types/ClearRectStruct.cs
index 2915404f..ae582a92 100644
--- a/Ryujinx.Graphics.Vic/Types/ClearRectStruct.cs
+++ b/Ryujinx.Graphics.Vic/Types/ClearRectStruct.cs
@@ -1,4 +1,6 @@
-namespace Ryujinx.Graphics.Vic.Types
+using Ryujinx.Common.Utilities;
+
+namespace Ryujinx.Graphics.Vic.Types
{
struct ClearRectStruct
{
@@ -7,13 +9,13 @@
private long _word1;
#pragma warning restore CS0649
- public int ClearRect0Left => _word0.Extract(0, 14);
- public int ClearRect0Right => _word0.Extract(16, 14);
- public int ClearRect0Top => _word0.Extract(32, 14);
- public int ClearRect0Bottom => _word0.Extract(48, 14);
- public int ClearRect1Left => _word1.Extract(64, 14);
- public int ClearRect1Right => _word1.Extract(80, 14);
- public int ClearRect1Top => _word1.Extract(96, 14);
- public int ClearRect1Bottom => _word1.Extract(112, 14);
+ public int ClearRect0Left => (int)_word0.Extract(0, 14);
+ public int ClearRect0Right => (int)_word0.Extract(16, 14);
+ public int ClearRect0Top => (int)_word0.Extract(32, 14);
+ public int ClearRect0Bottom => (int)_word0.Extract(48, 14);
+ public int ClearRect1Left => (int)_word1.Extract(64, 14);
+ public int ClearRect1Right => (int)_word1.Extract(80, 14);
+ public int ClearRect1Top => (int)_word1.Extract(96, 14);
+ public int ClearRect1Bottom => (int)_word1.Extract(112, 14);
}
}
diff --git a/Ryujinx.Graphics.Vic/Types/LumaKeyStruct.cs b/Ryujinx.Graphics.Vic/Types/LumaKeyStruct.cs
index df5e647e..5d83bd71 100644
--- a/Ryujinx.Graphics.Vic/Types/LumaKeyStruct.cs
+++ b/Ryujinx.Graphics.Vic/Types/LumaKeyStruct.cs
@@ -1,17 +1,19 @@
-namespace Ryujinx.Graphics.Vic.Types
+using Ryujinx.Common.Utilities;
+
+namespace Ryujinx.Graphics.Vic.Types
{
struct LumaKeyStruct
{
private long _word0;
private long _word1;
- public int LumaCoeff0 => _word0.Extract(0, 20);
- public int LumaCoeff1 => _word0.Extract(20, 20);
- public int LumaCoeff2 => _word0.Extract(40, 20);
- public int LumaRShift => _word0.Extract(60, 4);
- public int LumaCoeff3 => _word1.Extract(64, 20);
- public int LumaKeyLower => _word1.Extract(84, 10);
- public int LumaKeyUpper => _word1.Extract(94, 10);
+ public int LumaCoeff0 => (int)_word0.Extract(0, 20);
+ public int LumaCoeff1 => (int)_word0.Extract(20, 20);
+ public int LumaCoeff2 => (int)_word0.Extract(40, 20);
+ public int LumaRShift => (int)_word0.Extract(60, 4);
+ public int LumaCoeff3 => (int)_word1.Extract(64, 20);
+ public int LumaKeyLower => (int)_word1.Extract(84, 10);
+ public int LumaKeyUpper => (int)_word1.Extract(94, 10);
public bool LumaKeyEnabled => _word1.Extract(104);
}
}
diff --git a/Ryujinx.Graphics.Vic/Types/MatrixStruct.cs b/Ryujinx.Graphics.Vic/Types/MatrixStruct.cs
index b9dcd8ff..c0a4c34e 100644
--- a/Ryujinx.Graphics.Vic/Types/MatrixStruct.cs
+++ b/Ryujinx.Graphics.Vic/Types/MatrixStruct.cs
@@ -1,4 +1,6 @@
-namespace Ryujinx.Graphics.Vic.Types
+using Ryujinx.Common.Utilities;
+
+namespace Ryujinx.Graphics.Vic.Types
{
struct MatrixStruct
{
@@ -7,19 +9,19 @@
private long _word2;
private long _word3;
- public int MatrixCoeff00 => _word0.ExtractSx(0, 20);
- public int MatrixCoeff10 => _word0.ExtractSx(20, 20);
- public int MatrixCoeff20 => _word0.ExtractSx(40, 20);
- public int MatrixRShift => _word0.Extract(60, 4);
- public int MatrixCoeff01 => _word1.ExtractSx(64, 20);
- public int MatrixCoeff11 => _word1.ExtractSx(84, 20);
- public int MatrixCoeff21 => _word1.ExtractSx(104, 20);
+ public int MatrixCoeff00 => (int)_word0.ExtractSx(0, 20);
+ public int MatrixCoeff10 => (int)_word0.ExtractSx(20, 20);
+ public int MatrixCoeff20 => (int)_word0.ExtractSx(40, 20);
+ public int MatrixRShift => (int)_word0.Extract(60, 4);
+ public int MatrixCoeff01 => (int)_word1.ExtractSx(64, 20);
+ public int MatrixCoeff11 => (int)_word1.ExtractSx(84, 20);
+ public int MatrixCoeff21 => (int)_word1.ExtractSx(104, 20);
public bool MatrixEnable => _word1.Extract(127);
- public int MatrixCoeff02 => _word2.ExtractSx(128, 20);
- public int MatrixCoeff12 => _word2.ExtractSx(148, 20);
- public int MatrixCoeff22 => _word2.ExtractSx(168, 20);
- public int MatrixCoeff03 => _word3.ExtractSx(192, 20);
- public int MatrixCoeff13 => _word3.ExtractSx(212, 20);
- public int MatrixCoeff23 => _word3.ExtractSx(232, 20);
+ public int MatrixCoeff02 => (int)_word2.ExtractSx(128, 20);
+ public int MatrixCoeff12 => (int)_word2.ExtractSx(148, 20);
+ public int MatrixCoeff22 => (int)_word2.ExtractSx(168, 20);
+ public int MatrixCoeff03 => (int)_word3.ExtractSx(192, 20);
+ public int MatrixCoeff13 => (int)_word3.ExtractSx(212, 20);
+ public int MatrixCoeff23 => (int)_word3.ExtractSx(232, 20);
}
}
diff --git a/Ryujinx.Graphics.Vic/Types/OutputConfig.cs b/Ryujinx.Graphics.Vic/Types/OutputConfig.cs
index 29633297..7b866994 100644
--- a/Ryujinx.Graphics.Vic/Types/OutputConfig.cs
+++ b/Ryujinx.Graphics.Vic/Types/OutputConfig.cs
@@ -1,4 +1,6 @@
-namespace Ryujinx.Graphics.Vic.Types
+using Ryujinx.Common.Utilities;
+
+namespace Ryujinx.Graphics.Vic.Types
{
struct OutputConfig
{
@@ -7,19 +9,19 @@
private long _word1;
#pragma warning restore CS0649
- public int AlphaFillMode => _word0.Extract(0, 3);
- public int AlphaFillSlot => _word0.Extract(3, 3);
- public int BackgroundAlpha => _word0.Extract(6, 10);
- public int BackgroundR => _word0.Extract(16, 10);
- public int BackgroundG => _word0.Extract(26, 10);
- public int BackgroundB => _word0.Extract(36, 10);
- public int RegammaMode => _word0.Extract(46, 2);
+ public int AlphaFillMode => (int)_word0.Extract(0, 3);
+ public int AlphaFillSlot => (int)_word0.Extract(3, 3);
+ public int BackgroundAlpha => (int)_word0.Extract(6, 10);
+ public int BackgroundR => (int)_word0.Extract(16, 10);
+ public int BackgroundG => (int)_word0.Extract(26, 10);
+ public int BackgroundB => (int)_word0.Extract(36, 10);
+ public int RegammaMode => (int)_word0.Extract(46, 2);
public bool OutputFlipX => _word0.Extract(48);
public bool OutputFlipY => _word0.Extract(49);
public bool OutputTranspose => _word0.Extract(50);
- public int TargetRectLeft => _word1.Extract(64, 14);
- public int TargetRectRight => _word1.Extract(80, 14);
- public int TargetRectTop => _word1.Extract(96, 14);
- public int TargetRectBottom => _word1.Extract(112, 14);
+ public int TargetRectLeft => (int)_word1.Extract(64, 14);
+ public int TargetRectRight => (int)_word1.Extract(80, 14);
+ public int TargetRectTop => (int)_word1.Extract(96, 14);
+ public int TargetRectBottom => (int)_word1.Extract(112, 14);
}
}
diff --git a/Ryujinx.Graphics.Vic/Types/OutputSurfaceConfig.cs b/Ryujinx.Graphics.Vic/Types/OutputSurfaceConfig.cs
index 0a29b7b8..6a8b21e1 100644
--- a/Ryujinx.Graphics.Vic/Types/OutputSurfaceConfig.cs
+++ b/Ryujinx.Graphics.Vic/Types/OutputSurfaceConfig.cs
@@ -1,4 +1,6 @@
-namespace Ryujinx.Graphics.Vic.Types
+using Ryujinx.Common.Utilities;
+
+namespace Ryujinx.Graphics.Vic.Types
{
struct OutputSurfaceConfig
{
@@ -8,15 +10,15 @@
#pragma warning restore CS0649
public PixelFormat OutPixelFormat => (PixelFormat)_word0.Extract(0, 7);
- public int OutChromaLocHoriz => _word0.Extract(7, 2);
- public int OutChromaLocVert => _word0.Extract(9, 2);
- public int OutBlkKind => _word0.Extract(11, 4);
- public int OutBlkHeight => _word0.Extract(15, 4);
- public int OutSurfaceWidth => _word0.Extract(32, 14);
- public int OutSurfaceHeight => _word0.Extract(46, 14);
- public int OutLumaWidth => _word1.Extract(64, 14);
- public int OutLumaHeight => _word1.Extract(78, 14);
- public int OutChromaWidth => _word1.Extract(96, 14);
- public int OutChromaHeight => _word1.Extract(110, 14);
+ public int OutChromaLocHoriz => (int)_word0.Extract(7, 2);
+ public int OutChromaLocVert => (int)_word0.Extract(9, 2);
+ public int OutBlkKind => (int)_word0.Extract(11, 4);
+ public int OutBlkHeight => (int)_word0.Extract(15, 4);
+ public int OutSurfaceWidth => (int)_word0.Extract(32, 14);
+ public int OutSurfaceHeight => (int)_word0.Extract(46, 14);
+ public int OutLumaWidth => (int)_word1.Extract(64, 14);
+ public int OutLumaHeight => (int)_word1.Extract(78, 14);
+ public int OutChromaWidth => (int)_word1.Extract(96, 14);
+ public int OutChromaHeight => (int)_word1.Extract(110, 14);
}
}
diff --git a/Ryujinx.Graphics.Vic/Types/PipeConfig.cs b/Ryujinx.Graphics.Vic/Types/PipeConfig.cs
index cae04536..76720eb1 100644
--- a/Ryujinx.Graphics.Vic/Types/PipeConfig.cs
+++ b/Ryujinx.Graphics.Vic/Types/PipeConfig.cs
@@ -1,4 +1,6 @@
-namespace Ryujinx.Graphics.Vic.Types
+using Ryujinx.Common.Utilities;
+
+namespace Ryujinx.Graphics.Vic.Types
{
struct PipeConfig
{
@@ -7,7 +9,7 @@
private long _word1;
#pragma warning restore CS0169, CS0649
- public int DownsampleHoriz => _word0.Extract(0, 11);
- public int DownsampleVert => _word0.Extract(16, 11);
+ public int DownsampleHoriz => (int)_word0.Extract(0, 11);
+ public int DownsampleVert => (int)_word0.Extract(16, 11);
}
}
diff --git a/Ryujinx.Graphics.Vic/Types/SlotConfig.cs b/Ryujinx.Graphics.Vic/Types/SlotConfig.cs
index 373e76f6..aba61add 100644
--- a/Ryujinx.Graphics.Vic/Types/SlotConfig.cs
+++ b/Ryujinx.Graphics.Vic/Types/SlotConfig.cs
@@ -1,4 +1,6 @@
-namespace Ryujinx.Graphics.Vic.Types
+using Ryujinx.Common.Utilities;
+
+namespace Ryujinx.Graphics.Vic.Types
{
struct SlotConfig
{
@@ -28,36 +30,36 @@
public bool PpMotionFieldEnable => _word0.Extract(14);
public bool CombMotionFieldEnable => _word0.Extract(15);
public FrameFormat FrameFormat => (FrameFormat)_word0.Extract(16, 4);
- public int FilterLengthY => _word0.Extract(20, 2);
- public int FilterLengthX => _word0.Extract(22, 2);
- public int Panoramic => _word0.Extract(24, 12);
- public int DetailFltClamp => _word0.Extract(58, 6);
- public int FilterNoise => _word1.Extract(64, 10);
- public int FilterDetail => _word1.Extract(74, 10);
- public int ChromaNoise => _word1.Extract(84, 10);
- public int ChromaDetail => _word1.Extract(94, 10);
+ public int FilterLengthY => (int)_word0.Extract(20, 2);
+ public int FilterLengthX => (int)_word0.Extract(22, 2);
+ public int Panoramic => (int)_word0.Extract(24, 12);
+ public int DetailFltClamp => (int)_word0.Extract(58, 6);
+ public int FilterNoise => (int)_word1.Extract(64, 10);
+ public int FilterDetail => (int)_word1.Extract(74, 10);
+ public int ChromaNoise => (int)_word1.Extract(84, 10);
+ public int ChromaDetail => (int)_word1.Extract(94, 10);
public DeinterlaceMode DeinterlaceMode => (DeinterlaceMode)_word1.Extract(104, 4);
- public int MotionAccumWeight => _word1.Extract(108, 3);
- public int NoiseIir => _word1.Extract(111, 11);
- public int LightLevel => _word1.Extract(122, 4);
- public int SoftClampLow => _word2.Extract(128, 10);
- public int SoftClampHigh => _word2.Extract(138, 10);
- public int PlanarAlpha => _word2.Extract(160, 10);
+ public int MotionAccumWeight => (int)_word1.Extract(108, 3);
+ public int NoiseIir => (int)_word1.Extract(111, 11);
+ public int LightLevel => (int)_word1.Extract(122, 4);
+ public int SoftClampLow => (int)_word2.Extract(128, 10);
+ public int SoftClampHigh => (int)_word2.Extract(138, 10);
+ public int PlanarAlpha => (int)_word2.Extract(160, 10);
public bool ConstantAlpha => _word2.Extract(170);
- public int StereoInterleave => _word2.Extract(171, 3);
+ public int StereoInterleave => (int)_word2.Extract(171, 3);
public bool ClipEnabled => _word2.Extract(174);
- public int ClearRectMask => _word2.Extract(175, 8);
- public int DegammaMode => _word2.Extract(183, 2);
+ public int ClearRectMask => (int)_word2.Extract(175, 8);
+ public int DegammaMode => (int)_word2.Extract(183, 2);
public bool DecompressEnable => _word2.Extract(186);
- public int DecompressCtbCount => _word3.Extract(192, 8);
- public int DecompressZbcColor => _word3.Extract(200, 32);
- public int SourceRectLeft => _word4.Extract(256, 30);
- public int SourceRectRight => _word4.Extract(288, 30);
- public int SourceRectTop => _word5.Extract(320, 30);
- public int SourceRectBottom => _word5.Extract(352, 30);
- public int DstRectLeft => _word6.Extract(384, 14);
- public int DstRectRight => _word6.Extract(400, 14);
- public int DstRectTop => _word6.Extract(416, 14);
- public int DstRectBottom => _word6.Extract(432, 14);
+ public int DecompressCtbCount => (int)_word3.Extract(192, 8);
+ public int DecompressZbcColor => (int)_word3.Extract(200, 32);
+ public int SourceRectLeft => (int)_word4.Extract(256, 30);
+ public int SourceRectRight => (int)_word4.Extract(288, 30);
+ public int SourceRectTop => (int)_word5.Extract(320, 30);
+ public int SourceRectBottom => (int)_word5.Extract(352, 30);
+ public int DstRectLeft => (int)_word6.Extract(384, 14);
+ public int DstRectRight => (int)_word6.Extract(400, 14);
+ public int DstRectTop => (int)_word6.Extract(416, 14);
+ public int DstRectBottom => (int)_word6.Extract(432, 14);
}
}
diff --git a/Ryujinx.Graphics.Vic/Types/SlotSurfaceConfig.cs b/Ryujinx.Graphics.Vic/Types/SlotSurfaceConfig.cs
index 7396afa1..4492c85f 100644
--- a/Ryujinx.Graphics.Vic/Types/SlotSurfaceConfig.cs
+++ b/Ryujinx.Graphics.Vic/Types/SlotSurfaceConfig.cs
@@ -1,4 +1,6 @@
-namespace Ryujinx.Graphics.Vic.Types
+using Ryujinx.Common.Utilities;
+
+namespace Ryujinx.Graphics.Vic.Types
{
struct SlotSurfaceConfig
{
@@ -6,16 +8,16 @@
private long _word1;
public PixelFormat SlotPixelFormat => (PixelFormat)_word0.Extract(0, 7);
- public int SlotChromaLocHoriz => _word0.Extract(7, 2);
- public int SlotChromaLocVert => _word0.Extract(9, 2);
- public int SlotBlkKind => _word0.Extract(11, 4);
- public int SlotBlkHeight => _word0.Extract(15, 4);
- public int SlotCacheWidth => _word0.Extract(19, 3);
- public int SlotSurfaceWidth => _word0.Extract(32, 14);
- public int SlotSurfaceHeight => _word0.Extract(46, 14);
- public int SlotLumaWidth => _word1.Extract(64, 14);
- public int SlotLumaHeight => _word1.Extract(78, 14);
- public int SlotChromaWidth => _word1.Extract(96, 14);
- public int SlotChromaHeight => _word1.Extract(110, 14);
+ public int SlotChromaLocHoriz => (int)_word0.Extract(7, 2);
+ public int SlotChromaLocVert => (int)_word0.Extract(9, 2);
+ public int SlotBlkKind => (int)_word0.Extract(11, 4);
+ public int SlotBlkHeight => (int)_word0.Extract(15, 4);
+ public int SlotCacheWidth => (int)_word0.Extract(19, 3);
+ public int SlotSurfaceWidth => (int)_word0.Extract(32, 14);
+ public int SlotSurfaceHeight => (int)_word0.Extract(46, 14);
+ public int SlotLumaWidth => (int)_word1.Extract(64, 14);
+ public int SlotLumaHeight => (int)_word1.Extract(78, 14);
+ public int SlotChromaWidth => (int)_word1.Extract(96, 14);
+ public int SlotChromaHeight => (int)_word1.Extract(110, 14);
}
}
diff --git a/Ryujinx.HLE/HOS/Horizon.cs b/Ryujinx.HLE/HOS/Horizon.cs
index 288c308a..a8b5be33 100644
--- a/Ryujinx.HLE/HOS/Horizon.cs
+++ b/Ryujinx.HLE/HOS/Horizon.cs
@@ -36,6 +36,7 @@ using Ryujinx.HLE.HOS.Services.SurfaceFlinger;
using Ryujinx.HLE.HOS.Services.Time.Clock;
using Ryujinx.HLE.HOS.SystemState;
using Ryujinx.HLE.Loaders.Executables;
+using Ryujinx.Horizon;
using System;
using System.Collections.Generic;
using System.IO;
@@ -319,6 +320,42 @@ namespace Ryujinx.HLE.HOS
ViServer = new ServerBase(KernelContext, "ViServerU");
ViServerM = new ServerBase(KernelContext, "ViServerM");
ViServerS = new ServerBase(KernelContext, "ViServerS");
+
+ StartNewServices();
+ }
+
+ private void StartNewServices()
+ {
+ var services = ServiceTable.GetServices(new HorizonOptions(Device.Configuration.IgnoreMissingServices));
+
+ foreach (var service in services)
+ {
+ const ProcessCreationFlags flags =
+ ProcessCreationFlags.EnableAslr |
+ ProcessCreationFlags.AddressSpace64Bit |
+ ProcessCreationFlags.Is64Bit |
+ ProcessCreationFlags.PoolPartitionSystem;
+
+ ProcessCreationInfo creationInfo = new ProcessCreationInfo("Service", 1, 0, 0x8000000, 1, flags, 0, 0);
+
+ int[] defaultCapabilities = new int[]
+ {
+ 0x030363F7,
+ 0x1FFFFFCF,
+ 0x207FFFEF,
+ 0x47E0060F,
+ 0x0048BFFF,
+ 0x01007FFF
+ };
+
+ // TODO:
+ // - Pass enough information (capabilities, process creation info, etc) on ServiceEntry for proper initialization.
+ // - Have the ThreadStart function take the syscall, address space and thread context parameters instead of passing them here.
+ KernelStatic.StartInitialProcess(KernelContext, creationInfo, defaultCapabilities, 44, () =>
+ {
+ service.Start(KernelContext.Syscall, KernelStatic.GetCurrentProcess().CpuMemory, KernelStatic.GetCurrentThread().ThreadContext);
+ });
+ }
}
public void LoadKip(string kipPath)
diff --git a/Ryujinx.HLE/HOS/Kernel/Common/KAutoObject.cs b/Ryujinx.HLE/HOS/Kernel/Common/KAutoObject.cs
index a94b280f..424bf788 100644
--- a/Ryujinx.HLE/HOS/Kernel/Common/KAutoObject.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Common/KAutoObject.cs
@@ -1,3 +1,4 @@
+using Ryujinx.Horizon.Common;
using System.Diagnostics;
using System.Threading;
@@ -16,24 +17,24 @@ namespace Ryujinx.HLE.HOS.Kernel.Common
_referenceCount = 1;
}
- public virtual KernelResult SetName(string name)
+ public virtual Result SetName(string name)
{
if (!KernelContext.AutoObjectNames.TryAdd(name, this))
{
return KernelResult.InvalidState;
}
- return KernelResult.Success;
+ return Result.Success;
}
- public static KernelResult RemoveName(KernelContext context, string name)
+ public static Result RemoveName(KernelContext context, string name)
{
if (!context.AutoObjectNames.TryRemove(name, out _))
{
return KernelResult.NotFound;
}
- return KernelResult.Success;
+ return Result.Success;
}
public static KAutoObject FindNamedObject(KernelContext context, string name)
diff --git a/Ryujinx.HLE/HOS/Kernel/Common/KResourceLimit.cs b/Ryujinx.HLE/HOS/Kernel/Common/KResourceLimit.cs
index 7caff21a..b1a602f1 100644
--- a/Ryujinx.HLE/HOS/Kernel/Common/KResourceLimit.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Common/KResourceLimit.cs
@@ -1,5 +1,6 @@
using Ryujinx.Common;
using Ryujinx.HLE.HOS.Kernel.Threading;
+using Ryujinx.Horizon.Common;
using System.Collections.Generic;
namespace Ryujinx.HLE.HOS.Kernel.Common
@@ -159,7 +160,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Common
}
}
- public KernelResult SetLimitValue(LimitableResource resource, long limit)
+ public Result SetLimitValue(LimitableResource resource, long limit)
{
int index = GetIndex(resource);
@@ -170,7 +171,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Common
_limit[index] = limit;
_peak[index] = _current[index];
- return KernelResult.Success;
+ return Result.Success;
}
else
{
diff --git a/Ryujinx.HLE/HOS/Kernel/Common/KernelInit.cs b/Ryujinx.HLE/HOS/Kernel/Common/KernelInit.cs
index 9829ae03..efa2a480 100644
--- a/Ryujinx.HLE/HOS/Kernel/Common/KernelInit.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Common/KernelInit.cs
@@ -1,4 +1,5 @@
using Ryujinx.HLE.HOS.Kernel.Memory;
+using Ryujinx.Horizon.Common;
using System;
namespace Ryujinx.HLE.HOS.Kernel.Common
@@ -21,9 +22,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Common
public static void InitializeResourceLimit(KResourceLimit resourceLimit, MemorySize size)
{
- void EnsureSuccess(KernelResult result)
+ void EnsureSuccess(Result result)
{
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
throw new InvalidOperationException($"Unexpected result \"{result}\".");
}
diff --git a/Ryujinx.HLE/HOS/Kernel/Common/KernelResult.cs b/Ryujinx.HLE/HOS/Kernel/Common/KernelResult.cs
deleted file mode 100644
index 357b01ea..00000000
--- a/Ryujinx.HLE/HOS/Kernel/Common/KernelResult.cs
+++ /dev/null
@@ -1,37 +0,0 @@
-namespace Ryujinx.HLE.HOS.Kernel.Common
-{
- enum KernelResult
- {
- Success = 0,
- SessionCountExceeded = 0xe01,
- InvalidCapability = 0x1c01,
- ThreadNotStarted = 0x7201,
- ThreadTerminating = 0x7601,
- InvalidSize = 0xca01,
- InvalidAddress = 0xcc01,
- OutOfResource = 0xce01,
- OutOfMemory = 0xd001,
- HandleTableFull = 0xd201,
- InvalidMemState = 0xd401,
- InvalidPermission = 0xd801,
- InvalidMemRange = 0xdc01,
- InvalidPriority = 0xe001,
- InvalidCpuCore = 0xe201,
- InvalidHandle = 0xe401,
- UserCopyFailed = 0xe601,
- InvalidCombination = 0xe801,
- TimedOut = 0xea01,
- Cancelled = 0xec01,
- MaximumExceeded = 0xee01,
- InvalidEnumValue = 0xf001,
- NotFound = 0xf201,
- InvalidThread = 0xf401,
- PortRemoteClosed = 0xf601,
- InvalidState = 0xfa01,
- ReservedValue = 0xfc01,
- PortClosed = 0x10601,
- ResLimitExceeded = 0x10801,
- OutOfVaSpace = 0x20601,
- CmdBufferTooSmall = 0x20801
- }
-} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Kernel/Common/OnScopeExit.cs b/Ryujinx.HLE/HOS/Kernel/Common/OnScopeExit.cs
deleted file mode 100644
index d805a4e1..00000000
--- a/Ryujinx.HLE/HOS/Kernel/Common/OnScopeExit.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-using System;
-
-namespace Ryujinx.HLE.HOS.Kernel.Common
-{
- readonly struct OnScopeExit : IDisposable
- {
- private readonly Action _action;
- public OnScopeExit(Action action) => _action = action;
- public void Dispose() => _action();
- }
-}
diff --git a/Ryujinx.HLE/HOS/Kernel/Ipc/KBufferDescriptorTable.cs b/Ryujinx.HLE/HOS/Kernel/Ipc/KBufferDescriptorTable.cs
index 5726299b..593d2c9d 100644
--- a/Ryujinx.HLE/HOS/Kernel/Ipc/KBufferDescriptorTable.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Ipc/KBufferDescriptorTable.cs
@@ -1,6 +1,6 @@
using Ryujinx.Common;
-using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Memory;
+using Ryujinx.Horizon.Common;
using System.Collections.Generic;
namespace Ryujinx.HLE.HOS.Kernel.Ipc
@@ -20,38 +20,38 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
_exchangeBufferDescriptors = new List<KBufferDescriptor>(MaxInternalBuffersCount);
}
- public KernelResult AddSendBuffer(ulong src, ulong dst, ulong size, MemoryState state)
+ public Result AddSendBuffer(ulong src, ulong dst, ulong size, MemoryState state)
{
return Add(_sendBufferDescriptors, src, dst, size, state);
}
- public KernelResult AddReceiveBuffer(ulong src, ulong dst, ulong size, MemoryState state)
+ public Result AddReceiveBuffer(ulong src, ulong dst, ulong size, MemoryState state)
{
return Add(_receiveBufferDescriptors, src, dst, size, state);
}
- public KernelResult AddExchangeBuffer(ulong src, ulong dst, ulong size, MemoryState state)
+ public Result AddExchangeBuffer(ulong src, ulong dst, ulong size, MemoryState state)
{
return Add(_exchangeBufferDescriptors, src, dst, size, state);
}
- private KernelResult Add(List<KBufferDescriptor> list, ulong src, ulong dst, ulong size, MemoryState state)
+ private Result Add(List<KBufferDescriptor> list, ulong src, ulong dst, ulong size, MemoryState state)
{
if (list.Count < MaxInternalBuffersCount)
{
list.Add(new KBufferDescriptor(src, dst, size, state));
- return KernelResult.Success;
+ return Result.Success;
}
return KernelResult.OutOfMemory;
}
- public KernelResult CopyBuffersToClient(KPageTableBase memoryManager)
+ public Result CopyBuffersToClient(KPageTableBase memoryManager)
{
- KernelResult result = CopyToClient(memoryManager, _receiveBufferDescriptors);
+ Result result = CopyToClient(memoryManager, _receiveBufferDescriptors);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
return result;
}
@@ -59,7 +59,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
return CopyToClient(memoryManager, _exchangeBufferDescriptors);
}
- private KernelResult CopyToClient(KPageTableBase memoryManager, List<KBufferDescriptor> list)
+ private Result CopyToClient(KPageTableBase memoryManager, List<KBufferDescriptor> list)
{
foreach (KBufferDescriptor desc in list)
{
@@ -94,7 +94,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
copySize = desc.Size;
}
- KernelResult result = memoryManager.CopyDataFromCurrentProcess(
+ Result result = memoryManager.CopyDataFromCurrentProcess(
desc.ClientAddress,
copySize,
stateMask,
@@ -104,7 +104,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
MemoryAttribute.None,
desc.ServerAddress);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
return result;
}
@@ -120,7 +120,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
if (clientEndAddrTruncated < clientEndAddrRounded &&
(clientAddrTruncated == clientAddrRounded || clientAddrTruncated < clientEndAddrTruncated))
{
- KernelResult result = memoryManager.CopyDataFromCurrentProcess(
+ Result result = memoryManager.CopyDataFromCurrentProcess(
clientEndAddrTruncated,
clientEndAddr - clientEndAddrTruncated,
stateMask,
@@ -130,28 +130,28 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
MemoryAttribute.None,
serverEndAddrTruncated);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
return result;
}
}
}
- return KernelResult.Success;
+ return Result.Success;
}
- public KernelResult UnmapServerBuffers(KPageTableBase memoryManager)
+ public Result UnmapServerBuffers(KPageTableBase memoryManager)
{
- KernelResult result = UnmapServer(memoryManager, _sendBufferDescriptors);
+ Result result = UnmapServer(memoryManager, _sendBufferDescriptors);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
return result;
}
result = UnmapServer(memoryManager, _receiveBufferDescriptors);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
return result;
}
@@ -159,36 +159,36 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
return UnmapServer(memoryManager, _exchangeBufferDescriptors);
}
- private KernelResult UnmapServer(KPageTableBase memoryManager, List<KBufferDescriptor> list)
+ private Result UnmapServer(KPageTableBase memoryManager, List<KBufferDescriptor> list)
{
foreach (KBufferDescriptor descriptor in list)
{
- KernelResult result = memoryManager.UnmapNoAttributeIfStateEquals(
+ Result result = memoryManager.UnmapNoAttributeIfStateEquals(
descriptor.ServerAddress,
descriptor.Size,
descriptor.State);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
return result;
}
}
- return KernelResult.Success;
+ return Result.Success;
}
- public KernelResult RestoreClientBuffers(KPageTableBase memoryManager)
+ public Result RestoreClientBuffers(KPageTableBase memoryManager)
{
- KernelResult result = RestoreClient(memoryManager, _sendBufferDescriptors);
+ Result result = RestoreClient(memoryManager, _sendBufferDescriptors);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
return result;
}
result = RestoreClient(memoryManager, _receiveBufferDescriptors);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
return result;
}
@@ -196,22 +196,22 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
return RestoreClient(memoryManager, _exchangeBufferDescriptors);
}
- private KernelResult RestoreClient(KPageTableBase memoryManager, List<KBufferDescriptor> list)
+ private Result RestoreClient(KPageTableBase memoryManager, List<KBufferDescriptor> list)
{
foreach (KBufferDescriptor descriptor in list)
{
- KernelResult result = memoryManager.UnmapIpcRestorePermission(
+ Result result = memoryManager.UnmapIpcRestorePermission(
descriptor.ClientAddress,
descriptor.Size,
descriptor.State);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
return result;
}
}
- return KernelResult.Success;
+ return Result.Success;
}
}
} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Kernel/Ipc/KClientPort.cs b/Ryujinx.HLE/HOS/Kernel/Ipc/KClientPort.cs
index 6e935077..eb7c5a41 100644
--- a/Ryujinx.HLE/HOS/Kernel/Ipc/KClientPort.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Ipc/KClientPort.cs
@@ -1,5 +1,6 @@
using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Process;
+using Ryujinx.Horizon.Common;
using System.Threading;
namespace Ryujinx.HLE.HOS.Kernel.Ipc
@@ -19,7 +20,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
_parent = parent;
}
- public KernelResult Connect(out KClientSession clientSession)
+ public Result Connect(out KClientSession clientSession)
{
clientSession = null;
@@ -40,9 +41,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
KSession session = new KSession(KernelContext, this);
- KernelResult result = _parent.EnqueueIncomingSession(session.ServerSession);
+ Result result = _parent.EnqueueIncomingSession(session.ServerSession);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
session.ClientSession.DecrementReferenceCount();
session.ServerSession.DecrementReferenceCount();
@@ -55,7 +56,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
return result;
}
- public KernelResult ConnectLight(out KLightClientSession clientSession)
+ public Result ConnectLight(out KLightClientSession clientSession)
{
clientSession = null;
@@ -76,9 +77,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
KLightSession session = new KLightSession(KernelContext);
- KernelResult result = _parent.EnqueueIncomingLightSession(session.ServerSession);
+ Result result = _parent.EnqueueIncomingLightSession(session.ServerSession);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
session.ClientSession.DecrementReferenceCount();
session.ServerSession.DecrementReferenceCount();
@@ -128,7 +129,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
}
}
- public new static KernelResult RemoveName(KernelContext context, string name)
+ public new static Result RemoveName(KernelContext context, string name)
{
KAutoObject foundObj = FindNamedObject(context, name);
diff --git a/Ryujinx.HLE/HOS/Kernel/Ipc/KClientSession.cs b/Ryujinx.HLE/HOS/Kernel/Ipc/KClientSession.cs
index 7bbc3ba2..a24bcc31 100644
--- a/Ryujinx.HLE/HOS/Kernel/Ipc/KClientSession.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Ipc/KClientSession.cs
@@ -1,6 +1,7 @@
using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Process;
using Ryujinx.HLE.HOS.Kernel.Threading;
+using Ryujinx.Horizon.Common;
namespace Ryujinx.HLE.HOS.Kernel.Ipc
{
@@ -27,7 +28,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
CreatorProcess.IncrementReferenceCount();
}
- public KernelResult SendSyncRequest(ulong customCmdBuffAddr = 0, ulong customCmdBuffSize = 0)
+ public Result SendSyncRequest(ulong customCmdBuffAddr = 0, ulong customCmdBuffSize = 0)
{
KThread currentThread = KernelStatic.GetCurrentThread();
@@ -36,13 +37,13 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
KernelContext.CriticalSection.Enter();
currentThread.SignaledObj = null;
- currentThread.ObjSyncResult = KernelResult.Success;
+ currentThread.ObjSyncResult = Result.Success;
- KernelResult result = _parent.ServerSession.EnqueueRequest(request);
+ Result result = _parent.ServerSession.EnqueueRequest(request);
KernelContext.CriticalSection.Leave();
- if (result == KernelResult.Success)
+ if (result == Result.Success)
{
result = currentThread.ObjSyncResult;
}
@@ -50,7 +51,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
return result;
}
- public KernelResult SendAsyncRequest(KWritableEvent asyncEvent, ulong customCmdBuffAddr = 0, ulong customCmdBuffSize = 0)
+ public Result SendAsyncRequest(KWritableEvent asyncEvent, ulong customCmdBuffAddr = 0, ulong customCmdBuffSize = 0)
{
KThread currentThread = KernelStatic.GetCurrentThread();
@@ -58,7 +59,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
KernelContext.CriticalSection.Enter();
- KernelResult result = _parent.ServerSession.EnqueueRequest(request);
+ Result result = _parent.ServerSession.EnqueueRequest(request);
KernelContext.CriticalSection.Leave();
diff --git a/Ryujinx.HLE/HOS/Kernel/Ipc/KPort.cs b/Ryujinx.HLE/HOS/Kernel/Ipc/KPort.cs
index 2f67aeae..93f0f34c 100644
--- a/Ryujinx.HLE/HOS/Kernel/Ipc/KPort.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Ipc/KPort.cs
@@ -1,4 +1,5 @@
using Ryujinx.HLE.HOS.Kernel.Common;
+using Ryujinx.Horizon.Common;
namespace Ryujinx.HLE.HOS.Kernel.Ipc
{
@@ -7,26 +8,26 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
public KServerPort ServerPort { get; }
public KClientPort ClientPort { get; }
- private long _nameAddress;
+ private string _name;
private ChannelState _state;
public bool IsLight { get; private set; }
- public KPort(KernelContext context, int maxSessions, bool isLight, long nameAddress) : base(context)
+ public KPort(KernelContext context, int maxSessions, bool isLight, string name) : base(context)
{
ServerPort = new KServerPort(context, this);
ClientPort = new KClientPort(context, this, maxSessions);
- IsLight = isLight;
- _nameAddress = nameAddress;
+ IsLight = isLight;
+ _name = name;
_state = ChannelState.Open;
}
- public KernelResult EnqueueIncomingSession(KServerSession session)
+ public Result EnqueueIncomingSession(KServerSession session)
{
- KernelResult result;
+ Result result;
KernelContext.CriticalSection.Enter();
@@ -34,7 +35,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
{
ServerPort.EnqueueIncomingSession(session);
- result = KernelResult.Success;
+ result = Result.Success;
}
else
{
@@ -46,9 +47,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
return result;
}
- public KernelResult EnqueueIncomingLightSession(KLightServerSession session)
+ public Result EnqueueIncomingLightSession(KLightServerSession session)
{
- KernelResult result;
+ Result result;
KernelContext.CriticalSection.Enter();
@@ -56,7 +57,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
{
ServerPort.EnqueueIncomingLightSession(session);
- result = KernelResult.Success;
+ result = Result.Success;
}
else
{
diff --git a/Ryujinx.HLE/HOS/Kernel/Ipc/KServerSession.cs b/Ryujinx.HLE/HOS/Kernel/Ipc/KServerSession.cs
index 199e78dc..9c2184d9 100644
--- a/Ryujinx.HLE/HOS/Kernel/Ipc/KServerSession.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Ipc/KServerSession.cs
@@ -3,6 +3,7 @@ using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Memory;
using Ryujinx.HLE.HOS.Kernel.Process;
using Ryujinx.HLE.HOS.Kernel.Threading;
+using Ryujinx.Horizon.Common;
using System.Collections.Generic;
namespace Ryujinx.HLE.HOS.Kernel.Ipc
@@ -178,7 +179,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
_requests = new LinkedList<KSessionRequest>();
}
- public KernelResult EnqueueRequest(KSessionRequest request)
+ public Result EnqueueRequest(KSessionRequest request)
{
if (_parent.ClientSession.State != ChannelState.Open)
{
@@ -203,10 +204,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
Signal();
}
- return KernelResult.Success;
+ return Result.Success;
}
- public KernelResult Receive(ulong customCmdBuffAddr = 0, ulong customCmdBuffSize = 0)
+ public Result Receive(ulong customCmdBuffAddr = 0, ulong customCmdBuffSize = 0)
{
KThread serverThread = KernelStatic.GetCurrentThread();
KProcess serverProcess = serverThread.Owner;
@@ -249,12 +250,12 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
MessageHeader clientHeader = GetClientMessageHeader(clientProcess, clientMsg);
MessageHeader serverHeader = GetServerMessageHeader(serverMsg);
- KernelResult serverResult = KernelResult.NotFound;
- KernelResult clientResult = KernelResult.Success;
+ Result serverResult = KernelResult.NotFound;
+ Result clientResult = Result.Success;
void CleanUpForError()
{
- if (request.BufferDescriptorTable.UnmapServerBuffers(serverProcess.MemoryManager) == KernelResult.Success)
+ if (request.BufferDescriptorTable.UnmapServerBuffers(serverProcess.MemoryManager) == Result.Success)
{
request.BufferDescriptorTable.RestoreClientBuffers(clientProcess.MemoryManager);
}
@@ -348,7 +349,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
int newHandle = 0;
int handle = clientProcess.CpuMemory.Read<int>(clientMsg.Address + offset * 4);
- if (clientResult == KernelResult.Success && handle != 0)
+ if (clientResult == Result.Success && handle != 0)
{
clientResult = GetCopyObjectHandle(clientThread, serverProcess, handle, out newHandle);
}
@@ -365,7 +366,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
if (handle != 0)
{
- if (clientResult == KernelResult.Success)
+ if (clientResult == Result.Success)
{
clientResult = GetMoveObjectHandle(clientProcess, serverProcess, handle, out newHandle);
}
@@ -380,7 +381,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
offset++;
}
- if (clientResult != KernelResult.Success)
+ if (clientResult != Result.Success)
{
CleanUpForError();
@@ -412,7 +413,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
ref recvListDstOffset,
out ulong recvListBufferAddress);
- if (clientResult != KernelResult.Success)
+ if (clientResult != Result.Success)
{
CleanUpForError();
@@ -429,7 +430,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
MemoryAttribute.Uncached,
MemoryAttribute.None);
- if (clientResult != KernelResult.Success)
+ if (clientResult != Result.Success)
{
CleanUpForError();
@@ -498,7 +499,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
notReceiveDesc,
out dstAddress);
- if (clientResult != KernelResult.Success)
+ if (clientResult != Result.Success)
{
CleanUpForError();
@@ -518,7 +519,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
clientResult = request.BufferDescriptorTable.AddExchangeBuffer(bufferAddress, dstAddress, bufferSize, state);
}
- if (clientResult != KernelResult.Success)
+ if (clientResult != Result.Success)
{
CleanUpForError();
@@ -573,7 +574,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
serverProcess.CpuMemory.Write(copyDst, clientProcess.CpuMemory.GetSpan(copySrc, (int)copySize));
}
- if (clientResult != KernelResult.Success)
+ if (clientResult != Result.Success)
{
CleanUpForError();
@@ -581,10 +582,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
}
}
- return KernelResult.Success;
+ return Result.Success;
}
- public KernelResult Reply(ulong customCmdBuffAddr = 0, ulong customCmdBuffSize = 0)
+ public Result Reply(ulong customCmdBuffAddr = 0, ulong customCmdBuffSize = 0)
{
KThread serverThread = KernelStatic.GetCurrentThread();
KProcess serverProcess = serverThread.Owner;
@@ -618,8 +619,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
MessageHeader clientHeader = GetClientMessageHeader(clientProcess, clientMsg);
MessageHeader serverHeader = GetServerMessageHeader(serverMsg);
- KernelResult clientResult = KernelResult.Success;
- KernelResult serverResult = KernelResult.Success;
+ Result clientResult = Result.Success;
+ Result serverResult = Result.Success;
void CleanUpForError()
{
@@ -683,7 +684,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
// Copy receive and exchange buffers.
clientResult = request.BufferDescriptorTable.CopyBuffersToClient(clientProcess.MemoryManager);
- if (clientResult != KernelResult.Success)
+ if (clientResult != Result.Success)
{
CleanUpForError();
@@ -734,7 +735,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
if (handle != 0)
{
- if (clientResult == KernelResult.Success)
+ if (clientResult == Result.Success)
{
clientResult = GetMoveObjectHandle(serverProcess, clientProcess, handle, out newHandle);
}
@@ -776,7 +777,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
ref recvListDstOffset,
out recvListBufferAddress);
- if (clientResult != KernelResult.Success)
+ if (clientResult != Result.Success)
{
CleanUpForError();
@@ -793,7 +794,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
MemoryAttribute.None,
descriptor.BufferAddress);
- if (clientResult != KernelResult.Success)
+ if (clientResult != Result.Success)
{
CleanUpForError();
@@ -888,7 +889,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
return new MessageHeader(word0, word1, word2);
}
- private KernelResult GetCopyObjectHandle(KThread srcThread, KProcess dstProcess, int srcHandle, out int dstHandle)
+ private Result GetCopyObjectHandle(KThread srcThread, KProcess dstProcess, int srcHandle, out int dstHandle)
{
dstHandle = 0;
@@ -919,7 +920,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
}
}
- private KernelResult GetMoveObjectHandle(KProcess srcProcess, KProcess dstProcess, int srcHandle, out int dstHandle)
+ private Result GetMoveObjectHandle(KProcess srcProcess, KProcess dstProcess, int srcHandle, out int dstHandle)
{
dstHandle = 0;
@@ -927,7 +928,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
if (obj != null)
{
- KernelResult result = dstProcess.HandleTable.GenerateHandle(obj, out dstHandle);
+ Result result = dstProcess.HandleTable.GenerateHandle(obj, out dstHandle);
srcProcess.HandleTable.CloseHandle(srcHandle);
@@ -964,7 +965,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
return receiveList;
}
- private KernelResult GetReceiveListAddress(
+ private Result GetReceiveListAddress(
PointerBufferDesc descriptor,
Message message,
uint recvListType,
@@ -1038,7 +1039,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
address = recvListBufferAddress;
- return KernelResult.Success;
+ return Result.Success;
}
private void CloseAllHandles(Message message, MessageHeader header, KProcess process)
@@ -1166,19 +1167,19 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
return hasRequest;
}
- private void FinishRequest(KSessionRequest request, KernelResult result)
+ private void FinishRequest(KSessionRequest request, Result result)
{
KProcess clientProcess = request.ClientThread.Owner;
KProcess serverProcess = request.ServerProcess;
- KernelResult unmapResult = KernelResult.Success;
+ Result unmapResult = Result.Success;
if (serverProcess != null)
{
unmapResult = request.BufferDescriptorTable.UnmapServerBuffers(serverProcess.MemoryManager);
}
- if (unmapResult == KernelResult.Success)
+ if (unmapResult == Result.Success)
{
request.BufferDescriptorTable.RestoreClientBuffers(clientProcess.MemoryManager);
}
@@ -1186,7 +1187,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
WakeClientThread(request, result);
}
- private void WakeClientThread(KSessionRequest request, KernelResult result)
+ private void WakeClientThread(KSessionRequest request, Result result)
{
// Wait client thread waiting for a response for the given request.
if (request.AsyncEvent != null)
@@ -1203,16 +1204,16 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
}
}
- private void SendResultToAsyncRequestClient(KSessionRequest request, KernelResult result)
+ private void SendResultToAsyncRequestClient(KSessionRequest request, Result result)
{
KProcess clientProcess = request.ClientThread.Owner;
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
ulong address = request.CustomCmdBuffAddr;
clientProcess.CpuMemory.Write<ulong>(address, 0);
- clientProcess.CpuMemory.Write(address + 8, (int)result);
+ clientProcess.CpuMemory.Write(address + 8, result.ErrorCode);
}
clientProcess.MemoryManager.UnborrowIpcBuffer(request.CustomCmdBuffAddr, request.CustomCmdBuffSize);
@@ -1220,24 +1221,24 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
request.AsyncEvent.Signal();
}
- private void WakeServerThreads(KernelResult result)
+ private void WakeServerThreads(Result result)
{
// Wake all server threads waiting for requests.
KernelContext.CriticalSection.Enter();
foreach (KThread thread in WaitingThreads)
{
- WakeAndSetResult(thread, result);
+ WakeAndSetResult(thread, result, this);
}
KernelContext.CriticalSection.Leave();
}
- private void WakeAndSetResult(KThread thread, KernelResult result)
+ private void WakeAndSetResult(KThread thread, Result result, KSynchronizationObject signaledObj = null)
{
if ((thread.SchedFlags & ThreadSchedState.LowMask) == ThreadSchedState.Paused)
{
- thread.SignaledObj = null;
+ thread.SignaledObj = signaledObj;
thread.ObjSyncResult = result;
thread.Reschedule(ThreadSchedState.Running);
diff --git a/Ryujinx.HLE/HOS/Kernel/KernelStatic.cs b/Ryujinx.HLE/HOS/Kernel/KernelStatic.cs
index 625a007d..18cf212a 100644
--- a/Ryujinx.HLE/HOS/Kernel/KernelStatic.cs
+++ b/Ryujinx.HLE/HOS/Kernel/KernelStatic.cs
@@ -2,6 +2,7 @@
using Ryujinx.HLE.HOS.Kernel.Memory;
using Ryujinx.HLE.HOS.Kernel.Process;
using Ryujinx.HLE.HOS.Kernel.Threading;
+using Ryujinx.Horizon.Common;
using System;
using System.Threading;
@@ -15,7 +16,7 @@ namespace Ryujinx.HLE.HOS.Kernel
[ThreadStatic]
private static KThread CurrentThread;
- public static KernelResult StartInitialProcess(
+ public static Result StartInitialProcess(
KernelContext context,
ProcessCreationInfo creationInfo,
ReadOnlySpan<int> capabilities,
@@ -24,7 +25,7 @@ namespace Ryujinx.HLE.HOS.Kernel
{
KProcess process = new KProcess(context);
- KernelResult result = process.Initialize(
+ Result result = process.Initialize(
creationInfo,
capabilities,
context.ResourceLimit,
@@ -32,7 +33,7 @@ namespace Ryujinx.HLE.HOS.Kernel
null,
customThreadStart);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
return result;
}
diff --git a/Ryujinx.HLE/HOS/Kernel/Memory/KCodeMemory.cs b/Ryujinx.HLE/HOS/Kernel/Memory/KCodeMemory.cs
index 05cf4a4f..11474e49 100644
--- a/Ryujinx.HLE/HOS/Kernel/Memory/KCodeMemory.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Memory/KCodeMemory.cs
@@ -1,6 +1,7 @@
using Ryujinx.Common;
using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Process;
+using Ryujinx.Horizon.Common;
using System;
using System.Diagnostics;
@@ -21,13 +22,13 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
_lock = new object();
}
- public KernelResult Initialize(ulong address, ulong size)
+ public Result Initialize(ulong address, ulong size)
{
Owner = KernelStatic.GetCurrentProcess();
- KernelResult result = Owner.MemoryManager.BorrowCodeMemory(_pageList, address, size);
+ Result result = Owner.MemoryManager.BorrowCodeMemory(_pageList, address, size);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
return result;
}
@@ -39,10 +40,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
_isMapped = false;
_isOwnerMapped = false;
- return KernelResult.Success;
+ return Result.Success;
}
- public KernelResult Map(ulong address, ulong size, KMemoryPermission perm)
+ public Result Map(ulong address, ulong size, KMemoryPermission perm)
{
if (_pageList.GetPagesCount() != BitUtils.DivRoundUp<ulong>(size, (ulong)KPageTableBase.PageSize))
{
@@ -58,9 +59,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
KProcess process = KernelStatic.GetCurrentProcess();
- KernelResult result = process.MemoryManager.MapPages(address, _pageList, MemoryState.CodeWritable, KMemoryPermission.ReadAndWrite);
+ Result result = process.MemoryManager.MapPages(address, _pageList, MemoryState.CodeWritable, KMemoryPermission.ReadAndWrite);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
return result;
}
@@ -68,10 +69,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
_isMapped = true;
}
- return KernelResult.Success;
+ return Result.Success;
}
- public KernelResult MapToOwner(ulong address, ulong size, KMemoryPermission permission)
+ public Result MapToOwner(ulong address, ulong size, KMemoryPermission permission)
{
if (_pageList.GetPagesCount() != BitUtils.DivRoundUp<ulong>(size, (ulong)KPageTableBase.PageSize))
{
@@ -87,9 +88,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
Debug.Assert(permission == KMemoryPermission.Read || permission == KMemoryPermission.ReadAndExecute);
- KernelResult result = Owner.MemoryManager.MapPages(address, _pageList, MemoryState.CodeReadOnly, permission);
+ Result result = Owner.MemoryManager.MapPages(address, _pageList, MemoryState.CodeReadOnly, permission);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
return result;
}
@@ -97,10 +98,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
_isOwnerMapped = true;
}
- return KernelResult.Success;
+ return Result.Success;
}
- public KernelResult Unmap(ulong address, ulong size)
+ public Result Unmap(ulong address, ulong size)
{
if (_pageList.GetPagesCount() != BitUtils.DivRoundUp<ulong>(size, (ulong)KPageTableBase.PageSize))
{
@@ -111,9 +112,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
{
KProcess process = KernelStatic.GetCurrentProcess();
- KernelResult result = process.MemoryManager.UnmapPages(address, _pageList, MemoryState.CodeWritable);
+ Result result = process.MemoryManager.UnmapPages(address, _pageList, MemoryState.CodeWritable);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
return result;
}
@@ -123,10 +124,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
_isMapped = false;
}
- return KernelResult.Success;
+ return Result.Success;
}
- public KernelResult UnmapFromOwner(ulong address, ulong size)
+ public Result UnmapFromOwner(ulong address, ulong size)
{
if (_pageList.GetPagesCount() != BitUtils.DivRoundUp<ulong>(size, KPageTableBase.PageSize))
{
@@ -135,9 +136,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
lock (_lock)
{
- KernelResult result = Owner.MemoryManager.UnmapPages(address, _pageList, MemoryState.CodeReadOnly);
+ Result result = Owner.MemoryManager.UnmapPages(address, _pageList, MemoryState.CodeReadOnly);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
return result;
}
@@ -147,7 +148,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
_isOwnerMapped = false;
}
- return KernelResult.Success;
+ return Result.Success;
}
protected override void Destroy()
@@ -156,7 +157,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
{
ulong size = _pageList.GetPagesCount() * KPageTableBase.PageSize;
- if (Owner.MemoryManager.UnborrowCodeMemory(_address, size, _pageList) != KernelResult.Success)
+ if (Owner.MemoryManager.UnborrowCodeMemory(_address, size, _pageList) != Result.Success)
{
throw new InvalidOperationException("Unexpected failure restoring transfer memory attributes.");
}
diff --git a/Ryujinx.HLE/HOS/Kernel/Memory/KMemoryBlockManager.cs b/Ryujinx.HLE/HOS/Kernel/Memory/KMemoryBlockManager.cs
index 9cfdfda3..e9146aeb 100644
--- a/Ryujinx.HLE/HOS/Kernel/Memory/KMemoryBlockManager.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Memory/KMemoryBlockManager.cs
@@ -1,5 +1,5 @@
using Ryujinx.Common.Collections;
-using Ryujinx.HLE.HOS.Kernel.Common;
+using Ryujinx.Horizon.Common;
using System.Diagnostics;
namespace Ryujinx.HLE.HOS.Kernel.Memory
@@ -22,7 +22,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
_blockTree = new IntrusiveRedBlackTree<KMemoryBlock>();
}
- public KernelResult Initialize(ulong addrSpaceStart, ulong addrSpaceEnd, KMemoryBlockSlabManager slabManager)
+ public Result Initialize(ulong addrSpaceStart, ulong addrSpaceEnd, KMemoryBlockSlabManager slabManager)
{
_slabManager = slabManager;
_addrSpaceStart = addrSpaceStart;
@@ -43,7 +43,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
KMemoryPermission.None,
MemoryAttribute.None));
- return KernelResult.Success;
+ return Result.Success;
}
public void InsertBlock(
diff --git a/Ryujinx.HLE/HOS/Kernel/Memory/KMemoryRegionManager.cs b/Ryujinx.HLE/HOS/Kernel/Memory/KMemoryRegionManager.cs
index 43d48946..5e6273b8 100644
--- a/Ryujinx.HLE/HOS/Kernel/Memory/KMemoryRegionManager.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Memory/KMemoryRegionManager.cs
@@ -1,4 +1,4 @@
-using Ryujinx.HLE.HOS.Kernel.Common;
+using Ryujinx.Horizon.Common;
using System.Diagnostics;
namespace Ryujinx.HLE.HOS.Kernel.Memory
@@ -25,20 +25,20 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
_pageHeap.UpdateUsedSize();
}
- public KernelResult AllocatePages(out KPageList pageList, ulong pagesCount)
+ public Result AllocatePages(out KPageList pageList, ulong pagesCount)
{
if (pagesCount == 0)
{
pageList = new KPageList();
- return KernelResult.Success;
+ return Result.Success;
}
lock (_pageHeap)
{
- KernelResult result = AllocatePagesImpl(out pageList, pagesCount, false);
+ Result result = AllocatePagesImpl(out pageList, pagesCount, false);
- if (result == KernelResult.Success)
+ if (result == Result.Success)
{
foreach (var node in pageList)
{
@@ -71,7 +71,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
}
}
- private KernelResult AllocatePagesImpl(out KPageList pageList, ulong pagesCount, bool random)
+ private Result AllocatePagesImpl(out KPageList pageList, ulong pagesCount, bool random)
{
pageList = new KPageList();
@@ -95,9 +95,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
break;
}
- KernelResult result = pageList.AddRange(allocatedBlock, pagesPerAlloc);
+ Result result = pageList.AddRange(allocatedBlock, pagesPerAlloc);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
FreePages(pageList);
_pageHeap.Free(allocatedBlock, pagesPerAlloc);
@@ -116,7 +116,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
return KernelResult.OutOfMemory;
}
- return KernelResult.Success;
+ return Result.Success;
}
private ulong AllocatePagesContiguousImpl(ulong pagesCount, ulong alignPages, bool random)
diff --git a/Ryujinx.HLE/HOS/Kernel/Memory/KPageList.cs b/Ryujinx.HLE/HOS/Kernel/Memory/KPageList.cs
index 7f2f1ba6..3149faa9 100644
--- a/Ryujinx.HLE/HOS/Kernel/Memory/KPageList.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Memory/KPageList.cs
@@ -1,4 +1,4 @@
-using Ryujinx.HLE.HOS.Kernel.Common;
+using Ryujinx.Horizon.Common;
using System.Collections;
using System.Collections.Generic;
@@ -13,7 +13,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
Nodes = new LinkedList<KPageNode>();
}
- public KernelResult AddRange(ulong address, ulong pagesCount)
+ public Result AddRange(ulong address, ulong pagesCount)
{
if (pagesCount != 0)
{
@@ -33,7 +33,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
Nodes.AddLast(new KPageNode(address, pagesCount));
}
- return KernelResult.Success;
+ return Result.Success;
}
public ulong GetPagesCount()
diff --git a/Ryujinx.HLE/HOS/Kernel/Memory/KPageTable.cs b/Ryujinx.HLE/HOS/Kernel/Memory/KPageTable.cs
index 9d521231..9b7c99ba 100644
--- a/Ryujinx.HLE/HOS/Kernel/Memory/KPageTable.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Memory/KPageTable.cs
@@ -1,4 +1,4 @@
-using Ryujinx.HLE.HOS.Kernel.Common;
+using Ryujinx.Horizon.Common;
using Ryujinx.Memory;
using System;
using System.Diagnostics;
@@ -31,31 +31,31 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
}
/// <inheritdoc/>
- protected override KernelResult MapMemory(ulong src, ulong dst, ulong pagesCount, KMemoryPermission oldSrcPermission, KMemoryPermission newDstPermission)
+ protected override Result MapMemory(ulong src, ulong dst, ulong pagesCount, KMemoryPermission oldSrcPermission, KMemoryPermission newDstPermission)
{
KPageList pageList = new KPageList();
GetPhysicalRegions(src, pagesCount * PageSize, pageList);
- KernelResult result = Reprotect(src, pagesCount, KMemoryPermission.None);
+ Result result = Reprotect(src, pagesCount, KMemoryPermission.None);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
return result;
}
result = MapPages(dst, pageList, newDstPermission, false, 0);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
- KernelResult reprotectResult = Reprotect(src, pagesCount, oldSrcPermission);
- Debug.Assert(reprotectResult == KernelResult.Success);
+ Result reprotectResult = Reprotect(src, pagesCount, oldSrcPermission);
+ Debug.Assert(reprotectResult == Result.Success);
}
return result;
}
/// <inheritdoc/>
- protected override KernelResult UnmapMemory(ulong dst, ulong src, ulong pagesCount, KMemoryPermission oldDstPermission, KMemoryPermission newSrcPermission)
+ protected override Result UnmapMemory(ulong dst, ulong src, ulong pagesCount, KMemoryPermission oldDstPermission, KMemoryPermission newSrcPermission)
{
ulong size = pagesCount * PageSize;
@@ -70,26 +70,26 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
return KernelResult.InvalidMemRange;
}
- KernelResult result = Unmap(dst, pagesCount);
+ Result result = Unmap(dst, pagesCount);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
return result;
}
result = Reprotect(src, pagesCount, newSrcPermission);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
- KernelResult mapResult = MapPages(dst, dstPageList, oldDstPermission, false, 0);
- Debug.Assert(mapResult == KernelResult.Success);
+ Result mapResult = MapPages(dst, dstPageList, oldDstPermission, false, 0);
+ Debug.Assert(mapResult == Result.Success);
}
return result;
}
/// <inheritdoc/>
- protected override KernelResult MapPages(ulong dstVa, ulong pagesCount, ulong srcPa, KMemoryPermission permission, bool shouldFillPages, byte fillValue)
+ protected override Result MapPages(ulong dstVa, ulong pagesCount, ulong srcPa, KMemoryPermission permission, bool shouldFillPages, byte fillValue)
{
ulong size = pagesCount * PageSize;
@@ -107,11 +107,11 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
_cpuMemory.Fill(dstVa, size, fillValue);
}
- return KernelResult.Success;
+ return Result.Success;
}
/// <inheritdoc/>
- protected override KernelResult MapPages(ulong address, KPageList pageList, KMemoryPermission permission, bool shouldFillPages, byte fillValue)
+ protected override Result MapPages(ulong address, KPageList pageList, KMemoryPermission permission, bool shouldFillPages, byte fillValue)
{
using var scopedPageList = new KScopedPageList(Context.MemoryManager, pageList);
@@ -136,11 +136,11 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
scopedPageList.SignalSuccess();
- return KernelResult.Success;
+ return Result.Success;
}
/// <inheritdoc/>
- protected override KernelResult Unmap(ulong address, ulong pagesCount)
+ protected override Result Unmap(ulong address, ulong pagesCount)
{
KPageList pagesToClose = new KPageList();
@@ -159,21 +159,21 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
pagesToClose.DecrementPagesReferenceCount(Context.MemoryManager);
- return KernelResult.Success;
+ return Result.Success;
}
/// <inheritdoc/>
- protected override KernelResult Reprotect(ulong address, ulong pagesCount, KMemoryPermission permission)
+ protected override Result Reprotect(ulong address, ulong pagesCount, KMemoryPermission permission)
{
// TODO.
- return KernelResult.Success;
+ return Result.Success;
}
/// <inheritdoc/>
- protected override KernelResult ReprotectWithAttributes(ulong address, ulong pagesCount, KMemoryPermission permission)
+ protected override Result ReprotectWithAttributes(ulong address, ulong pagesCount, KMemoryPermission permission)
{
// TODO.
- return KernelResult.Success;
+ return Result.Success;
}
/// <inheritdoc/>
diff --git a/Ryujinx.HLE/HOS/Kernel/Memory/KPageTableBase.cs b/Ryujinx.HLE/HOS/Kernel/Memory/KPageTableBase.cs
index 2c94cba2..e19e22c8 100644
--- a/Ryujinx.HLE/HOS/Kernel/Memory/KPageTableBase.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Memory/KPageTableBase.cs
@@ -1,6 +1,7 @@
using Ryujinx.Common;
using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Process;
+using Ryujinx.Horizon.Common;
using System;
using System.Collections.Generic;
using System.Diagnostics;
@@ -88,7 +89,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
private static readonly int[] AddrSpaceSizes = new int[] { 32, 36, 32, 39 };
- public KernelResult InitializeForProcess(
+ public Result InitializeForProcess(
AddressSpaceType addrSpaceType,
bool aslrEnabled,
bool aslrDisabled,
@@ -107,7 +108,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
ulong addrSpaceBase = 0;
ulong addrSpaceSize = 1UL << AddrSpaceSizes[(int)addrSpaceType];
- KernelResult result = CreateUserAddressSpace(
+ Result result = CreateUserAddressSpace(
addrSpaceType,
aslrEnabled,
aslrDisabled,
@@ -118,7 +119,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
size,
slabManager);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
Context.ContextIdManager.PutId(_contextId);
}
@@ -134,7 +135,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
public ulong AslrOffset;
}
- private KernelResult CreateUserAddressSpace(
+ private Result CreateUserAddressSpace(
AddressSpaceType addrSpaceType,
bool aslrEnabled,
bool aslrDisabled,
@@ -342,7 +343,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
}
}
- public KernelResult MapPages(ulong address, KPageList pageList, MemoryState state, KMemoryPermission permission)
+ public Result MapPages(ulong address, KPageList pageList, MemoryState state, KMemoryPermission permission)
{
ulong pagesCount = pageList.GetPagesCount();
@@ -365,9 +366,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
return KernelResult.OutOfResource;
}
- KernelResult result = MapPages(address, pageList, permission);
+ Result result = MapPages(address, pageList, permission);
- if (result == KernelResult.Success)
+ if (result == Result.Success)
{
_blockManager.InsertBlock(address, pagesCount, state, permission);
}
@@ -376,7 +377,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
}
}
- public KernelResult UnmapPages(ulong address, KPageList pageList, MemoryState stateExpected)
+ public Result UnmapPages(ulong address, KPageList pageList, MemoryState stateExpected)
{
ulong pagesCount = pageList.GetPagesCount();
ulong size = pagesCount * PageSize;
@@ -430,9 +431,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
return KernelResult.OutOfResource;
}
- KernelResult result = Unmap(address, pagesCount);
+ Result result = Unmap(address, pagesCount);
- if (result == KernelResult.Success)
+ if (result == Result.Success)
{
_blockManager.InsertBlock(address, pagesCount, MemoryState.Unmapped);
}
@@ -446,19 +447,19 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
}
}
- public KernelResult MapNormalMemory(long address, long size, KMemoryPermission permission)
+ public Result MapNormalMemory(long address, long size, KMemoryPermission permission)
{
// TODO.
- return KernelResult.Success;
+ return Result.Success;
}
- public KernelResult MapIoMemory(long address, long size, KMemoryPermission permission)
+ public Result MapIoMemory(long address, long size, KMemoryPermission permission)
{
// TODO.
- return KernelResult.Success;
+ return Result.Success;
}
- public KernelResult MapPages(
+ public Result MapPages(
ulong pagesCount,
int alignment,
ulong srcPa,
@@ -497,7 +498,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
return KernelResult.OutOfResource;
}
- KernelResult result;
+ Result result;
if (paIsValid)
{
@@ -508,7 +509,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
result = AllocateAndMapPages(address, pagesCount, permission);
}
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
return result;
}
@@ -516,10 +517,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
_blockManager.InsertBlock(address, pagesCount, state, permission);
}
- return KernelResult.Success;
+ return Result.Success;
}
- public KernelResult MapPages(ulong address, ulong pagesCount, MemoryState state, KMemoryPermission permission)
+ public Result MapPages(ulong address, ulong pagesCount, MemoryState state, KMemoryPermission permission)
{
ulong size = pagesCount * PageSize;
@@ -540,9 +541,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
return KernelResult.OutOfResource;
}
- KernelResult result = AllocateAndMapPages(address, pagesCount, permission);
+ Result result = AllocateAndMapPages(address, pagesCount, permission);
- if (result == KernelResult.Success)
+ if (result == Result.Success)
{
_blockManager.InsertBlock(address, pagesCount, state, permission);
}
@@ -551,13 +552,13 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
}
}
- private KernelResult AllocateAndMapPages(ulong address, ulong pagesCount, KMemoryPermission permission)
+ private Result AllocateAndMapPages(ulong address, ulong pagesCount, KMemoryPermission permission)
{
KMemoryRegionManager region = GetMemoryRegionManager();
- KernelResult result = region.AllocatePages(out KPageList pageList, pagesCount);
+ Result result = region.AllocatePages(out KPageList pageList, pagesCount);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
return result;
}
@@ -567,7 +568,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
return MapPages(address, pageList, permission);
}
- public KernelResult MapProcessCodeMemory(ulong dst, ulong src, ulong size)
+ public Result MapProcessCodeMemory(ulong dst, ulong src, ulong size)
{
lock (_blockManager)
{
@@ -596,12 +597,12 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
ulong pagesCount = size / PageSize;
- KernelResult result = MapMemory(src, dst, pagesCount, permission, KMemoryPermission.None);
+ Result result = MapMemory(src, dst, pagesCount, permission, KMemoryPermission.None);
_blockManager.InsertBlock(src, pagesCount, state, KMemoryPermission.None, MemoryAttribute.Borrowed);
_blockManager.InsertBlock(dst, pagesCount, MemoryState.ModCodeStatic);
- return KernelResult.Success;
+ return Result.Success;
}
else
{
@@ -610,7 +611,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
}
}
- public KernelResult UnmapProcessCodeMemory(ulong dst, ulong src, ulong size)
+ public Result UnmapProcessCodeMemory(ulong dst, ulong src, ulong size)
{
lock (_blockManager)
{
@@ -656,9 +657,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
{
ulong pagesCount = size / PageSize;
- KernelResult result = Unmap(dst, pagesCount);
+ Result result = Unmap(dst, pagesCount);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
return result;
}
@@ -673,7 +674,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
_blockManager.InsertBlock(dst, pagesCount, MemoryState.Unmapped);
_blockManager.InsertBlock(src, pagesCount, MemoryState.Heap, KMemoryPermission.ReadAndWrite);
- return KernelResult.Success;
+ return Result.Success;
}
else
{
@@ -682,7 +683,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
}
}
- public KernelResult SetHeapSize(ulong size, out ulong address)
+ public Result SetHeapSize(ulong size, out ulong address)
{
address = 0;
@@ -712,7 +713,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
KMemoryRegionManager region = GetMemoryRegionManager();
- KernelResult result = region.AllocatePages(out KPageList pageList, pagesCount);
+ Result result = region.AllocatePages(out KPageList pageList, pagesCount);
using var _ = new OnScopeExit(() => pageList.DecrementPagesReferenceCount(Context.MemoryManager));
@@ -724,7 +725,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
}
}
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
CleanUpForError();
@@ -747,7 +748,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
result = MapPages(_currentHeapAddr, pageList, KMemoryPermission.ReadAndWrite, true, (byte)_heapFillValue);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
CleanUpForError();
@@ -786,9 +787,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
ulong pagesCount = sizeDelta / PageSize;
- KernelResult result = Unmap(freeAddr, pagesCount);
+ Result result = Unmap(freeAddr, pagesCount);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
return result;
}
@@ -803,10 +804,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
address = HeapRegionStart;
- return KernelResult.Success;
+ return Result.Success;
}
- public KernelResult SetMemoryPermission(ulong address, ulong size, KMemoryPermission permission)
+ public Result SetMemoryPermission(ulong address, ulong size, KMemoryPermission permission)
{
lock (_blockManager)
{
@@ -833,9 +834,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
ulong pagesCount = size / PageSize;
- KernelResult result = Reprotect(address, pagesCount, permission);
+ Result result = Reprotect(address, pagesCount, permission);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
return result;
}
@@ -843,7 +844,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
_blockManager.InsertBlock(address, pagesCount, oldState, permission);
}
- return KernelResult.Success;
+ return Result.Success;
}
else
{
@@ -865,17 +866,17 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
return _currentHeapAddr - HeapRegionStart;
}
- public KernelResult SetHeapCapacity(ulong capacity)
+ public Result SetHeapCapacity(ulong capacity)
{
lock (_blockManager)
{
_heapCapacity = capacity;
}
- return KernelResult.Success;
+ return Result.Success;
}
- public KernelResult SetMemoryAttribute(
+ public Result SetMemoryAttribute(
ulong address,
ulong size,
MemoryAttribute attributeMask,
@@ -909,7 +910,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
_blockManager.InsertBlock(address, pagesCount, state, permission, attribute);
- return KernelResult.Success;
+ return Result.Success;
}
else
{
@@ -942,7 +943,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
}
}
- public KernelResult Map(ulong dst, ulong src, ulong size)
+ public Result Map(ulong dst, ulong src, ulong size)
{
bool success;
@@ -973,9 +974,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
ulong pagesCount = size / PageSize;
- KernelResult result = MapMemory(src, dst, pagesCount, KMemoryPermission.ReadAndWrite, KMemoryPermission.ReadAndWrite);
+ Result result = MapMemory(src, dst, pagesCount, KMemoryPermission.ReadAndWrite, KMemoryPermission.ReadAndWrite);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
return result;
}
@@ -983,7 +984,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
_blockManager.InsertBlock(src, pagesCount, srcState, KMemoryPermission.None, MemoryAttribute.Borrowed);
_blockManager.InsertBlock(dst, pagesCount, MemoryState.Stack, KMemoryPermission.ReadAndWrite);
- return KernelResult.Success;
+ return Result.Success;
}
else
{
@@ -992,7 +993,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
}
}
- public KernelResult UnmapForKernel(ulong address, ulong pagesCount, MemoryState stateExpected)
+ public Result UnmapForKernel(ulong address, ulong pagesCount, MemoryState stateExpected)
{
ulong size = pagesCount * PageSize;
@@ -1017,14 +1018,14 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
return KernelResult.OutOfResource;
}
- KernelResult result = Unmap(address, pagesCount);
+ Result result = Unmap(address, pagesCount);
- if (result == KernelResult.Success)
+ if (result == Result.Success)
{
_blockManager.InsertBlock(address, pagesCount, MemoryState.Unmapped);
}
- return KernelResult.Success;
+ return Result.Success;
}
else
{
@@ -1033,7 +1034,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
}
}
- public KernelResult Unmap(ulong dst, ulong src, ulong size)
+ public Result Unmap(ulong dst, ulong src, ulong size)
{
bool success;
@@ -1076,9 +1077,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
ulong pagesCount = size / PageSize;
- KernelResult result = UnmapMemory(dst, src, pagesCount, dstPermission, KMemoryPermission.ReadAndWrite);
+ Result result = UnmapMemory(dst, src, pagesCount, dstPermission, KMemoryPermission.ReadAndWrite);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
return result;
}
@@ -1086,7 +1087,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
_blockManager.InsertBlock(src, pagesCount, srcState, KMemoryPermission.ReadAndWrite);
_blockManager.InsertBlock(dst, pagesCount, MemoryState.Unmapped);
- return KernelResult.Success;
+ return Result.Success;
}
else
{
@@ -1095,7 +1096,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
}
}
- public KernelResult UnmapProcessMemory(ulong dst, ulong size, KPageTableBase srcPageTable, ulong src)
+ public Result UnmapProcessMemory(ulong dst, ulong size, KPageTableBase srcPageTable, ulong src)
{
lock (_blockManager)
{
@@ -1153,20 +1154,20 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
ulong pagesCount = size / PageSize;
- KernelResult result = Unmap(dst, pagesCount);
+ Result result = Unmap(dst, pagesCount);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
return result;
}
_blockManager.InsertBlock(dst, pagesCount, MemoryState.Unmapped);
- return KernelResult.Success;
+ return Result.Success;
}
}
- public KernelResult SetProcessMemoryPermission(ulong address, ulong size, KMemoryPermission permission)
+ public Result SetProcessMemoryPermission(ulong address, ulong size, KMemoryPermission permission)
{
lock (_blockManager)
{
@@ -1213,7 +1214,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
ulong pagesCount = size / PageSize;
- KernelResult result;
+ Result result;
if ((oldPermission & KMemoryPermission.Execute) != 0)
{
@@ -1224,7 +1225,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
result = Reprotect(address, pagesCount, permission);
}
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
return result;
}
@@ -1232,7 +1233,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
_blockManager.InsertBlock(address, pagesCount, newState, permission);
}
- return KernelResult.Success;
+ return Result.Success;
}
else
{
@@ -1241,7 +1242,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
}
}
- public KernelResult MapPhysicalMemory(ulong address, ulong size)
+ public Result MapPhysicalMemory(ulong address, ulong size)
{
ulong endAddr = address + size;
@@ -1259,7 +1260,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
if (mappedSize == size)
{
- return KernelResult.Success;
+ return Result.Success;
}
ulong remainingSize = size - mappedSize;
@@ -1276,7 +1277,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
KMemoryRegionManager region = GetMemoryRegionManager();
- KernelResult result = region.AllocatePages(out KPageList pageList, remainingPages);
+ Result result = region.AllocatePages(out KPageList pageList, remainingPages);
using var _ = new OnScopeExit(() => pageList.DecrementPagesReferenceCount(Context.MemoryManager));
@@ -1285,7 +1286,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
currentProcess.ResourceLimit?.Release(LimitableResource.Memory, remainingSize);
}
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
CleanUpForError();
@@ -1357,10 +1358,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
MemoryAttribute.None);
}
- return KernelResult.Success;
+ return Result.Success;
}
- public KernelResult UnmapPhysicalMemory(ulong address, ulong size)
+ public Result UnmapPhysicalMemory(ulong address, ulong size)
{
ulong endAddr = address + size;
@@ -1391,7 +1392,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
if (heapMappedSize == 0)
{
- return KernelResult.Success;
+ return Result.Success;
}
if (!_slabManager.CanAllocate(MaxBlocksNeededForInsertion))
@@ -1400,7 +1401,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
}
// Try to unmap all the heap mapped memory inside range.
- KernelResult result = KernelResult.Success;
+ Result result = Result.Success;
foreach (KMemoryInfo info in IterateOverRange(address, endAddr))
{
@@ -1416,11 +1417,11 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
// The kernel would attempt to remap if this fails, but we don't because:
// - The implementation may not support remapping if memory aliasing is not supported on the platform.
// - Unmap can't ever fail here anyway.
- Debug.Assert(result == KernelResult.Success);
+ Debug.Assert(result == Result.Success);
}
}
- if (result == KernelResult.Success)
+ if (result == Result.Success)
{
PhysicalMemoryUsage -= heapMappedSize;
@@ -1437,7 +1438,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
}
}
- public KernelResult CopyDataToCurrentProcess(
+ public Result CopyDataToCurrentProcess(
ulong dst,
ulong size,
ulong src,
@@ -1460,7 +1461,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
toServer: true);
}
- public KernelResult CopyDataFromCurrentProcess(
+ public Result CopyDataFromCurrentProcess(
ulong dst,
ulong size,
MemoryState stateMask,
@@ -1483,7 +1484,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
toServer: false);
}
- private KernelResult CopyDataFromOrToCurrentProcess(
+ private Result CopyDataFromOrToCurrentProcess(
ulong size,
ulong clientAddress,
ulong serverAddress,
@@ -1543,7 +1544,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
size -= copySize;
}
- return KernelResult.Success;
+ return Result.Success;
}
else
{
@@ -1552,7 +1553,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
}
}
- public KernelResult MapBufferFromClientProcess(
+ public Result MapBufferFromClientProcess(
ulong size,
ulong src,
KPageTableBase srcPageTable,
@@ -1567,14 +1568,14 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
{
lock (_blockManager)
{
- KernelResult result = srcPageTable.ReprotectClientProcess(
+ Result result = srcPageTable.ReprotectClientProcess(
src,
size,
permission,
state,
out int blocksNeeded);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
return result;
}
@@ -1590,7 +1591,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
result = MapPagesFromClientProcess(size, src, permission, state, srcPageTable, send, out ulong va);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
if (srcMapEndAddr > srcMapAddress)
{
@@ -1613,10 +1614,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
}
}
- return KernelResult.Success;
+ return Result.Success;
}
- private KernelResult ReprotectClientProcess(
+ private Result ReprotectClientProcess(
ulong address,
ulong size,
KMemoryPermission permission,
@@ -1689,8 +1690,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
ulong blockPagesCount = blockSize / PageSize;
- KernelResult reprotectResult = Reprotect(blockAddress, blockPagesCount, info.Permission);
- Debug.Assert(reprotectResult == KernelResult.Success);
+ Result reprotectResult = Reprotect(blockAddress, blockPagesCount, info.Permission);
+ Debug.Assert(reprotectResult == Result.Success);
}
}
}
@@ -1699,7 +1700,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
SignalMemoryTracking(addressTruncated, endAddrRounded - addressTruncated, false);
// Reprotect the aligned pages range on the client to make them inaccessible from the client process.
- KernelResult result;
+ Result result;
if (addressRounded < endAddrTruncated)
{
@@ -1736,7 +1737,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
{
result = Reprotect(blockAddress, blockPagesCount, permissionMask);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
CleanUpForError();
@@ -1748,10 +1749,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
}
}
- return KernelResult.Success;
+ return Result.Success;
}
- private KernelResult MapPagesFromClientProcess(
+ private Result MapPagesFromClientProcess(
ulong size,
ulong address,
KMemoryPermission permission,
@@ -1877,9 +1878,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
Context.Memory.Fill(GetDramAddressFromPa(firstPageFillAddress), unusedSizeAfter, (byte)_ipcFillValue);
}
- KernelResult result = MapPages(currentVa, 1, dstFirstPagePa, permission);
+ Result result = MapPages(currentVa, 1, dstFirstPagePa, permission);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
CleanUpForError();
@@ -1896,9 +1897,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
KPageList pageList = new KPageList();
srcPageTable.GetPhysicalRegions(addressRounded, alignedSize, pageList);
- KernelResult result = MapPages(currentVa, pageList, permission);
+ Result result = MapPages(currentVa, pageList, permission);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
CleanUpForError();
@@ -1931,9 +1932,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
Context.Memory.Fill(GetDramAddressFromPa(lastPageFillAddr), unusedSizeAfter, (byte)_ipcFillValue);
- KernelResult result = MapPages(currentVa, 1, dstLastPagePa, permission);
+ Result result = MapPages(currentVa, 1, dstLastPagePa, permission);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
CleanUpForError();
@@ -1945,10 +1946,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
dst = va + (address - addressTruncated);
- return KernelResult.Success;
+ return Result.Success;
}
- public KernelResult UnmapNoAttributeIfStateEquals(ulong address, ulong size, MemoryState state)
+ public Result UnmapNoAttributeIfStateEquals(ulong address, ulong size, MemoryState state)
{
if (AddrSpaceStart > address)
{
@@ -1990,9 +1991,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
ulong pagesCount = (endAddrRounded - addressTruncated) / PageSize;
- KernelResult result = Unmap(addressTruncated, pagesCount);
+ Result result = Unmap(addressTruncated, pagesCount);
- if (result == KernelResult.Success)
+ if (result == Result.Success)
{
_blockManager.InsertBlock(addressTruncated, pagesCount, MemoryState.Unmapped);
}
@@ -2006,7 +2007,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
}
}
- public KernelResult UnmapIpcRestorePermission(ulong address, ulong size, MemoryState state)
+ public Result UnmapIpcRestorePermission(ulong address, ulong size, MemoryState state)
{
ulong endAddr = address + size;
@@ -2019,7 +2020,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
if (pagesCount == 0)
{
- return KernelResult.Success;
+ return Result.Success;
}
MemoryState stateMask;
@@ -2069,9 +2070,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
ulong blockPagesCount = blockSize / PageSize;
- KernelResult result = Reprotect(blockAddress, blockPagesCount, info.SourcePermission);
+ Result result = Reprotect(blockAddress, blockPagesCount, info.SourcePermission);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
return result;
}
@@ -2080,7 +2081,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
_blockManager.InsertBlock(addressRounded, pagesCount, RestoreIpcMappingPermissions);
- return KernelResult.Success;
+ return Result.Success;
}
}
@@ -2094,7 +2095,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
block.RestoreIpcMappingPermission();
}
- public KernelResult GetPagesIfStateEquals(
+ public Result GetPagesIfStateEquals(
ulong address,
ulong size,
MemoryState stateMask,
@@ -2128,7 +2129,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
{
GetPhysicalRegions(address, size, pageList);
- return KernelResult.Success;
+ return Result.Success;
}
else
{
@@ -2137,7 +2138,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
}
}
- public KernelResult BorrowIpcBuffer(ulong address, ulong size)
+ public Result BorrowIpcBuffer(ulong address, ulong size)
{
return SetAttributesAndChangePermission(
address,
@@ -2152,7 +2153,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
MemoryAttribute.Borrowed);
}
- public KernelResult BorrowTransferMemory(KPageList pageList, ulong address, ulong size, KMemoryPermission permission)
+ public Result BorrowTransferMemory(KPageList pageList, ulong address, ulong size, KMemoryPermission permission)
{
return SetAttributesAndChangePermission(
address,
@@ -2168,7 +2169,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
pageList);
}
- public KernelResult BorrowCodeMemory(KPageList pageList, ulong address, ulong size)
+ public Result BorrowCodeMemory(KPageList pageList, ulong address, ulong size)
{
return SetAttributesAndChangePermission(
address,
@@ -2184,7 +2185,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
pageList);
}
- private KernelResult SetAttributesAndChangePermission(
+ private Result SetAttributesAndChangePermission(
ulong address,
ulong size,
MemoryState stateMask,
@@ -2237,9 +2238,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
if (newPermission != oldPermission)
{
- KernelResult result = Reprotect(address, pagesCount, newPermission);
+ Result result = Reprotect(address, pagesCount, newPermission);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
return result;
}
@@ -2249,7 +2250,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
_blockManager.InsertBlock(address, pagesCount, oldState, newPermission, newAttribute);
- return KernelResult.Success;
+ return Result.Success;
}
else
{
@@ -2258,7 +2259,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
}
}
- public KernelResult UnborrowIpcBuffer(ulong address, ulong size)
+ public Result UnborrowIpcBuffer(ulong address, ulong size)
{
return ClearAttributesAndChangePermission(
address,
@@ -2273,7 +2274,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
MemoryAttribute.Borrowed);
}
- public KernelResult UnborrowTransferMemory(ulong address, ulong size, KPageList pageList)
+ public Result UnborrowTransferMemory(ulong address, ulong size, KPageList pageList)
{
return ClearAttributesAndChangePermission(
address,
@@ -2289,7 +2290,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
pageList);
}
- public KernelResult UnborrowCodeMemory(ulong address, ulong size, KPageList pageList)
+ public Result UnborrowCodeMemory(ulong address, ulong size, KPageList pageList)
{
return ClearAttributesAndChangePermission(
address,
@@ -2305,7 +2306,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
pageList);
}
- private KernelResult ClearAttributesAndChangePermission(
+ private Result ClearAttributesAndChangePermission(
ulong address,
ulong size,
MemoryState stateMask,
@@ -2365,9 +2366,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
if (newPermission != oldPermission)
{
- KernelResult result = Reprotect(address, pagesCount, newPermission);
+ Result result = Reprotect(address, pagesCount, newPermission);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
return result;
}
@@ -2377,7 +2378,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
_blockManager.InsertBlock(address, pagesCount, oldState, newPermission, newAttribute);
- return KernelResult.Success;
+ return Result.Success;
}
else
{
@@ -2915,7 +2916,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
/// <param name="oldSrcPermission">Current protection of the source memory region</param>
/// <param name="newDstPermission">Desired protection for the destination memory region</param>
/// <returns>Result of the mapping operation</returns>
- protected abstract KernelResult MapMemory(ulong src, ulong dst, ulong pagesCount, KMemoryPermission oldSrcPermission, KMemoryPermission newDstPermission);
+ protected abstract Result MapMemory(ulong src, ulong dst, ulong pagesCount, KMemoryPermission oldSrcPermission, KMemoryPermission newDstPermission);
/// <summary>
/// Unmaps a region of memory that was previously mapped with <see cref="MapMemory"/>.
@@ -2926,7 +2927,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
/// <param name="oldDstPermission">Current protection of the destination memory region</param>
/// <param name="newSrcPermission">Desired protection of the source memory region</param>
/// <returns>Result of the unmapping operation</returns>
- protected abstract KernelResult UnmapMemory(ulong dst, ulong src, ulong pagesCount, KMemoryPermission oldDstPermission, KMemoryPermission newSrcPermission);
+ protected abstract Result UnmapMemory(ulong dst, ulong src, ulong pagesCount, KMemoryPermission oldDstPermission, KMemoryPermission newSrcPermission);
/// <summary>
/// Maps a region of memory into the specified physical memory region.
@@ -2938,7 +2939,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
/// <param name="shouldFillPages">Indicate if the pages should be filled with the <paramref name="fillValue"/> value</param>
/// <param name="fillValue">The value used to fill pages when <paramref name="shouldFillPages"/> is set to true</param>
/// <returns>Result of the mapping operation</returns>
- protected abstract KernelResult MapPages(ulong dstVa, ulong pagesCount, ulong srcPa, KMemoryPermission permission, bool shouldFillPages = false, byte fillValue = 0);
+ protected abstract Result MapPages(ulong dstVa, ulong pagesCount, ulong srcPa, KMemoryPermission permission, bool shouldFillPages = false, byte fillValue = 0);
/// <summary>
/// Maps a region of memory into the specified physical memory region.
@@ -2949,7 +2950,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
/// <param name="shouldFillPages">Indicate if the pages should be filled with the <paramref name="fillValue"/> value</param>
/// <param name="fillValue">The value used to fill pages when <paramref name="shouldFillPages"/> is set to true</param>
/// <returns>Result of the mapping operation</returns>
- protected abstract KernelResult MapPages(ulong address, KPageList pageList, KMemoryPermission permission, bool shouldFillPages = false, byte fillValue = 0);
+ protected abstract Result MapPages(ulong address, KPageList pageList, KMemoryPermission permission, bool shouldFillPages = false, byte fillValue = 0);
/// <summary>
/// Unmaps a region of memory that was previously mapped with one of the page mapping methods.
@@ -2957,7 +2958,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
/// <param name="address">Virtual address of the region to unmap</param>
/// <param name="pagesCount">Number of pages to unmap</param>
/// <returns>Result of the unmapping operation</returns>
- protected abstract KernelResult Unmap(ulong address, ulong pagesCount);
+ protected abstract Result Unmap(ulong address, ulong pagesCount);
/// <summary>
/// Changes the permissions of a given virtual memory region.
@@ -2966,7 +2967,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
/// <param name="pagesCount">Number of pages to have their permissions changed</param>
/// <param name="permission">New permission</param>
/// <returns>Result of the permission change operation</returns>
- protected abstract KernelResult Reprotect(ulong address, ulong pagesCount, KMemoryPermission permission);
+ protected abstract Result Reprotect(ulong address, ulong pagesCount, KMemoryPermission permission);
/// <summary>
/// Changes the permissions of a given virtual memory region.
@@ -2975,7 +2976,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
/// <param name="pagesCount">Number of pages to have their permissions changed</param>
/// <param name="permission">New permission</param>
/// <returns>Result of the permission change operation</returns>
- protected abstract KernelResult ReprotectWithAttributes(ulong address, ulong pagesCount, KMemoryPermission permission);
+ protected abstract Result ReprotectWithAttributes(ulong address, ulong pagesCount, KMemoryPermission permission);
/// <summary>
/// Alerts the memory tracking that a given region has been read from or written to.
diff --git a/Ryujinx.HLE/HOS/Kernel/Memory/KSharedMemory.cs b/Ryujinx.HLE/HOS/Kernel/Memory/KSharedMemory.cs
index 3af62750..2dbaf3cd 100644
--- a/Ryujinx.HLE/HOS/Kernel/Memory/KSharedMemory.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Memory/KSharedMemory.cs
@@ -1,6 +1,7 @@
using Ryujinx.Common;
using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Process;
+using Ryujinx.Horizon.Common;
namespace Ryujinx.HLE.HOS.Kernel.Memory
{
@@ -26,7 +27,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
_userPermission = userPermission;
}
- public KernelResult MapIntoProcess(
+ public Result MapIntoProcess(
KPageTableBase memoryManager,
ulong address,
ulong size,
@@ -50,7 +51,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
return memoryManager.MapPages(address, _pageList, MemoryState.SharedMemory, permission);
}
- public KernelResult UnmapFromProcess(KPageTableBase memoryManager, ulong address, ulong size, KProcess process)
+ public Result UnmapFromProcess(KPageTableBase memoryManager, ulong address, ulong size, KProcess process)
{
if (_pageList.GetPagesCount() != BitUtils.DivRoundUp<ulong>(size, KPageTableBase.PageSize))
{
diff --git a/Ryujinx.HLE/HOS/Kernel/Memory/KTransferMemory.cs b/Ryujinx.HLE/HOS/Kernel/Memory/KTransferMemory.cs
index 2888efb8..b2449598 100644
--- a/Ryujinx.HLE/HOS/Kernel/Memory/KTransferMemory.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Memory/KTransferMemory.cs
@@ -1,6 +1,7 @@
using Ryujinx.Common;
using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Process;
+using Ryujinx.Horizon.Common;
using System;
namespace Ryujinx.HLE.HOS.Kernel.Memory
@@ -36,15 +37,15 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
_isMapped = false;
}
- public KernelResult Initialize(ulong address, ulong size, KMemoryPermission permission)
+ public Result Initialize(ulong address, ulong size, KMemoryPermission permission)
{
KProcess creator = KernelStatic.GetCurrentProcess();
_creator = creator;
- KernelResult result = creator.MemoryManager.BorrowTransferMemory(_pageList, address, size, permission);
+ Result result = creator.MemoryManager.BorrowTransferMemory(_pageList, address, size, permission);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
return result;
}
@@ -60,7 +61,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
return result;
}
- public KernelResult MapIntoProcess(
+ public Result MapIntoProcess(
KPageTableBase memoryManager,
ulong address,
ulong size,
@@ -79,9 +80,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
MemoryState state = Permission == KMemoryPermission.None ? MemoryState.TransferMemoryIsolated : MemoryState.TransferMemory;
- KernelResult result = memoryManager.MapPages(address, _pageList, state, KMemoryPermission.ReadAndWrite);
+ Result result = memoryManager.MapPages(address, _pageList, state, KMemoryPermission.ReadAndWrite);
- if (result == KernelResult.Success)
+ if (result == Result.Success)
{
_isMapped = true;
}
@@ -89,7 +90,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
return result;
}
- public KernelResult UnmapFromProcess(
+ public Result UnmapFromProcess(
KPageTableBase memoryManager,
ulong address,
ulong size,
@@ -102,9 +103,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
MemoryState state = Permission == KMemoryPermission.None ? MemoryState.TransferMemoryIsolated : MemoryState.TransferMemory;
- KernelResult result = memoryManager.UnmapPages(address, _pageList, state);
+ Result result = memoryManager.UnmapPages(address, _pageList, state);
- if (result == KernelResult.Success)
+ if (result == Result.Success)
{
_isMapped = false;
}
@@ -116,7 +117,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
{
if (_hasBeenInitialized)
{
- if (!_isMapped && _creator.MemoryManager.UnborrowTransferMemory(Address, Size, _pageList) != KernelResult.Success)
+ if (!_isMapped && _creator.MemoryManager.UnborrowTransferMemory(Address, Size, _pageList) != Result.Success)
{
throw new InvalidOperationException("Unexpected failure restoring transfer memory attributes.");
}
diff --git a/Ryujinx.HLE/HOS/Kernel/Process/KHandleTable.cs b/Ryujinx.HLE/HOS/Kernel/Process/KHandleTable.cs
index bcbb3b03..c15ebef5 100644
--- a/Ryujinx.HLE/HOS/Kernel/Process/KHandleTable.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Process/KHandleTable.cs
@@ -1,5 +1,6 @@
using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Threading;
+using Ryujinx.Horizon.Common;
using System;
namespace Ryujinx.HLE.HOS.Kernel.Process
@@ -27,7 +28,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
_context = context;
}
- public KernelResult Initialize(int size)
+ public Result Initialize(int size)
{
if ((uint)size > 1024)
{
@@ -62,10 +63,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
_nextFreeEntry = _tableHead;
- return KernelResult.Success;
+ return Result.Success;
}
- public KernelResult GenerateHandle(KAutoObject obj, out int handle)
+ public Result GenerateHandle(KAutoObject obj, out int handle)
{
handle = 0;
@@ -99,10 +100,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
}
}
- return KernelResult.Success;
+ return Result.Success;
}
- public KernelResult ReserveHandle(out int handle)
+ public Result ReserveHandle(out int handle)
{
handle = 0;
@@ -131,7 +132,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
}
}
- return KernelResult.Success;
+ return Result.Success;
}
public void CancelHandleReservation(int handle)
diff --git a/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs b/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs
index 6a2d45ea..8d9cd242 100644
--- a/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs
@@ -5,6 +5,7 @@ using Ryujinx.HLE.Exceptions;
using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Memory;
using Ryujinx.HLE.HOS.Kernel.Threading;
+using Ryujinx.Horizon.Common;
using Ryujinx.Memory;
using System;
using System.Collections.Generic;
@@ -116,7 +117,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
Debugger = new HleProcessDebugger(this);
}
- public KernelResult InitializeKip(
+ public Result InitializeKip(
ProcessCreationInfo creationInfo,
ReadOnlySpan<int> capabilities,
KPageList pageList,
@@ -151,7 +152,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
? KernelContext.LargeMemoryBlockSlabManager
: KernelContext.SmallMemoryBlockSlabManager;
- KernelResult result = MemoryManager.InitializeForProcess(
+ Result result = MemoryManager.InitializeForProcess(
addrSpaceType,
aslrEnabled,
!aslrEnabled,
@@ -160,7 +161,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
codeSize,
slabManager);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
return result;
}
@@ -172,14 +173,14 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
result = MemoryManager.MapPages(codeAddress, pageList, MemoryState.CodeStatic, KMemoryPermission.None);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
return result;
}
result = Capabilities.InitializeForKernel(capabilities, MemoryManager);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
return result;
}
@@ -187,7 +188,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
return ParseProcessInfo(creationInfo);
}
- public KernelResult Initialize(
+ public Result Initialize(
ProcessCreationInfo creationInfo,
ReadOnlySpan<int> capabilities,
KResourceLimit resourceLimit,
@@ -255,7 +256,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
ulong codeSize = codePagesCount * KPageTableBase.PageSize;
- KernelResult result = MemoryManager.InitializeForProcess(
+ Result result = MemoryManager.InitializeForProcess(
addrSpaceType,
aslrEnabled,
!aslrEnabled,
@@ -264,7 +265,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
codeSize,
slabManager);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
CleanUpForError();
@@ -284,7 +285,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
MemoryState.CodeStatic,
KMemoryPermission.None);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
CleanUpForError();
@@ -293,7 +294,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
result = Capabilities.InitializeForUser(capabilities, MemoryManager);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
CleanUpForError();
@@ -302,7 +303,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
result = ParseProcessInfo(creationInfo);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
CleanUpForError();
}
@@ -310,7 +311,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
return result;
}
- private KernelResult ParseProcessInfo(ProcessCreationInfo creationInfo)
+ private Result ParseProcessInfo(ProcessCreationInfo creationInfo)
{
// Ensure that the current kernel version is equal or above to the minimum required.
uint requiredKernelVersionMajor = (uint)Capabilities.KernelReleaseVersion >> 19;
@@ -334,9 +335,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
}
}
- KernelResult result = AllocateThreadLocalStorage(out ulong userExceptionContextAddress);
+ Result result = AllocateThreadLocalStorage(out ulong userExceptionContextAddress);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
return result;
}
@@ -378,14 +379,14 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
GenerateRandomEntropy();
- return KernelResult.Success;
+ return Result.Success;
}
- public KernelResult AllocateThreadLocalStorage(out ulong address)
+ public Result AllocateThreadLocalStorage(out ulong address)
{
KernelContext.CriticalSection.Enter();
- KernelResult result;
+ Result result;
if (_freeTlsPages.Count > 0)
{
@@ -404,14 +405,14 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
_fullTlsPages.Add(pageInfo.PageVirtualAddress, pageInfo);
}
- result = KernelResult.Success;
+ result = Result.Success;
}
else
{
// Otherwise, we need to create a new one.
result = AllocateTlsPage(out KTlsPageInfo pageInfo);
- if (result == KernelResult.Success)
+ if (result == Result.Success)
{
if (!pageInfo.TryGetFreePage(out address))
{
@@ -431,7 +432,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
return result;
}
- private KernelResult AllocateTlsPage(out KTlsPageInfo pageInfo)
+ private Result AllocateTlsPage(out KTlsPageInfo pageInfo)
{
pageInfo = default;
@@ -445,7 +446,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
ulong regionPagesCount = regionSize / KPageTableBase.PageSize;
- KernelResult result = MemoryManager.MapPages(
+ Result result = MemoryManager.MapPages(
1,
KPageTableBase.PageSize,
tlsPagePa,
@@ -456,7 +457,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
KMemoryPermission.ReadAndWrite,
out ulong tlsPageVa);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
KernelContext.UserSlabHeapPages.Free(tlsPagePa);
}
@@ -470,13 +471,13 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
return result;
}
- public KernelResult FreeThreadLocalStorage(ulong tlsSlotAddr)
+ public Result FreeThreadLocalStorage(ulong tlsSlotAddr)
{
ulong tlsPageAddr = BitUtils.AlignDown<ulong>(tlsSlotAddr, KPageTableBase.PageSize);
KernelContext.CriticalSection.Enter();
- KernelResult result = KernelResult.Success;
+ Result result = Result.Success;
KTlsPageInfo pageInfo;
@@ -506,7 +507,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
FreeTlsPage(pageInfo);
- return KernelResult.Success;
+ return Result.Success;
}
}
@@ -515,11 +516,11 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
return result;
}
- private KernelResult FreeTlsPage(KTlsPageInfo pageInfo)
+ private Result FreeTlsPage(KTlsPageInfo pageInfo)
{
- KernelResult result = MemoryManager.UnmapForKernel(pageInfo.PageVirtualAddress, 1, MemoryState.ThreadLocal);
+ Result result = MemoryManager.UnmapForKernel(pageInfo.PageVirtualAddress, 1, MemoryState.ThreadLocal);
- if (result == KernelResult.Success)
+ if (result == Result.Success)
{
KernelContext.UserSlabHeapPages.Free(pageInfo.PagePhysicalAddress);
}
@@ -532,7 +533,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
// TODO.
}
- public KernelResult Start(int mainThreadPriority, ulong stackSize)
+ public Result Start(int mainThreadPriority, ulong stackSize)
{
lock (_processLock)
{
@@ -580,7 +581,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
}
}
- KernelResult result;
+ Result result;
KThread mainThread = null;
@@ -627,7 +628,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
KMemoryPermission.ReadAndWrite,
out ulong stackBottom);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
CleanUpForError();
@@ -643,7 +644,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
result = MemoryManager.SetHeapCapacity(heapCapacity);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
CleanUpForError();
@@ -654,7 +655,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
result = HandleTable.Initialize(Capabilities.HandleTableSize);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
CleanUpForError();
@@ -673,7 +674,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
ThreadType.User,
_customThreadStart);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
CleanUpForError();
@@ -682,7 +683,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
result = HandleTable.GenerateHandle(mainThread, out int mainThreadHandle);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
CleanUpForError();
@@ -700,14 +701,14 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
result = mainThread.Start();
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
SetState(oldState);
CleanUpForError();
}
- if (result == KernelResult.Success)
+ if (result == Result.Success)
{
mainThread.IncrementReferenceCount();
}
@@ -729,7 +730,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
}
}
- public KernelResult InitializeThread(
+ public Result InitializeThread(
KThread thread,
ulong entrypoint,
ulong argsPtr,
@@ -888,9 +889,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
return _signaled;
}
- public KernelResult Terminate()
+ public Result Terminate()
{
- KernelResult result;
+ Result result;
bool shallTerminate = false;
@@ -910,7 +911,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
shallTerminate = true;
}
- result = KernelResult.Success;
+ result = Result.Success;
}
else
{
@@ -1044,9 +1045,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
KernelContext.CriticalSection.Leave();
}
- public KernelResult ClearIfNotExited()
+ public Result ClearIfNotExited()
{
- KernelResult result;
+ Result result;
KernelContext.CriticalSection.Enter();
@@ -1056,7 +1057,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
{
_signaled = false;
- result = KernelResult.Success;
+ result = Result.Success;
}
else
{
@@ -1107,7 +1108,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
protected override void Destroy() => Context.Dispose();
- public KernelResult SetActivity(bool pause)
+ public Result SetActivity(bool pause)
{
KernelContext.CriticalSection.Enter();
@@ -1154,7 +1155,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
KernelContext.CriticalSection.Leave();
- return KernelResult.Success;
+ return Result.Success;
}
KernelContext.CriticalSection.Leave();
diff --git a/Ryujinx.HLE/HOS/Kernel/Process/KProcessCapabilities.cs b/Ryujinx.HLE/HOS/Kernel/Process/KProcessCapabilities.cs
index a08c4b26..ef55a165 100644
--- a/Ryujinx.HLE/HOS/Kernel/Process/KProcessCapabilities.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Process/KProcessCapabilities.cs
@@ -1,6 +1,7 @@
using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Memory;
using Ryujinx.HLE.HOS.Kernel.Threading;
+using Ryujinx.Horizon.Common;
using System;
using System.Numerics;
@@ -25,7 +26,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
IrqAccessMask = new byte[0x80];
}
- public KernelResult InitializeForKernel(ReadOnlySpan<int> capabilities, KPageTableBase memoryManager)
+ public Result InitializeForKernel(ReadOnlySpan<int> capabilities, KPageTableBase memoryManager)
{
AllowedCpuCoresMask = 0xf;
AllowedThreadPriosMask = ulong.MaxValue;
@@ -35,12 +36,12 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
return Parse(capabilities, memoryManager);
}
- public KernelResult InitializeForUser(ReadOnlySpan<int> capabilities, KPageTableBase memoryManager)
+ public Result InitializeForUser(ReadOnlySpan<int> capabilities, KPageTableBase memoryManager)
{
return Parse(capabilities, memoryManager);
}
- private KernelResult Parse(ReadOnlySpan<int> capabilities, KPageTableBase memoryManager)
+ private Result Parse(ReadOnlySpan<int> capabilities, KPageTableBase memoryManager)
{
int mask0 = 0;
int mask1 = 0;
@@ -51,9 +52,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
if (((cap + 1) & ~cap) != 0x40)
{
- KernelResult result = ParseCapability(cap, ref mask0, ref mask1, memoryManager);
+ Result result = ParseCapability(cap, ref mask0, ref mask1, memoryManager);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
return result;
}
@@ -96,7 +97,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
? KMemoryPermission.Read
: KMemoryPermission.ReadAndWrite;
- KernelResult result;
+ Result result;
if ((cap >> 31) != 0)
{
@@ -107,17 +108,17 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
result = memoryManager.MapIoMemory(address, size, perm);
}
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
return result;
}
}
}
- return KernelResult.Success;
+ return Result.Success;
}
- private KernelResult ParseCapability(int cap, ref int mask0, ref int mask1, KPageTableBase memoryManager)
+ private Result ParseCapability(int cap, ref int mask0, ref int mask1, KPageTableBase memoryManager)
{
int code = (cap + 1) & ~cap;
@@ -127,7 +128,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
}
else if (code == 0)
{
- return KernelResult.Success;
+ return Result.Success;
}
int codeMask = 1 << (32 - BitOperations.LeadingZeroCount((uint)code + 1));
@@ -300,7 +301,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
default: return KernelResult.InvalidCapability;
}
- return KernelResult.Success;
+ return Result.Success;
}
private static ulong GetMaskFromMinMax(int min, int max)
diff --git a/Ryujinx.HLE/HOS/Kernel/Process/ProcessExecutionContext.cs b/Ryujinx.HLE/HOS/Kernel/Process/ProcessExecutionContext.cs
index a0841252..77fcdf33 100644
--- a/Ryujinx.HLE/HOS/Kernel/Process/ProcessExecutionContext.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Process/ProcessExecutionContext.cs
@@ -7,23 +7,25 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
{
public ulong Pc => 0UL;
- public ulong CntfrqEl0 { get => 0; set { } }
+ public ulong CntfrqEl0 { get; set; }
public ulong CntpctEl0 => 0UL;
- public long TpidrEl0 { get => 0; set { } }
- public long TpidrroEl0 { get => 0; set { } }
+ public long TpidrEl0 { get; set; }
+ public long TpidrroEl0 { get; set; }
- public uint Pstate { get => 0; set { } }
+ public uint Pstate { get; set; }
- public uint Fpcr { get => 0; set { } }
- public uint Fpsr { get => 0; set { } }
+ public uint Fpcr { get; set; }
+ public uint Fpsr { get; set; }
public bool IsAarch32 { get => false; set { } }
public bool Running { get; private set; } = true;
- public ulong GetX(int index) => 0UL;
- public void SetX(int index, ulong value) { }
+ private readonly ulong[] _x = new ulong[32];
+
+ public ulong GetX(int index) => _x[index];
+ public void SetX(int index, ulong value) => _x[index] = value;
public V128 GetV(int index) => default;
public void SetV(int index, V128 value) { }
diff --git a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs
index c3fb8b8a..e23274eb 100644
--- a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs
+++ b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs
@@ -7,13 +7,14 @@ using Ryujinx.HLE.HOS.Kernel.Ipc;
using Ryujinx.HLE.HOS.Kernel.Memory;
using Ryujinx.HLE.HOS.Kernel.Process;
using Ryujinx.HLE.HOS.Kernel.Threading;
+using Ryujinx.Horizon.Common;
using System;
using System.Threading;
namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
{
[SvcImpl]
- class Syscall
+ class Syscall : ISyscallApi
{
private readonly KernelContext _context;
@@ -25,7 +26,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
// Process
[Svc(0x24)]
- public KernelResult GetProcessId(out ulong pid, int handle)
+ public Result GetProcessId(out ulong pid, int handle)
{
KProcess currentProcess = KernelStatic.GetCurrentProcess();
@@ -46,11 +47,11 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
pid = process?.Pid ?? 0;
return process != null
- ? KernelResult.Success
+ ? Result.Success
: KernelResult.InvalidHandle;
}
- public KernelResult CreateProcess(
+ public Result CreateProcess(
out int handle,
ProcessCreationInfo info,
ReadOnlySpan<int> capabilities,
@@ -118,7 +119,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
_ => MemoryRegion.NvServices
};
- KernelResult result = process.Initialize(
+ Result result = process.Initialize(
info,
capabilities,
resourceLimit,
@@ -126,7 +127,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
contextFactory,
customThreadStart);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
return result;
}
@@ -136,7 +137,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return handleTable.GenerateHandle(process, out handle);
}
- public KernelResult StartProcess(int handle, int priority, int cpuCore, ulong mainThreadStackSize)
+ public Result StartProcess(int handle, int priority, int cpuCore, ulong mainThreadStackSize)
{
KProcess process = KernelStatic.GetCurrentProcess().HandleTable.GetObject<KProcess>(handle);
@@ -157,30 +158,30 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
process.DefaultCpuCore = cpuCore;
- KernelResult result = process.Start(priority, mainThreadStackSize);
+ Result result = process.Start(priority, mainThreadStackSize);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
return result;
}
process.IncrementReferenceCount();
- return KernelResult.Success;
+ return Result.Success;
}
[Svc(0x5f)]
- public KernelResult FlushProcessDataCache(int processHandle, ulong address, ulong size)
+ public Result FlushProcessDataCache(int processHandle, ulong address, ulong size)
{
// FIXME: This needs to be implemented as ARMv7 doesn't have any way to do cache maintenance operations on EL0.
// As we don't support (and don't actually need) to flush the cache, this is stubbed.
- return KernelResult.Success;
+ return Result.Success;
}
// IPC
[Svc(0x1f)]
- public KernelResult ConnectToNamedPort(out int handle, [PointerSized] ulong namePtr)
+ public Result ConnectToNamedPort(out int handle, [PointerSized] ulong namePtr)
{
handle = 0;
@@ -192,7 +193,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return ConnectToNamedPort(out handle, name);
}
- public KernelResult ConnectToNamedPort(out int handle, string name)
+ public Result ConnectToNamedPort(out int handle, string name)
{
handle = 0;
@@ -210,16 +211,16 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
KProcess currentProcess = KernelStatic.GetCurrentProcess();
- KernelResult result = currentProcess.HandleTable.ReserveHandle(out handle);
+ Result result = currentProcess.HandleTable.ReserveHandle(out handle);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
return result;
}
result = clientPort.Connect(out KClientSession clientSession);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
currentProcess.HandleTable.CancelHandleReservation(handle);
@@ -234,7 +235,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
}
[Svc(0x21)]
- public KernelResult SendSyncRequest(int handle)
+ public Result SendSyncRequest(int handle)
{
KProcess currentProcess = KernelStatic.GetCurrentProcess();
@@ -249,7 +250,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
}
[Svc(0x22)]
- public KernelResult SendSyncRequestWithUserBuffer(
+ public Result SendSyncRequestWithUserBuffer(
[PointerSized] ulong messagePtr,
[PointerSized] ulong messageSize,
int handle)
@@ -271,9 +272,9 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
KProcess currentProcess = KernelStatic.GetCurrentProcess();
- KernelResult result = currentProcess.MemoryManager.BorrowIpcBuffer(messagePtr, messageSize);
+ Result result = currentProcess.MemoryManager.BorrowIpcBuffer(messagePtr, messageSize);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
return result;
}
@@ -289,9 +290,9 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
result = session.SendSyncRequest(messagePtr, messageSize);
}
- KernelResult result2 = currentProcess.MemoryManager.UnborrowIpcBuffer(messagePtr, messageSize);
+ Result result2 = currentProcess.MemoryManager.UnborrowIpcBuffer(messagePtr, messageSize);
- if (result == KernelResult.Success)
+ if (result == Result.Success)
{
result = result2;
}
@@ -300,7 +301,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
}
[Svc(0x23)]
- public KernelResult SendAsyncRequestWithUserBuffer(
+ public Result SendAsyncRequestWithUserBuffer(
out int doneEventHandle,
[PointerSized] ulong messagePtr,
[PointerSized] ulong messageSize,
@@ -325,9 +326,9 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
KProcess currentProcess = KernelStatic.GetCurrentProcess();
- KernelResult result = currentProcess.MemoryManager.BorrowIpcBuffer(messagePtr, messageSize);
+ Result result = currentProcess.MemoryManager.BorrowIpcBuffer(messagePtr, messageSize);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
return result;
}
@@ -353,18 +354,18 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
result = currentProcess.HandleTable.GenerateHandle(doneEvent.ReadableEvent, out doneEventHandle);
- if (result == KernelResult.Success)
+ if (result == Result.Success)
{
result = session.SendAsyncRequest(doneEvent.WritableEvent, messagePtr, messageSize);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
currentProcess.HandleTable.CloseHandle(doneEventHandle);
}
}
}
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
resourceLimit?.Release(LimitableResource.Event, 1);
@@ -375,12 +376,21 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
}
[Svc(0x40)]
- public KernelResult CreateSession(
+ public Result CreateSession(
out int serverSessionHandle,
out int clientSessionHandle,
bool isLight,
[PointerSized] ulong namePtr)
{
+ return CreateSession(out serverSessionHandle, out clientSessionHandle, isLight, null);
+ }
+
+ public Result CreateSession(
+ out int serverSessionHandle,
+ out int clientSessionHandle,
+ bool isLight,
+ string name)
+ {
serverSessionHandle = 0;
clientSessionHandle = 0;
@@ -393,7 +403,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return KernelResult.ResLimitExceeded;
}
- KernelResult result;
+ Result result;
if (isLight)
{
@@ -401,11 +411,11 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
result = currentProcess.HandleTable.GenerateHandle(session.ServerSession, out serverSessionHandle);
- if (result == KernelResult.Success)
+ if (result == Result.Success)
{
result = currentProcess.HandleTable.GenerateHandle(session.ClientSession, out clientSessionHandle);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
currentProcess.HandleTable.CloseHandle(serverSessionHandle);
@@ -422,11 +432,11 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
result = currentProcess.HandleTable.GenerateHandle(session.ServerSession, out serverSessionHandle);
- if (result == KernelResult.Success)
+ if (result == Result.Success)
{
result = currentProcess.HandleTable.GenerateHandle(session.ClientSession, out clientSessionHandle);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
currentProcess.HandleTable.CloseHandle(serverSessionHandle);
@@ -442,7 +452,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
}
[Svc(0x41)]
- public KernelResult AcceptSession(out int sessionHandle, int portHandle)
+ public Result AcceptSession(out int sessionHandle, int portHandle)
{
sessionHandle = 0;
@@ -455,9 +465,9 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return KernelResult.InvalidHandle;
}
- KernelResult result = currentProcess.HandleTable.ReserveHandle(out int handle);
+ Result result = currentProcess.HandleTable.ReserveHandle(out int handle);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
return result;
}
@@ -481,7 +491,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
sessionHandle = handle;
- result = KernelResult.Success;
+ result = Result.Success;
}
else
{
@@ -494,7 +504,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
}
[Svc(0x43)]
- public KernelResult ReplyAndReceive(
+ public Result ReplyAndReceive(
out int handleIndex,
[PointerSized] ulong handlesPtr,
int handlesCount,
@@ -537,7 +547,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return ReplyAndReceive(out handleIndex, handles, replyTargetHandle, timeout);
}
- public KernelResult ReplyAndReceive(out int handleIndex, ReadOnlySpan<int> handles, int replyTargetHandle, long timeout)
+ public Result ReplyAndReceive(out int handleIndex, ReadOnlySpan<int> handles, int replyTargetHandle, long timeout)
{
handleIndex = 0;
@@ -557,7 +567,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
syncObjs[index] = obj;
}
- KernelResult result = KernelResult.Success;
+ Result result = Result.Success;
if (replyTargetHandle != 0)
{
@@ -573,14 +583,14 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
}
}
- if (result == KernelResult.Success)
+ if (result == Result.Success)
{
if (timeout > 0)
{
timeout += KTimeManager.DefaultTimeIncrementNanoseconds;
}
- while ((result = _context.Synchronization.WaitFor(syncObjs, timeout, out handleIndex)) == KernelResult.Success)
+ while ((result = _context.Synchronization.WaitFor(syncObjs, timeout, out handleIndex)) == Result.Success)
{
KServerSession session = currentProcess.HandleTable.GetObject<KServerSession>(handles[handleIndex]);
@@ -600,7 +610,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
}
[Svc(0x44)]
- public KernelResult ReplyAndReceiveWithUserBuffer(
+ public Result ReplyAndReceiveWithUserBuffer(
out int handleIndex,
[PointerSized] ulong messagePtr,
[PointerSized] ulong messageSize,
@@ -630,9 +640,9 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return KernelResult.UserCopyFailed;
}
- KernelResult result = currentProcess.MemoryManager.BorrowIpcBuffer(messagePtr, messageSize);
+ Result result = currentProcess.MemoryManager.BorrowIpcBuffer(messagePtr, messageSize);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
return result;
}
@@ -676,14 +686,14 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
}
}
- if (result == KernelResult.Success)
+ if (result == Result.Success)
{
if (timeout > 0)
{
timeout += KTimeManager.DefaultTimeIncrementNanoseconds;
}
- while ((result = _context.Synchronization.WaitFor(syncObjs, timeout, out handleIndex)) == KernelResult.Success)
+ while ((result = _context.Synchronization.WaitFor(syncObjs, timeout, out handleIndex)) == Result.Success)
{
KServerSession session = currentProcess.HandleTable.GetObject<KServerSession>(handles[handleIndex]);
@@ -705,13 +715,24 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
}
[Svc(0x70)]
- public KernelResult CreatePort(
+ public Result CreatePort(
out int serverPortHandle,
out int clientPortHandle,
int maxSessions,
bool isLight,
[PointerSized] ulong namePtr)
{
+ // The kernel doesn't use the name pointer, so we can just pass null as the name.
+ return CreatePort(out serverPortHandle, out clientPortHandle, maxSessions, isLight, null);
+ }
+
+ public Result CreatePort(
+ out int serverPortHandle,
+ out int clientPortHandle,
+ int maxSessions,
+ bool isLight,
+ string name)
+ {
serverPortHandle = clientPortHandle = 0;
if (maxSessions < 1)
@@ -719,20 +740,20 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return KernelResult.MaximumExceeded;
}
- KPort port = new KPort(_context, maxSessions, isLight, (long)namePtr);
+ KPort port = new KPort(_context, maxSessions, isLight, name);
KProcess currentProcess = KernelStatic.GetCurrentProcess();
- KernelResult result = currentProcess.HandleTable.GenerateHandle(port.ClientPort, out clientPortHandle);
+ Result result = currentProcess.HandleTable.GenerateHandle(port.ClientPort, out clientPortHandle);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
return result;
}
result = currentProcess.HandleTable.GenerateHandle(port.ServerPort, out serverPortHandle);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
currentProcess.HandleTable.CloseHandle(clientPortHandle);
}
@@ -741,7 +762,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
}
[Svc(0x71)]
- public KernelResult ManageNamedPort(out int handle, [PointerSized] ulong namePtr, int maxSessions)
+ public Result ManageNamedPort(out int handle, [PointerSized] ulong namePtr, int maxSessions)
{
handle = 0;
@@ -758,7 +779,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return ManageNamedPort(out handle, name, maxSessions);
}
- public KernelResult ManageNamedPort(out int handle, string name, int maxSessions)
+ public Result ManageNamedPort(out int handle, string name, int maxSessions)
{
handle = 0;
@@ -772,20 +793,20 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return KAutoObject.RemoveName(_context, name);
}
- KPort port = new KPort(_context, maxSessions, false, 0);
+ KPort port = new KPort(_context, maxSessions, false, null);
KProcess currentProcess = KernelStatic.GetCurrentProcess();
- KernelResult result = currentProcess.HandleTable.GenerateHandle(port.ServerPort, out handle);
+ Result result = currentProcess.HandleTable.GenerateHandle(port.ServerPort, out handle);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
return result;
}
result = port.ClientPort.SetName(name);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
currentProcess.HandleTable.CloseHandle(handle);
}
@@ -794,7 +815,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
}
[Svc(0x72)]
- public KernelResult ConnectToPort(out int clientSessionHandle, int clientPortHandle)
+ public Result ConnectToPort(out int clientSessionHandle, int clientPortHandle)
{
clientSessionHandle = 0;
@@ -807,9 +828,9 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return KernelResult.InvalidHandle;
}
- KernelResult result = currentProcess.HandleTable.ReserveHandle(out int handle);
+ Result result = currentProcess.HandleTable.ReserveHandle(out int handle);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
return result;
}
@@ -829,7 +850,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
session = clientSession;
}
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
currentProcess.HandleTable.CancelHandleReservation(handle);
@@ -848,7 +869,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
// Memory
[Svc(1)]
- public KernelResult SetHeapSize([PointerSized] out ulong address, [PointerSized] ulong size)
+ public Result SetHeapSize([PointerSized] out ulong address, [PointerSized] ulong size)
{
if ((size & 0xfffffffe001fffff) != 0)
{
@@ -863,7 +884,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
}
[Svc(2)]
- public KernelResult SetMemoryPermission([PointerSized] ulong address, [PointerSized] ulong size, KMemoryPermission permission)
+ public Result SetMemoryPermission([PointerSized] ulong address, [PointerSized] ulong size, KMemoryPermission permission)
{
if (!PageAligned(address))
{
@@ -896,7 +917,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
}
[Svc(3)]
- public KernelResult SetMemoryAttribute(
+ public Result SetMemoryAttribute(
[PointerSized] ulong address,
[PointerSized] ulong size,
MemoryAttribute attributeMask,
@@ -927,7 +948,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return KernelResult.InvalidMemState;
}
- KernelResult result = process.MemoryManager.SetMemoryAttribute(
+ Result result = process.MemoryManager.SetMemoryAttribute(
address,
size,
attributeMask,
@@ -937,7 +958,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
}
[Svc(4)]
- public KernelResult MapMemory([PointerSized] ulong dst, [PointerSized] ulong src, [PointerSized] ulong size)
+ public Result MapMemory([PointerSized] ulong dst, [PointerSized] ulong src, [PointerSized] ulong size)
{
if (!PageAligned(src | dst))
{
@@ -974,7 +995,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
}
[Svc(5)]
- public KernelResult UnmapMemory([PointerSized] ulong dst, [PointerSized] ulong src, [PointerSized] ulong size)
+ public Result UnmapMemory([PointerSized] ulong dst, [PointerSized] ulong src, [PointerSized] ulong size)
{
if (!PageAligned(src | dst))
{
@@ -1011,21 +1032,21 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
}
[Svc(6)]
- public KernelResult QueryMemory([PointerSized] ulong infoPtr, [PointerSized] out ulong pageInfo, [PointerSized] ulong address)
+ public Result QueryMemory([PointerSized] ulong infoPtr, [PointerSized] out ulong pageInfo, [PointerSized] ulong address)
{
- KernelResult result = QueryMemory(out MemoryInfo info, out pageInfo, address);
+ Result result = QueryMemory(out MemoryInfo info, out pageInfo, address);
- if (result == KernelResult.Success)
+ if (result == Result.Success)
{
return KernelTransfer.KernelToUser(infoPtr, info)
- ? KernelResult.Success
+ ? Result.Success
: KernelResult.InvalidMemState;
}
return result;
}
- public KernelResult QueryMemory(out MemoryInfo info, out ulong pageInfo, ulong address)
+ public Result QueryMemory(out MemoryInfo info, out ulong pageInfo, ulong address)
{
KProcess process = KernelStatic.GetCurrentProcess();
@@ -1042,11 +1063,11 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
pageInfo = 0;
- return KernelResult.Success;
+ return Result.Success;
}
[Svc(0x13)]
- public KernelResult MapSharedMemory(int handle, [PointerSized] ulong address, [PointerSized] ulong size, KMemoryPermission permission)
+ public Result MapSharedMemory(int handle, [PointerSized] ulong address, [PointerSized] ulong size, KMemoryPermission permission)
{
if (!PageAligned(address))
{
@@ -1093,7 +1114,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
}
[Svc(0x14)]
- public KernelResult UnmapSharedMemory(int handle, [PointerSized] ulong address, [PointerSized] ulong size)
+ public Result UnmapSharedMemory(int handle, [PointerSized] ulong address, [PointerSized] ulong size)
{
if (!PageAligned(address))
{
@@ -1134,7 +1155,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
}
[Svc(0x15)]
- public KernelResult CreateTransferMemory(out int handle, [PointerSized] ulong address, [PointerSized] ulong size, KMemoryPermission permission)
+ public Result CreateTransferMemory(out int handle, [PointerSized] ulong address, [PointerSized] ulong size, KMemoryPermission permission)
{
handle = 0;
@@ -1181,9 +1202,9 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
KTransferMemory transferMemory = new KTransferMemory(_context);
- KernelResult result = transferMemory.Initialize(address, size, permission);
+ Result result = transferMemory.Initialize(address, size, permission);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
CleanUpForError();
@@ -1198,7 +1219,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
}
[Svc(0x51)]
- public KernelResult MapTransferMemory(int handle, [PointerSized] ulong address, [PointerSized] ulong size, KMemoryPermission permission)
+ public Result MapTransferMemory(int handle, [PointerSized] ulong address, [PointerSized] ulong size, KMemoryPermission permission)
{
if (!PageAligned(address))
{
@@ -1245,7 +1266,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
}
[Svc(0x52)]
- public KernelResult UnmapTransferMemory(int handle, [PointerSized] ulong address, [PointerSized] ulong size)
+ public Result UnmapTransferMemory(int handle, [PointerSized] ulong address, [PointerSized] ulong size)
{
if (!PageAligned(address))
{
@@ -1286,7 +1307,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
}
[Svc(0x2c)]
- public KernelResult MapPhysicalMemory([PointerSized] ulong address, [PointerSized] ulong size)
+ public Result MapPhysicalMemory([PointerSized] ulong address, [PointerSized] ulong size)
{
if (!PageAligned(address))
{
@@ -1322,7 +1343,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
}
[Svc(0x2d)]
- public KernelResult UnmapPhysicalMemory([PointerSized] ulong address, [PointerSized] ulong size)
+ public Result UnmapPhysicalMemory([PointerSized] ulong address, [PointerSized] ulong size)
{
if (!PageAligned(address))
{
@@ -1358,7 +1379,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
}
[Svc(0x4b)]
- public KernelResult CreateCodeMemory(out int handle, [PointerSized] ulong address, [PointerSized] ulong size)
+ public Result CreateCodeMemory(out int handle, [PointerSized] ulong address, [PointerSized] ulong size)
{
handle = 0;
@@ -1388,9 +1409,9 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return KernelResult.InvalidMemState;
}
- KernelResult result = codeMemory.Initialize(address, size);
+ Result result = codeMemory.Initialize(address, size);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
return result;
}
@@ -1399,7 +1420,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
}
[Svc(0x4c)]
- public KernelResult ControlCodeMemory(
+ public Result ControlCodeMemory(
int handle,
CodeMemoryOperation op,
ulong address,
@@ -1477,7 +1498,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
}
[Svc(0x73)]
- public KernelResult SetProcessMemoryPermission(
+ public Result SetProcessMemoryPermission(
int handle,
[PointerSized] ulong src,
[PointerSized] ulong size,
@@ -1519,7 +1540,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
}
[Svc(0x74)]
- public KernelResult MapProcessMemory(
+ public Result MapProcessMemory(
[PointerSized] ulong dst,
int handle,
ulong src,
@@ -1556,7 +1577,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
KPageList pageList = new KPageList();
- KernelResult result = srcProcess.MemoryManager.GetPagesIfStateEquals(
+ Result result = srcProcess.MemoryManager.GetPagesIfStateEquals(
src,
size,
MemoryState.MapProcessAllowed,
@@ -1567,7 +1588,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
MemoryAttribute.None,
pageList);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
return result;
}
@@ -1576,7 +1597,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
}
[Svc(0x75)]
- public KernelResult UnmapProcessMemory(
+ public Result UnmapProcessMemory(
[PointerSized] ulong dst,
int handle,
ulong src,
@@ -1611,18 +1632,18 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return KernelResult.InvalidMemRange;
}
- KernelResult result = dstProcess.MemoryManager.UnmapProcessMemory(dst, size, srcProcess.MemoryManager, src);
+ Result result = dstProcess.MemoryManager.UnmapProcessMemory(dst, size, srcProcess.MemoryManager, src);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
return result;
}
- return KernelResult.Success;
+ return Result.Success;
}
[Svc(0x77)]
- public KernelResult MapProcessCodeMemory(int handle, ulong dst, ulong src, ulong size)
+ public Result MapProcessCodeMemory(int handle, ulong dst, ulong src, ulong size)
{
if (!PageAligned(dst) || !PageAligned(src))
{
@@ -1660,7 +1681,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
}
[Svc(0x78)]
- public KernelResult UnmapProcessCodeMemory(int handle, ulong dst, ulong src, ulong size)
+ public Result UnmapProcessCodeMemory(int handle, ulong dst, ulong src, ulong size)
{
if (!PageAligned(dst) || !PageAligned(src))
{
@@ -1705,19 +1726,19 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
// System
[Svc(0x7b)]
- public KernelResult TerminateProcess(int handle)
+ public Result TerminateProcess(int handle)
{
KProcess process = KernelStatic.GetCurrentProcess();
process = process.HandleTable.GetObject<KProcess>(handle);
- KernelResult result;
+ Result result;
if (process != null)
{
if (process == KernelStatic.GetCurrentProcess())
{
- result = KernelResult.Success;
+ result = Result.Success;
process.DecrementToZeroWhileTerminatingCurrent();
}
else
@@ -1741,19 +1762,19 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
}
[Svc(0x11)]
- public KernelResult SignalEvent(int handle)
+ public Result SignalEvent(int handle)
{
KProcess process = KernelStatic.GetCurrentProcess();
KWritableEvent writableEvent = process.HandleTable.GetObject<KWritableEvent>(handle);
- KernelResult result;
+ Result result;
if (writableEvent != null)
{
writableEvent.Signal();
- result = KernelResult.Success;
+ result = Result.Success;
}
else
{
@@ -1764,9 +1785,9 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
}
[Svc(0x12)]
- public KernelResult ClearEvent(int handle)
+ public Result ClearEvent(int handle)
{
- KernelResult result;
+ Result result;
KProcess process = KernelStatic.GetCurrentProcess();
@@ -1787,21 +1808,21 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
}
[Svc(0x16)]
- public KernelResult CloseHandle(int handle)
+ public Result CloseHandle(int handle)
{
KProcess currentProcess = KernelStatic.GetCurrentProcess();
- return currentProcess.HandleTable.CloseHandle(handle) ? KernelResult.Success : KernelResult.InvalidHandle;
+ return currentProcess.HandleTable.CloseHandle(handle) ? Result.Success : KernelResult.InvalidHandle;
}
[Svc(0x17)]
- public KernelResult ResetSignal(int handle)
+ public Result ResetSignal(int handle)
{
KProcess currentProcess = KernelStatic.GetCurrentProcess();
KReadableEvent readableEvent = currentProcess.HandleTable.GetObject<KReadableEvent>(handle);
- KernelResult result;
+ Result result;
if (readableEvent != null)
{
@@ -1868,7 +1889,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
}
[Svc(0x29)]
- public KernelResult GetInfo(out ulong value, InfoType id, int handle, long subId)
+ public Result GetInfo(out ulong value, InfoType id, int handle, long subId)
{
value = 0;
@@ -2010,9 +2031,9 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
KHandleTable handleTable = currentProcess.HandleTable;
KResourceLimit resourceLimit = currentProcess.ResourceLimit;
- KernelResult result = handleTable.GenerateHandle(resourceLimit, out int resLimHandle);
+ Result result = handleTable.GenerateHandle(resourceLimit, out int resLimHandle);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
return result;
}
@@ -2081,7 +2102,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
if (subId != -1 && subId != currentCore)
{
- return KernelResult.Success;
+ return Result.Success;
}
KScheduler scheduler = _context.Schedulers[currentCore];
@@ -2122,12 +2143,12 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
KProcess currentProcess = KernelStatic.GetCurrentProcess();
KHandleTable handleTable = currentProcess.HandleTable;
- KernelResult result = handleTable.GenerateHandle(currentProcess, out int outHandle);
+ Result result = handleTable.GenerateHandle(currentProcess, out int outHandle);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
return result;
- }
+ }
value = (ulong)outHandle;
@@ -2137,23 +2158,23 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
default: return KernelResult.InvalidEnumValue;
}
- return KernelResult.Success;
+ return Result.Success;
}
[Svc(0x45)]
- public KernelResult CreateEvent(out int wEventHandle, out int rEventHandle)
+ public Result CreateEvent(out int wEventHandle, out int rEventHandle)
{
KEvent Event = new KEvent(_context);
KProcess process = KernelStatic.GetCurrentProcess();
- KernelResult result = process.HandleTable.GenerateHandle(Event.WritableEvent, out wEventHandle);
+ Result result = process.HandleTable.GenerateHandle(Event.WritableEvent, out wEventHandle);
- if (result == KernelResult.Success)
+ if (result == Result.Success)
{
result = process.HandleTable.GenerateHandle(Event.ReadableEvent, out rEventHandle);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
process.HandleTable.CloseHandle(wEventHandle);
}
@@ -2167,7 +2188,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
}
[Svc(0x65)]
- public KernelResult GetProcessList(out int count, [PointerSized] ulong address, int maxCount)
+ public Result GetProcessList(out int count, [PointerSized] ulong address, int maxCount)
{
count = 0;
@@ -2213,11 +2234,11 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
count = copyCount;
- return KernelResult.Success;
+ return Result.Success;
}
[Svc(0x6f)]
- public KernelResult GetSystemInfo(out long value, uint id, int handle, long subId)
+ public Result GetSystemInfo(out long value, uint id, int handle, long subId)
{
value = 0;
@@ -2270,11 +2291,11 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
}
}
- return KernelResult.Success;
+ return Result.Success;
}
[Svc(0x30)]
- public KernelResult GetResourceLimitLimitValue(out long limitValue, int handle, LimitableResource resource)
+ public Result GetResourceLimitLimitValue(out long limitValue, int handle, LimitableResource resource)
{
limitValue = 0;
@@ -2292,11 +2313,11 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
limitValue = resourceLimit.GetLimitValue(resource);
- return KernelResult.Success;
+ return Result.Success;
}
[Svc(0x31)]
- public KernelResult GetResourceLimitCurrentValue(out long limitValue, int handle, LimitableResource resource)
+ public Result GetResourceLimitCurrentValue(out long limitValue, int handle, LimitableResource resource)
{
limitValue = 0;
@@ -2314,11 +2335,11 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
limitValue = resourceLimit.GetCurrentValue(resource);
- return KernelResult.Success;
+ return Result.Success;
}
[Svc(0x37)]
- public KernelResult GetResourceLimitPeakValue(out long peak, int handle, LimitableResource resource)
+ public Result GetResourceLimitPeakValue(out long peak, int handle, LimitableResource resource)
{
peak = 0;
@@ -2336,11 +2357,11 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
peak = resourceLimit.GetPeakValue(resource);
- return KernelResult.Success;
+ return Result.Success;
}
[Svc(0x7d)]
- public KernelResult CreateResourceLimit(out int handle)
+ public Result CreateResourceLimit(out int handle)
{
KResourceLimit limit = new KResourceLimit(_context);
@@ -2350,7 +2371,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
}
[Svc(0x7e)]
- public KernelResult SetResourceLimitLimitValue(int handle, LimitableResource resource, long limitValue)
+ public Result SetResourceLimitLimitValue(int handle, LimitableResource resource, long limitValue)
{
if (resource >= LimitableResource.Count)
{
@@ -2370,7 +2391,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
// Thread
[Svc(8)]
- public KernelResult CreateThread(
+ public Result CreateThread(
out int handle,
[PointerSized] ulong entrypoint,
[PointerSized] ulong argsPtr,
@@ -2381,7 +2402,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return CreateThread(out handle, entrypoint, argsPtr, stackTop, priority, cpuCore, null);
}
- public KernelResult CreateThread(
+ public Result CreateThread(
out int handle,
ulong entrypoint,
ulong argsPtr,
@@ -2419,7 +2440,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
KThread thread = new KThread(_context);
- KernelResult result = currentProcess.InitializeThread(
+ Result result = currentProcess.InitializeThread(
thread,
entrypoint,
argsPtr,
@@ -2428,7 +2449,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
cpuCore,
customThreadStart);
- if (result == KernelResult.Success)
+ if (result == Result.Success)
{
KProcess process = KernelStatic.GetCurrentProcess();
@@ -2445,7 +2466,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
}
[Svc(9)]
- public KernelResult StartThread(int handle)
+ public Result StartThread(int handle)
{
KProcess process = KernelStatic.GetCurrentProcess();
@@ -2455,9 +2476,9 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
{
thread.IncrementReferenceCount();
- KernelResult result = thread.Start();
+ Result result = thread.Start();
- if (result == KernelResult.Success)
+ if (result == Result.Success)
{
thread.IncrementReferenceCount();
}
@@ -2499,7 +2520,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
}
[Svc(0xc)]
- public KernelResult GetThreadPriority(out int priority, int handle)
+ public Result GetThreadPriority(out int priority, int handle)
{
KProcess process = KernelStatic.GetCurrentProcess();
@@ -2509,7 +2530,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
{
priority = thread.DynamicPriority;
- return KernelResult.Success;
+ return Result.Success;
}
else
{
@@ -2520,7 +2541,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
}
[Svc(0xd)]
- public KernelResult SetThreadPriority(int handle, int priority)
+ public Result SetThreadPriority(int handle, int priority)
{
// TODO: NPDM check.
@@ -2535,11 +2556,11 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
thread.SetPriority(priority);
- return KernelResult.Success;
+ return Result.Success;
}
[Svc(0xe)]
- public KernelResult GetThreadCoreMask(out int preferredCore, out ulong affinityMask, int handle)
+ public Result GetThreadCoreMask(out int preferredCore, out ulong affinityMask, int handle)
{
KProcess process = KernelStatic.GetCurrentProcess();
@@ -2550,7 +2571,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
preferredCore = thread.PreferredCore;
affinityMask = thread.AffinityMask;
- return KernelResult.Success;
+ return Result.Success;
}
else
{
@@ -2562,7 +2583,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
}
[Svc(0xf)]
- public KernelResult SetThreadCoreMask(int handle, int preferredCore, ulong affinityMask)
+ public Result SetThreadCoreMask(int handle, int preferredCore, ulong affinityMask)
{
KProcess currentProcess = KernelStatic.GetCurrentProcess();
@@ -2617,7 +2638,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
}
[Svc(0x25)]
- public KernelResult GetThreadId(out ulong threadUid, int handle)
+ public Result GetThreadId(out ulong threadUid, int handle)
{
KProcess process = KernelStatic.GetCurrentProcess();
@@ -2627,7 +2648,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
{
threadUid = thread.ThreadUid;
- return KernelResult.Success;
+ return Result.Success;
}
else
{
@@ -2638,7 +2659,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
}
[Svc(0x32)]
- public KernelResult SetThreadActivity(int handle, bool pause)
+ public Result SetThreadActivity(int handle, bool pause)
{
KProcess process = KernelStatic.GetCurrentProcess();
@@ -2663,7 +2684,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
}
[Svc(0x33)]
- public KernelResult GetThreadContext3([PointerSized] ulong address, int handle)
+ public Result GetThreadContext3([PointerSized] ulong address, int handle)
{
KProcess currentProcess = KernelStatic.GetCurrentProcess();
KThread currentThread = KernelStatic.GetCurrentThread();
@@ -2685,12 +2706,12 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return KernelResult.InvalidThread;
}
- KernelResult result = thread.GetThreadContext3(out ThreadContext context);
+ Result result = thread.GetThreadContext3(out ThreadContext context);
- if (result == KernelResult.Success)
+ if (result == Result.Success)
{
return KernelTransfer.KernelToUser(address, context)
- ? KernelResult.Success
+ ? Result.Success
: KernelResult.InvalidMemState;
}
@@ -2700,7 +2721,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
// Thread synchronization
[Svc(0x18)]
- public KernelResult WaitSynchronization(out int handleIndex, [PointerSized] ulong handlesPtr, int handlesCount, long timeout)
+ public Result WaitSynchronization(out int handleIndex, [PointerSized] ulong handlesPtr, int handlesCount, long timeout)
{
handleIndex = 0;
@@ -2711,8 +2732,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
KThread currentThread = KernelStatic.GetCurrentThread();
- var syncObjs = new Span<KSynchronizationObject>(currentThread.WaitSyncObjects).Slice(0, handlesCount);
-
if (handlesCount != 0)
{
KProcess currentProcess = KernelStatic.GetCurrentProcess();
@@ -2741,9 +2760,32 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return KernelResult.UserCopyFailed;
}
+ return WaitSynchronization(out handleIndex, handles, timeout);
+ }
+
+ return WaitSynchronization(out handleIndex, ReadOnlySpan<int>.Empty, timeout);
+ }
+
+ public Result WaitSynchronization(out int handleIndex, ReadOnlySpan<int> handles, long timeout)
+ {
+ handleIndex = 0;
+
+ if ((uint)handles.Length > KThread.MaxWaitSyncObjects)
+ {
+ return KernelResult.MaximumExceeded;
+ }
+
+ KThread currentThread = KernelStatic.GetCurrentThread();
+
+ var syncObjs = new Span<KSynchronizationObject>(currentThread.WaitSyncObjects).Slice(0, handles.Length);
+
+ if (handles.Length != 0)
+ {
+ KProcess currentProcess = KernelStatic.GetCurrentProcess();
+
int processedHandles = 0;
- for (; processedHandles < handlesCount; processedHandles++)
+ for (; processedHandles < handles.Length; processedHandles++)
{
KSynchronizationObject syncObj = currentProcess.HandleTable.GetObject<KSynchronizationObject>(handles[processedHandles]);
@@ -2757,7 +2799,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
syncObj.IncrementReferenceCount();
}
- if (processedHandles != handlesCount)
+ if (processedHandles != handles.Length)
{
// One or more handles are invalid.
for (int index = 0; index < processedHandles; index++)
@@ -2774,14 +2816,14 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
timeout += KTimeManager.DefaultTimeIncrementNanoseconds;
}
- KernelResult result = _context.Synchronization.WaitFor(syncObjs, timeout, out handleIndex);
+ Result result = _context.Synchronization.WaitFor(syncObjs, timeout, out handleIndex);
if (result == KernelResult.PortRemoteClosed)
{
- result = KernelResult.Success;
+ result = Result.Success;
}
- for (int index = 0; index < handlesCount; index++)
+ for (int index = 0; index < handles.Length; index++)
{
currentThread.WaitSyncObjects[index].DecrementReferenceCount();
}
@@ -2790,7 +2832,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
}
[Svc(0x19)]
- public KernelResult CancelSynchronization(int handle)
+ public Result CancelSynchronization(int handle)
{
KProcess process = KernelStatic.GetCurrentProcess();
@@ -2803,11 +2845,11 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
thread.CancelSynchronization();
- return KernelResult.Success;
+ return Result.Success;
}
[Svc(0x1a)]
- public KernelResult ArbitrateLock(int ownerHandle, [PointerSized] ulong mutexAddress, int requesterHandle)
+ public Result ArbitrateLock(int ownerHandle, [PointerSized] ulong mutexAddress, int requesterHandle)
{
if (IsPointingInsideKernel(mutexAddress))
{
@@ -2825,7 +2867,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
}
[Svc(0x1b)]
- public KernelResult ArbitrateUnlock([PointerSized] ulong mutexAddress)
+ public Result ArbitrateUnlock([PointerSized] ulong mutexAddress)
{
if (IsPointingInsideKernel(mutexAddress))
{
@@ -2843,7 +2885,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
}
[Svc(0x1c)]
- public KernelResult WaitProcessWideKeyAtomic(
+ public Result WaitProcessWideKeyAtomic(
[PointerSized] ulong mutexAddress,
[PointerSized] ulong condVarAddress,
int handle,
@@ -2874,17 +2916,17 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
}
[Svc(0x1d)]
- public KernelResult SignalProcessWideKey([PointerSized] ulong address, int count)
+ public Result SignalProcessWideKey([PointerSized] ulong address, int count)
{
KProcess currentProcess = KernelStatic.GetCurrentProcess();
currentProcess.AddressArbiter.SignalProcessWideKey(address, count);
- return KernelResult.Success;
+ return Result.Success;
}
[Svc(0x34)]
- public KernelResult WaitForAddress([PointerSized] ulong address, ArbitrationType type, int value, long timeout)
+ public Result WaitForAddress([PointerSized] ulong address, ArbitrationType type, int value, long timeout)
{
if (IsPointingInsideKernel(address))
{
@@ -2916,7 +2958,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
}
[Svc(0x35)]
- public KernelResult SignalToAddress([PointerSized] ulong address, SignalType type, int value, int count)
+ public Result SignalToAddress([PointerSized] ulong address, SignalType type, int value, int count)
{
if (IsPointingInsideKernel(address))
{
@@ -2943,11 +2985,11 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
}
[Svc(0x36)]
- public KernelResult SynchronizePreemptionState()
+ public Result SynchronizePreemptionState()
{
KernelStatic.GetCurrentThread().SynchronizePreemptionState();
- return KernelResult.Success;
+ return Result.Success;
}
private static bool IsPointingInsideKernel(ulong address)
diff --git a/Ryujinx.HLE/HOS/Kernel/Threading/KAddressArbiter.cs b/Ryujinx.HLE/HOS/Kernel/Threading/KAddressArbiter.cs
index f53b43b3..a5f9df5e 100644
--- a/Ryujinx.HLE/HOS/Kernel/Threading/KAddressArbiter.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Threading/KAddressArbiter.cs
@@ -1,5 +1,6 @@
using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Process;
+using Ryujinx.Horizon.Common;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -24,14 +25,14 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
_arbiterThreads = new List<KThread>();
}
- public KernelResult ArbitrateLock(int ownerHandle, ulong mutexAddress, int requesterHandle)
+ public Result ArbitrateLock(int ownerHandle, ulong mutexAddress, int requesterHandle)
{
KThread currentThread = KernelStatic.GetCurrentThread();
_context.CriticalSection.Enter();
currentThread.SignaledObj = null;
- currentThread.ObjSyncResult = KernelResult.Success;
+ currentThread.ObjSyncResult = Result.Success;
KProcess currentProcess = KernelStatic.GetCurrentProcess();
@@ -46,7 +47,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
{
_context.CriticalSection.Leave();
- return 0;
+ return Result.Success;
}
KThread mutexOwner = currentProcess.HandleTable.GetObject<KThread>(ownerHandle);
@@ -78,7 +79,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
return currentThread.ObjSyncResult;
}
- public KernelResult ArbitrateUnlock(ulong mutexAddress)
+ public Result ArbitrateUnlock(ulong mutexAddress)
{
_context.CriticalSection.Enter();
@@ -86,14 +87,14 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
(int mutexValue, KThread newOwnerThread) = MutexUnlock(currentThread, mutexAddress);
- KernelResult result = KernelResult.Success;
+ Result result = Result.Success;
if (!KernelTransfer.KernelToUser(mutexAddress, mutexValue))
{
result = KernelResult.InvalidMemState;
}
- if (result != KernelResult.Success && newOwnerThread != null)
+ if (result != Result.Success && newOwnerThread != null)
{
newOwnerThread.SignaledObj = null;
newOwnerThread.ObjSyncResult = result;
@@ -104,7 +105,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
return result;
}
- public KernelResult WaitProcessWideKeyAtomic(ulong mutexAddress, ulong condVarAddress, int threadHandle, long timeout)
+ public Result WaitProcessWideKeyAtomic(ulong mutexAddress, ulong condVarAddress, int threadHandle, long timeout)
{
_context.CriticalSection.Enter();
@@ -185,7 +186,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
}
newOwnerThread.SignaledObj = null;
- newOwnerThread.ObjSyncResult = KernelResult.Success;
+ newOwnerThread.ObjSyncResult = Result.Success;
newOwnerThread.ReleaseAndResume();
}
@@ -247,7 +248,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
{
// We now own the mutex.
requester.SignaledObj = null;
- requester.ObjSyncResult = KernelResult.Success;
+ requester.ObjSyncResult = Result.Success;
requester.ReleaseAndResume();
@@ -273,7 +274,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
}
}
- public KernelResult WaitForAddressIfEqual(ulong address, int value, long timeout)
+ public Result WaitForAddressIfEqual(ulong address, int value, long timeout)
{
KThread currentThread = KernelStatic.GetCurrentThread();
@@ -344,7 +345,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
return KernelResult.InvalidState;
}
- public KernelResult WaitForAddressIfLessThan(ulong address, int value, bool shouldDecrement, long timeout)
+ public Result WaitForAddressIfLessThan(ulong address, int value, bool shouldDecrement, long timeout)
{
KThread currentThread = KernelStatic.GetCurrentThread();
@@ -422,7 +423,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
return KernelResult.InvalidState;
}
- public KernelResult Signal(ulong address, int count)
+ public Result Signal(ulong address, int count)
{
_context.CriticalSection.Enter();
@@ -430,10 +431,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
_context.CriticalSection.Leave();
- return KernelResult.Success;
+ return Result.Success;
}
- public KernelResult SignalAndIncrementIfEqual(ulong address, int value, int count)
+ public Result SignalAndIncrementIfEqual(ulong address, int value, int count)
{
_context.CriticalSection.Enter();
@@ -467,10 +468,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
_context.CriticalSection.Leave();
- return KernelResult.Success;
+ return Result.Success;
}
- public KernelResult SignalAndModifyIfEqual(ulong address, int value, int count)
+ public Result SignalAndModifyIfEqual(ulong address, int value, int count)
{
_context.CriticalSection.Enter();
@@ -539,7 +540,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
_context.CriticalSection.Leave();
- return KernelResult.Success;
+ return Result.Success;
}
private void WakeArbiterThreads(ulong address, int count)
@@ -547,7 +548,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
static void RemoveArbiterThread(KThread thread)
{
thread.SignaledObj = null;
- thread.ObjSyncResult = KernelResult.Success;
+ thread.ObjSyncResult = Result.Success;
thread.ReleaseAndResume();
diff --git a/Ryujinx.HLE/HOS/Kernel/Threading/KReadableEvent.cs b/Ryujinx.HLE/HOS/Kernel/Threading/KReadableEvent.cs
index d378b81e..d9e7befa 100644
--- a/Ryujinx.HLE/HOS/Kernel/Threading/KReadableEvent.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Threading/KReadableEvent.cs
@@ -1,4 +1,5 @@
using Ryujinx.HLE.HOS.Kernel.Common;
+using Ryujinx.Horizon.Common;
namespace Ryujinx.HLE.HOS.Kernel.Threading
{
@@ -27,16 +28,16 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
KernelContext.CriticalSection.Leave();
}
- public KernelResult Clear()
+ public Result Clear()
{
_signaled = false;
- return KernelResult.Success;
+ return Result.Success;
}
- public KernelResult ClearIfSignaled()
+ public Result ClearIfSignaled()
{
- KernelResult result;
+ Result result;
KernelContext.CriticalSection.Enter();
@@ -44,7 +45,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
{
_signaled = false;
- result = KernelResult.Success;
+ result = Result.Success;
}
else
{
diff --git a/Ryujinx.HLE/HOS/Kernel/Threading/KSynchronization.cs b/Ryujinx.HLE/HOS/Kernel/Threading/KSynchronization.cs
index 419f1536..01b65f55 100644
--- a/Ryujinx.HLE/HOS/Kernel/Threading/KSynchronization.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Threading/KSynchronization.cs
@@ -1,4 +1,5 @@
using Ryujinx.HLE.HOS.Kernel.Common;
+using Ryujinx.Horizon.Common;
using System;
using System.Collections.Generic;
@@ -13,11 +14,11 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
_context = context;
}
- public KernelResult WaitFor(Span<KSynchronizationObject> syncObjs, long timeout, out int handleIndex)
+ public Result WaitFor(Span<KSynchronizationObject> syncObjs, long timeout, out int handleIndex)
{
handleIndex = 0;
- KernelResult result = KernelResult.TimedOut;
+ Result result = KernelResult.TimedOut;
_context.CriticalSection.Enter();
@@ -33,7 +34,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
_context.CriticalSection.Leave();
- return KernelResult.Success;
+ return Result.Success;
}
if (timeout == 0)
@@ -122,7 +123,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
if ((thread.SchedFlags & ThreadSchedState.LowMask) == ThreadSchedState.Paused)
{
thread.SignaledObj = syncObj;
- thread.ObjSyncResult = KernelResult.Success;
+ thread.ObjSyncResult = Result.Success;
thread.Reschedule(ThreadSchedState.Running);
}
diff --git a/Ryujinx.HLE/HOS/Kernel/Threading/KThread.cs b/Ryujinx.HLE/HOS/Kernel/Threading/KThread.cs
index b9dd91ef..6fd49605 100644
--- a/Ryujinx.HLE/HOS/Kernel/Threading/KThread.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Threading/KThread.cs
@@ -3,6 +3,7 @@ using Ryujinx.Cpu;
using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Process;
using Ryujinx.HLE.HOS.Kernel.SupervisorCall;
+using Ryujinx.Horizon.Common;
using System;
using System.Collections.Generic;
using System.Numerics;
@@ -79,7 +80,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
private ThreadSchedState _forcePauseFlags;
private ThreadSchedState _forcePausePermissionFlags;
- public KernelResult ObjSyncResult { get; set; }
+ public Result ObjSyncResult { get; set; }
public int BasePriority { get; set; }
public int PreferredCore { get; set; }
@@ -130,7 +131,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
_activityOperationLock = new object();
}
- public KernelResult Initialize(
+ public Result Initialize(
ulong entrypoint,
ulong argsPtr,
ulong stackTop,
@@ -145,8 +146,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
throw new ArgumentException($"Invalid thread type \"{type}\".");
}
- ThreadContext = new KThreadContext();
-
PreferredCore = cpuCore;
AffinityMask |= 1UL << cpuCore;
@@ -166,7 +165,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
if (type == ThreadType.User)
{
- if (owner.AllocateThreadLocalStorage(out _tlsAddress) != KernelResult.Success)
+ if (owner.AllocateThreadLocalStorage(out _tlsAddress) != Result.Success)
{
return KernelResult.OutOfMemory;
}
@@ -194,6 +193,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
Context = owner?.CreateExecutionContext() ?? new ProcessExecutionContext();
+ ThreadContext = new KThreadContext(Context);
+
Context.IsAarch32 = !is64Bits;
Context.SetX(0, argsPtr);
@@ -230,7 +231,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
{
KernelContext.CriticalSection.Leave();
- return KernelResult.Success;
+ return Result.Success;
}
_forcePauseFlags |= ThreadSchedState.ProcessPauseFlag;
@@ -241,10 +242,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
}
}
- return KernelResult.Success;
+ return Result.Success;
}
- public KernelResult Start()
+ public Result Start()
{
if (!KernelContext.KernelInitialized)
{
@@ -260,7 +261,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
KernelContext.CriticalSection.Leave();
}
- KernelResult result = KernelResult.ThreadTerminating;
+ Result result = KernelResult.ThreadTerminating;
KernelContext.CriticalSection.Enter();
@@ -287,7 +288,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
StartHostThread();
- result = KernelResult.Success;
+ result = Result.Success;
break;
}
else
@@ -465,7 +466,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
return -1;
}
- public KernelResult Sleep(long timeout)
+ public Result Sleep(long timeout)
{
KernelContext.CriticalSection.Enter();
@@ -490,7 +491,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
KernelContext.TimeManager.UnscheduleFutureInvocation(this);
}
- return 0;
+ return Result.Success;
}
public void SetPriority(int priority)
@@ -534,11 +535,11 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
}
}
- public KernelResult SetActivity(bool pause)
+ public Result SetActivity(bool pause)
{
lock (_activityOperationLock)
{
- KernelResult result = KernelResult.Success;
+ Result result = Result.Success;
KernelContext.CriticalSection.Enter();
@@ -581,7 +582,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
KernelContext.CriticalSection.Leave();
- if (result == KernelResult.Success && pause)
+ if (result == Result.Success && pause)
{
bool isThreadRunning = true;
@@ -628,7 +629,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
}
}
- public KernelResult GetThreadContext3(out ThreadContext context)
+ public Result GetThreadContext3(out ThreadContext context)
{
context = default;
@@ -651,7 +652,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
KernelContext.CriticalSection.Leave();
}
- return KernelResult.Success;
+ return Result.Success;
}
private static uint GetPsr(IExecutionContext context)
@@ -739,7 +740,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
KernelContext.CriticalSection.Leave();
}
- public KernelResult SetCoreAndAffinityMask(int newCore, ulong newAffinityMask)
+ public Result SetCoreAndAffinityMask(int newCore, ulong newAffinityMask)
{
lock (_activityOperationLock)
{
@@ -838,7 +839,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
KernelContext.CriticalSection.Leave();
}
- return KernelResult.Success;
+ return Result.Success;
}
}
@@ -1259,6 +1260,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
if (_customThreadStart != null)
{
_customThreadStart();
+
+ // Ensure that anything trying to join the HLE thread is unblocked.
+ Exit();
+ HandlePostSyscall();
}
else
{
@@ -1304,7 +1309,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
{
Owner?.RemoveThread(this);
- if (_tlsAddress != 0 && Owner.FreeThreadLocalStorage(_tlsAddress) != KernelResult.Success)
+ if (_tlsAddress != 0 && Owner.FreeThreadLocalStorage(_tlsAddress) != Result.Success)
{
throw new InvalidOperationException("Unexpected failure freeing thread local storage.");
}
diff --git a/Ryujinx.HLE/HOS/Kernel/Threading/KThreadContext.cs b/Ryujinx.HLE/HOS/Kernel/Threading/KThreadContext.cs
index a7e9c4b3..e8ad53c2 100644
--- a/Ryujinx.HLE/HOS/Kernel/Threading/KThreadContext.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Threading/KThreadContext.cs
@@ -1,11 +1,25 @@
-using System.Threading;
+using Ryujinx.Cpu;
+using Ryujinx.Horizon.Common;
+using System.Threading;
namespace Ryujinx.HLE.HOS.Kernel.Threading
{
- class KThreadContext
+ class KThreadContext : IThreadContext
{
+ private readonly IExecutionContext _context;
+
+ public bool Running => _context.Running;
+ public ulong TlsAddress => (ulong)_context.TpidrroEl0;
+
+ public ulong GetX(int index) => _context.GetX(index);
+
private int _locked;
+ public KThreadContext(IExecutionContext context)
+ {
+ _context = context;
+ }
+
public bool Lock()
{
return Interlocked.Exchange(ref _locked, 1) == 0;
diff --git a/Ryujinx.HLE/HOS/Kernel/Threading/KWritableEvent.cs b/Ryujinx.HLE/HOS/Kernel/Threading/KWritableEvent.cs
index 7aee0b57..b46122be 100644
--- a/Ryujinx.HLE/HOS/Kernel/Threading/KWritableEvent.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Threading/KWritableEvent.cs
@@ -1,4 +1,5 @@
using Ryujinx.HLE.HOS.Kernel.Common;
+using Ryujinx.Horizon.Common;
namespace Ryujinx.HLE.HOS.Kernel.Threading
{
@@ -16,7 +17,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
_parent.ReadableEvent.Signal();
}
- public KernelResult Clear()
+ public Result Clear()
{
return _parent.ReadableEvent.Clear();
}
diff --git a/Ryujinx.HLE/HOS/ProgramLoader.cs b/Ryujinx.HLE/HOS/ProgramLoader.cs
index beeb5ad6..b422fef7 100644
--- a/Ryujinx.HLE/HOS/ProgramLoader.cs
+++ b/Ryujinx.HLE/HOS/ProgramLoader.cs
@@ -9,6 +9,7 @@ using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Memory;
using Ryujinx.HLE.HOS.Kernel.Process;
using Ryujinx.HLE.Loaders.Executables;
+using Ryujinx.Horizon.Common;
using System;
using System.Linq;
using System.Runtime.InteropServices;
@@ -90,9 +91,9 @@ namespace Ryujinx.HLE.HOS
KMemoryRegionManager region = context.MemoryManager.MemoryRegions[(int)memoryRegion];
- KernelResult result = region.AllocatePages(out KPageList pageList, (ulong)codePagesCount);
+ Result result = region.AllocatePages(out KPageList pageList, (ulong)codePagesCount);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
Logger.Error?.Print(LogClass.Loader, $"Process initialization returned error \"{result}\".");
@@ -111,7 +112,7 @@ namespace Ryujinx.HLE.HOS
memoryRegion,
processContextFactory);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
Logger.Error?.Print(LogClass.Loader, $"Process initialization returned error \"{result}\".");
@@ -120,7 +121,7 @@ namespace Ryujinx.HLE.HOS
result = LoadIntoMemory(process, kip, codeBaseAddress);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
Logger.Error?.Print(LogClass.Loader, $"Process initialization returned error \"{result}\".");
@@ -131,7 +132,7 @@ namespace Ryujinx.HLE.HOS
result = process.Start(kip.Priority, (ulong)kip.StackSize);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
Logger.Error?.Print(LogClass.Loader, $"Process start returned error \"{result}\".");
@@ -230,19 +231,35 @@ namespace Ryujinx.HLE.HOS
context.Device.System.LibHacHorizonManager.InitializeApplicationClient(new ProgramId(programInfo.ProgramId), in npdm);
- KernelResult result;
+ Result result;
KResourceLimit resourceLimit = new KResourceLimit(context);
long applicationRgSize = (long)context.MemoryManager.MemoryRegions[(int)MemoryRegion.Application].Size;
- result = resourceLimit.SetLimitValue(LimitableResource.Memory, applicationRgSize);
- result |= resourceLimit.SetLimitValue(LimitableResource.Thread, 608);
- result |= resourceLimit.SetLimitValue(LimitableResource.Event, 700);
- result |= resourceLimit.SetLimitValue(LimitableResource.TransferMemory, 128);
- result |= resourceLimit.SetLimitValue(LimitableResource.Session, 894);
+ result = resourceLimit.SetLimitValue(LimitableResource.Memory, applicationRgSize);
- if (result != KernelResult.Success)
+ if (result.IsSuccess)
+ {
+ result = resourceLimit.SetLimitValue(LimitableResource.Thread, 608);
+ }
+
+ if (result.IsSuccess)
+ {
+ result = resourceLimit.SetLimitValue(LimitableResource.Event, 700);
+ }
+
+ if (result.IsSuccess)
+ {
+ result = resourceLimit.SetLimitValue(LimitableResource.TransferMemory, 128);
+ }
+
+ if (result.IsSuccess)
+ {
+ result = resourceLimit.SetLimitValue(LimitableResource.Session, 894);
+ }
+
+ if (result != Result.Success)
{
Logger.Error?.Print(LogClass.Loader, $"Process initialization failed setting resource limit values.");
@@ -273,7 +290,7 @@ namespace Ryujinx.HLE.HOS
memoryRegion,
processContextFactory);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
Logger.Error?.Print(LogClass.Loader, $"Process initialization returned error \"{result}\".");
@@ -288,7 +305,7 @@ namespace Ryujinx.HLE.HOS
result = LoadIntoMemory(process, executables[index], nsoBase[index]);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
Logger.Error?.Print(LogClass.Loader, $"Process initialization returned error \"{result}\".");
@@ -302,7 +319,7 @@ namespace Ryujinx.HLE.HOS
result = process.Start(meta.MainThreadPriority, meta.MainThreadStackSize);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
Logger.Error?.Print(LogClass.Loader, $"Process start returned error \"{result}\".");
@@ -322,18 +339,18 @@ namespace Ryujinx.HLE.HOS
return true;
}
- private static KernelResult LoadIntoMemory(KProcess process, IExecutable image, ulong baseAddress)
+ private static Result LoadIntoMemory(KProcess process, IExecutable image, ulong baseAddress)
{
- ulong textStart = baseAddress + (ulong)image.TextOffset;
- ulong roStart = baseAddress + (ulong)image.RoOffset;
- ulong dataStart = baseAddress + (ulong)image.DataOffset;
- ulong bssStart = baseAddress + (ulong)image.BssOffset;
+ ulong textStart = baseAddress + image.TextOffset;
+ ulong roStart = baseAddress + image.RoOffset;
+ ulong dataStart = baseAddress + image.DataOffset;
+ ulong bssStart = baseAddress + image.BssOffset;
ulong end = dataStart + (ulong)image.Data.Length;
if (image.BssSize != 0)
{
- end = bssStart + (ulong)image.BssSize;
+ end = bssStart + image.BssSize;
}
process.CpuMemory.Write(textStart, image.Text);
@@ -342,11 +359,11 @@ namespace Ryujinx.HLE.HOS
process.CpuMemory.Fill(bssStart, image.BssSize, 0);
- KernelResult SetProcessMemoryPermission(ulong address, ulong size, KMemoryPermission permission)
+ Result SetProcessMemoryPermission(ulong address, ulong size, KMemoryPermission permission)
{
if (size == 0)
{
- return KernelResult.Success;
+ return Result.Success;
}
size = BitUtils.AlignUp<ulong>(size, KPageTableBase.PageSize);
@@ -354,16 +371,16 @@ namespace Ryujinx.HLE.HOS
return process.MemoryManager.SetProcessMemoryPermission(address, size, permission);
}
- KernelResult result = SetProcessMemoryPermission(textStart, (ulong)image.Text.Length, KMemoryPermission.ReadAndExecute);
+ Result result = SetProcessMemoryPermission(textStart, (ulong)image.Text.Length, KMemoryPermission.ReadAndExecute);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
return result;
}
result = SetProcessMemoryPermission(roStart, (ulong)image.Ro.Length, KMemoryPermission.Read);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
return result;
}
diff --git a/Ryujinx.HLE/HOS/Services/Account/Acc/IAsyncContext.cs b/Ryujinx.HLE/HOS/Services/Account/Acc/IAsyncContext.cs
index b49a44e7..9a12e701 100644
--- a/Ryujinx.HLE/HOS/Services/Account/Acc/IAsyncContext.cs
+++ b/Ryujinx.HLE/HOS/Services/Account/Acc/IAsyncContext.cs
@@ -1,6 +1,6 @@
using Ryujinx.HLE.HOS.Ipc;
-using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Services.Account.Acc.AsyncContext;
+using Ryujinx.Horizon.Common;
using System;
namespace Ryujinx.HLE.HOS.Services.Account.Acc
@@ -18,7 +18,7 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc
// GetSystemEvent() -> handle<copy>
public ResultCode GetSystemEvent(ServiceCtx context)
{
- if (context.Process.HandleTable.GenerateHandle(AsyncExecution.SystemEvent.ReadableEvent, out int _systemEventHandle) != KernelResult.Success)
+ if (context.Process.HandleTable.GenerateHandle(AsyncExecution.SystemEvent.ReadableEvent, out int _systemEventHandle) != Result.Success)
{
throw new InvalidOperationException("Out of handles!");
}
diff --git a/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/LibraryAppletCreator/ILibraryAppletAccessor.cs b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/LibraryAppletCreator/ILibraryAppletAccessor.cs
index 405806c4..134566d9 100644
--- a/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/LibraryAppletCreator/ILibraryAppletAccessor.cs
+++ b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/LibraryAppletCreator/ILibraryAppletAccessor.cs
@@ -2,8 +2,8 @@
using Ryujinx.HLE.HOS.Applets;
using Ryujinx.HLE.HOS.Ipc;
using Ryujinx.HLE.HOS.Kernel;
-using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Threading;
+using Ryujinx.Horizon.Common;
using System;
namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.LibraryAppletCreator
@@ -68,7 +68,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Lib
{
if (_stateChangedEventHandle == 0)
{
- if (context.Process.HandleTable.GenerateHandle(_stateChangedEvent.ReadableEvent, out _stateChangedEventHandle) != KernelResult.Success)
+ if (context.Process.HandleTable.GenerateHandle(_stateChangedEvent.ReadableEvent, out _stateChangedEventHandle) != Result.Success)
{
throw new InvalidOperationException("Out of handles!");
}
@@ -178,7 +178,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Lib
{
if (_normalOutDataEventHandle == 0)
{
- if (context.Process.HandleTable.GenerateHandle(_normalOutDataEvent.ReadableEvent, out _normalOutDataEventHandle) != KernelResult.Success)
+ if (context.Process.HandleTable.GenerateHandle(_normalOutDataEvent.ReadableEvent, out _normalOutDataEventHandle) != Result.Success)
{
throw new InvalidOperationException("Out of handles!");
}
@@ -195,7 +195,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Lib
{
if (_interactiveOutDataEventHandle == 0)
{
- if (context.Process.HandleTable.GenerateHandle(_interactiveOutDataEvent.ReadableEvent, out _interactiveOutDataEventHandle) != KernelResult.Success)
+ if (context.Process.HandleTable.GenerateHandle(_interactiveOutDataEvent.ReadableEvent, out _interactiveOutDataEventHandle) != Result.Success)
{
throw new InvalidOperationException("Out of handles!");
}
diff --git a/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/ICommonStateGetter.cs b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/ICommonStateGetter.cs
index cb298fd4..b145a65d 100644
--- a/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/ICommonStateGetter.cs
+++ b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/ICommonStateGetter.cs
@@ -1,10 +1,10 @@
using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS.Ipc;
-using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Threading;
using Ryujinx.HLE.HOS.Services.Settings.Types;
using Ryujinx.HLE.HOS.Services.Vi.RootService.ApplicationDisplayService;
using Ryujinx.HLE.HOS.SystemState;
+using Ryujinx.Horizon.Common;
using System;
namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.SystemAppletProxy
@@ -38,7 +38,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
if (_messageEventHandle == 0)
{
- if (context.Process.HandleTable.GenerateHandle(messageEvent.ReadableEvent, out _messageEventHandle) != KernelResult.Success)
+ if (context.Process.HandleTable.GenerateHandle(messageEvent.ReadableEvent, out _messageEventHandle) != Result.Success)
{
throw new InvalidOperationException("Out of handles!");
}
@@ -211,7 +211,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
// NOTE: Original service calls IOperationModeManager::GetDefaultDisplayResolutionChangeEvent of omm service.
if (_displayResolutionChangedEventHandle == 0)
{
- if (context.Process.HandleTable.GenerateHandle(context.Device.System.DisplayResolutionChangeEvent.ReadableEvent, out _displayResolutionChangedEventHandle) != KernelResult.Success)
+ if (context.Process.HandleTable.GenerateHandle(context.Device.System.DisplayResolutionChangeEvent.ReadableEvent, out _displayResolutionChangedEventHandle) != Result.Success)
{
throw new InvalidOperationException("Out of handles!");
}
diff --git a/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/IDisplayController.cs b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/IDisplayController.cs
index d7816de9..7c03fc27 100644
--- a/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/IDisplayController.cs
+++ b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/IDisplayController.cs
@@ -1,7 +1,7 @@
using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS.Ipc;
-using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Memory;
+using Ryujinx.Horizon.Common;
using System;
namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.SystemAppletProxy
@@ -66,7 +66,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
return ResultCode.BufferAlreadyAcquired;
}
- if (context.Process.HandleTable.GenerateHandle(_transferMem, out int handle) != KernelResult.Success)
+ if (context.Process.HandleTable.GenerateHandle(_transferMem, out int handle) != Result.Success)
{
throw new InvalidOperationException("Out of handles!");
}
@@ -89,7 +89,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
return ResultCode.BufferAlreadyAcquired;
}
- if (context.Process.HandleTable.GenerateHandle(_transferMem, out int handle) != KernelResult.Success)
+ if (context.Process.HandleTable.GenerateHandle(_transferMem, out int handle) != Result.Success)
{
throw new InvalidOperationException("Out of handles!");
}
diff --git a/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/IHomeMenuFunctions.cs b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/IHomeMenuFunctions.cs
index 5c53c66f..2a9848dd 100644
--- a/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/IHomeMenuFunctions.cs
+++ b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/IHomeMenuFunctions.cs
@@ -1,7 +1,7 @@
using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS.Ipc;
-using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Threading;
+using Ryujinx.Horizon.Common;
using System;
namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.SystemAppletProxy
@@ -32,7 +32,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
{
if (_channelEventHandle == 0)
{
- if (context.Process.HandleTable.GenerateHandle(_channelEvent.ReadableEvent, out _channelEventHandle) != KernelResult.Success)
+ if (context.Process.HandleTable.GenerateHandle(_channelEvent.ReadableEvent, out _channelEventHandle) != Result.Success)
{
throw new InvalidOperationException("Out of handles!");
}
diff --git a/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/ISelfController.cs b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/ISelfController.cs
index 567bc264..39be7577 100644
--- a/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/ISelfController.cs
+++ b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/ISelfController.cs
@@ -1,8 +1,8 @@
using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS.Ipc;
-using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Threading;
using Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.SystemAppletProxy.Types;
+using Ryujinx.Horizon.Common;
using System;
namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.SystemAppletProxy
@@ -111,7 +111,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
if (_libraryAppletLaunchableEventHandle == 0)
{
- if (context.Process.HandleTable.GenerateHandle(_libraryAppletLaunchableEvent.ReadableEvent, out _libraryAppletLaunchableEventHandle) != KernelResult.Success)
+ if (context.Process.HandleTable.GenerateHandle(_libraryAppletLaunchableEvent.ReadableEvent, out _libraryAppletLaunchableEventHandle) != Result.Success)
{
throw new InvalidOperationException("Out of handles!");
}
@@ -378,7 +378,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
_accumulatedSuspendedTickChangedEvent.ReadableEvent.Signal();
- if (context.Process.HandleTable.GenerateHandle(_accumulatedSuspendedTickChangedEvent.ReadableEvent, out _accumulatedSuspendedTickChangedEventHandle) != KernelResult.Success)
+ if (context.Process.HandleTable.GenerateHandle(_accumulatedSuspendedTickChangedEvent.ReadableEvent, out _accumulatedSuspendedTickChangedEventHandle) != Result.Success)
{
throw new InvalidOperationException("Out of handles!");
}
diff --git a/Ryujinx.HLE/HOS/Services/Am/AppletOE/ApplicationProxyService/ApplicationProxy/IApplicationFunctions.cs b/Ryujinx.HLE/HOS/Services/Am/AppletOE/ApplicationProxyService/ApplicationProxy/IApplicationFunctions.cs
index 74068ad6..49331e21 100644
--- a/Ryujinx.HLE/HOS/Services/Am/AppletOE/ApplicationProxyService/ApplicationProxy/IApplicationFunctions.cs
+++ b/Ryujinx.HLE/HOS/Services/Am/AppletOE/ApplicationProxyService/ApplicationProxy/IApplicationFunctions.cs
@@ -1,4 +1,3 @@
-using LibHac;
using LibHac.Account;
using LibHac.Common;
using LibHac.Fs;
@@ -9,13 +8,13 @@ using Ryujinx.Common;
using Ryujinx.Common.Logging;
using Ryujinx.HLE.Exceptions;
using Ryujinx.HLE.HOS.Ipc;
-using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Memory;
using Ryujinx.HLE.HOS.Kernel.Threading;
using Ryujinx.HLE.HOS.Services.Am.AppletAE.Storage;
using Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.ApplicationProxy.Types;
using Ryujinx.HLE.HOS.Services.Sdb.Pdm.QueryService;
using Ryujinx.HLE.HOS.SystemState;
+using Ryujinx.Horizon.Common;
using System;
using System.Numerics;
using System.Threading;
@@ -43,7 +42,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati
private int _jitLoaded;
- private HorizonClient _horizon;
+ private LibHac.HorizonClient _horizon;
public IApplicationFunctions(Horizon system)
{
@@ -136,8 +135,8 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati
"No control file was found for this game. Using a dummy one instead. This may cause inaccuracies in some games.");
}
- HorizonClient hos = context.Device.System.LibHacHorizonManager.AmClient;
- Result result = hos.Fs.EnsureApplicationSaveData(out long requiredSize, applicationId, in control, in userId);
+ LibHac.HorizonClient hos = context.Device.System.LibHacHorizonManager.AmClient;
+ LibHac.Result result = hos.Fs.EnsureApplicationSaveData(out long requiredSize, applicationId, in control, in userId);
context.ResponseData.Write(requiredSize);
@@ -185,7 +184,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati
// SetTerminateResult(u32)
public ResultCode SetTerminateResult(ServiceCtx context)
{
- Result result = new Result(context.RequestData.ReadUInt32());
+ LibHac.Result result = new LibHac.Result(context.RequestData.ReadUInt32());
Logger.Info?.Print(LogClass.ServiceAm, $"Result = 0x{result.Value:x8} ({result.ToStringWithName()}).");
@@ -256,7 +255,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati
BlitStruct<ApplicationControlProperty> controlHolder = context.Device.Application.ControlData;
- Result result = _horizon.Fs.CreateApplicationCacheStorage(out long requiredSize,
+ LibHac.Result result = _horizon.Fs.CreateApplicationCacheStorage(out long requiredSize,
out CacheStorageTargetMedia storageTarget, applicationId, in controlHolder.Value, index, saveSize,
journalSize);
@@ -584,7 +583,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati
{
if (_gpuErrorDetectedSystemEventHandle == 0)
{
- if (context.Process.HandleTable.GenerateHandle(_gpuErrorDetectedSystemEvent.ReadableEvent, out _gpuErrorDetectedSystemEventHandle) != KernelResult.Success)
+ if (context.Process.HandleTable.GenerateHandle(_gpuErrorDetectedSystemEvent.ReadableEvent, out _gpuErrorDetectedSystemEventHandle) != Result.Success)
{
throw new InvalidOperationException("Out of handles!");
}
@@ -605,7 +604,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati
{
if (_friendInvitationStorageChannelEventHandle == 0)
{
- if (context.Process.HandleTable.GenerateHandle(_friendInvitationStorageChannelEvent.ReadableEvent, out _friendInvitationStorageChannelEventHandle) != KernelResult.Success)
+ if (context.Process.HandleTable.GenerateHandle(_friendInvitationStorageChannelEvent.ReadableEvent, out _friendInvitationStorageChannelEventHandle) != Result.Success)
{
throw new InvalidOperationException("Out of handles!");
}
@@ -636,7 +635,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati
{
if (_notificationStorageChannelEventHandle == 0)
{
- if (context.Process.HandleTable.GenerateHandle(_notificationStorageChannelEvent.ReadableEvent, out _notificationStorageChannelEventHandle) != KernelResult.Success)
+ if (context.Process.HandleTable.GenerateHandle(_notificationStorageChannelEvent.ReadableEvent, out _notificationStorageChannelEventHandle) != Result.Success)
{
throw new InvalidOperationException("Out of handles!");
}
@@ -653,7 +652,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati
{
if (_healthWarningDisappearedSystemEventHandle == 0)
{
- if (context.Process.HandleTable.GenerateHandle(_healthWarningDisappearedSystemEvent.ReadableEvent, out _healthWarningDisappearedSystemEventHandle) != KernelResult.Success)
+ if (context.Process.HandleTable.GenerateHandle(_healthWarningDisappearedSystemEvent.ReadableEvent, out _healthWarningDisappearedSystemEventHandle) != Result.Success)
{
throw new InvalidOperationException("Out of handles!");
}
diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioIn/AudioInServer.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioIn/AudioInServer.cs
index f9a9447f..4911b7f0 100644
--- a/Ryujinx.HLE/HOS/Services/Audio/AudioIn/AudioInServer.cs
+++ b/Ryujinx.HLE/HOS/Services/Audio/AudioIn/AudioInServer.cs
@@ -1,8 +1,8 @@
using Ryujinx.Audio.Common;
using Ryujinx.Cpu;
using Ryujinx.HLE.HOS.Ipc;
-using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Threading;
+using Ryujinx.Horizon.Common;
using Ryujinx.Memory;
using System;
using System.Runtime.InteropServices;
@@ -60,7 +60,7 @@ namespace Ryujinx.HLE.HOS.Services.Audio.AudioIn
{
KEvent bufferEvent = _impl.RegisterBufferEvent();
- if (context.Process.HandleTable.GenerateHandle(bufferEvent.ReadableEvent, out int handle) != KernelResult.Success)
+ if (context.Process.HandleTable.GenerateHandle(bufferEvent.ReadableEvent, out int handle) != Result.Success)
{
throw new InvalidOperationException("Out of handles!");
}
diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioOut/AudioOutServer.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioOut/AudioOutServer.cs
index aff08811..2d6908e3 100644
--- a/Ryujinx.HLE/HOS/Services/Audio/AudioOut/AudioOutServer.cs
+++ b/Ryujinx.HLE/HOS/Services/Audio/AudioOut/AudioOutServer.cs
@@ -1,8 +1,8 @@
using Ryujinx.Audio.Common;
using Ryujinx.Cpu;
using Ryujinx.HLE.HOS.Ipc;
-using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Threading;
+using Ryujinx.Horizon.Common;
using Ryujinx.Memory;
using System;
using System.Runtime.InteropServices;
@@ -60,7 +60,7 @@ namespace Ryujinx.HLE.HOS.Services.Audio.AudioOut
{
KEvent bufferEvent = _impl.RegisterBufferEvent();
- if (context.Process.HandleTable.GenerateHandle(bufferEvent.ReadableEvent, out int handle) != KernelResult.Success)
+ if (context.Process.HandleTable.GenerateHandle(bufferEvent.ReadableEvent, out int handle) != Result.Success)
{
throw new InvalidOperationException("Out of handles!");
}
diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/AudioDeviceServer.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/AudioDeviceServer.cs
index 1ef97ecc..e868ad5a 100644
--- a/Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/AudioDeviceServer.cs
+++ b/Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/AudioDeviceServer.cs
@@ -1,8 +1,8 @@
using Ryujinx.Common.Logging;
using Ryujinx.Cpu;
using Ryujinx.HLE.HOS.Ipc;
-using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Threading;
+using Ryujinx.Horizon.Common;
using System;
using System.Text;
@@ -115,7 +115,7 @@ namespace Ryujinx.HLE.HOS.Services.Audio.AudioRenderer
{
KEvent deviceSystemEvent = _impl.QueryAudioDeviceSystemEvent();
- if (context.Process.HandleTable.GenerateHandle(deviceSystemEvent.ReadableEvent, out int handle) != KernelResult.Success)
+ if (context.Process.HandleTable.GenerateHandle(deviceSystemEvent.ReadableEvent, out int handle) != Result.Success)
{
throw new InvalidOperationException("Out of handles!");
}
@@ -230,7 +230,7 @@ namespace Ryujinx.HLE.HOS.Services.Audio.AudioRenderer
{
KEvent deviceInputEvent = _impl.QueryAudioDeviceInputEvent();
- if (context.Process.HandleTable.GenerateHandle(deviceInputEvent.ReadableEvent, out int handle) != KernelResult.Success)
+ if (context.Process.HandleTable.GenerateHandle(deviceInputEvent.ReadableEvent, out int handle) != Result.Success)
{
throw new InvalidOperationException("Out of handles!");
}
@@ -248,7 +248,7 @@ namespace Ryujinx.HLE.HOS.Services.Audio.AudioRenderer
{
KEvent deviceOutputEvent = _impl.QueryAudioDeviceOutputEvent();
- if (context.Process.HandleTable.GenerateHandle(deviceOutputEvent.ReadableEvent, out int handle) != KernelResult.Success)
+ if (context.Process.HandleTable.GenerateHandle(deviceOutputEvent.ReadableEvent, out int handle) != Result.Success)
{
throw new InvalidOperationException("Out of handles!");
}
diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/AudioRendererServer.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/AudioRendererServer.cs
index b2ddb697..3843b408 100644
--- a/Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/AudioRendererServer.cs
+++ b/Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/AudioRendererServer.cs
@@ -1,7 +1,7 @@
using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS.Ipc;
-using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Threading;
+using Ryujinx.Horizon.Common;
using System;
using System.Buffers;
@@ -111,7 +111,7 @@ namespace Ryujinx.HLE.HOS.Services.Audio.AudioRenderer
if (result == ResultCode.Success)
{
- if (context.Process.HandleTable.GenerateHandle(systemEvent.ReadableEvent, out int handle) != KernelResult.Success)
+ if (context.Process.HandleTable.GenerateHandle(systemEvent.ReadableEvent, out int handle) != Result.Success)
{
throw new InvalidOperationException("Out of handles!");
}
diff --git a/Ryujinx.HLE/HOS/Services/Bcat/ServiceCreator/IDeliveryCacheProgressService.cs b/Ryujinx.HLE/HOS/Services/Bcat/ServiceCreator/IDeliveryCacheProgressService.cs
index 3e516d83..b176195d 100644
--- a/Ryujinx.HLE/HOS/Services/Bcat/ServiceCreator/IDeliveryCacheProgressService.cs
+++ b/Ryujinx.HLE/HOS/Services/Bcat/ServiceCreator/IDeliveryCacheProgressService.cs
@@ -1,9 +1,9 @@
using Ryujinx.Common.Logging;
using Ryujinx.Cpu;
using Ryujinx.HLE.HOS.Ipc;
-using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Threading;
using Ryujinx.HLE.HOS.Services.Bcat.ServiceCreator.Types;
+using Ryujinx.Horizon.Common;
using System;
namespace Ryujinx.HLE.HOS.Services.Bcat.ServiceCreator
@@ -24,7 +24,7 @@ namespace Ryujinx.HLE.HOS.Services.Bcat.ServiceCreator
{
if (_eventHandle == 0)
{
- if (context.Process.HandleTable.GenerateHandle(_event.ReadableEvent, out _eventHandle) != KernelResult.Success)
+ if (context.Process.HandleTable.GenerateHandle(_event.ReadableEvent, out _eventHandle) != Result.Success)
{
throw new InvalidOperationException("Out of handles!");
}
diff --git a/Ryujinx.HLE/HOS/Services/Bluetooth/IBluetoothDriver.cs b/Ryujinx.HLE/HOS/Services/Bluetooth/IBluetoothDriver.cs
index 5ce43495..65535ea1 100644
--- a/Ryujinx.HLE/HOS/Services/Bluetooth/IBluetoothDriver.cs
+++ b/Ryujinx.HLE/HOS/Services/Bluetooth/IBluetoothDriver.cs
@@ -1,8 +1,8 @@
using Ryujinx.HLE.HOS.Ipc;
-using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Threading;
using Ryujinx.HLE.HOS.Services.Bluetooth.BluetoothDriver;
using Ryujinx.HLE.HOS.Services.Settings;
+using Ryujinx.Horizon.Common;
using System;
namespace Ryujinx.HLE.HOS.Services.Bluetooth
@@ -30,7 +30,7 @@ namespace Ryujinx.HLE.HOS.Services.Bluetooth
{
BluetoothEventManager.InitializeBleDebugEvent = new KEvent(context.Device.System.KernelContext);
- if (context.Process.HandleTable.GenerateHandle(BluetoothEventManager.InitializeBleDebugEvent.ReadableEvent, out BluetoothEventManager.InitializeBleDebugEventHandle) != KernelResult.Success)
+ if (context.Process.HandleTable.GenerateHandle(BluetoothEventManager.InitializeBleDebugEvent.ReadableEvent, out BluetoothEventManager.InitializeBleDebugEventHandle) != Result.Success)
{
throw new InvalidOperationException("Out of handles!");
}
@@ -40,7 +40,7 @@ namespace Ryujinx.HLE.HOS.Services.Bluetooth
{
BluetoothEventManager.UnknownBleDebugEvent = new KEvent(context.Device.System.KernelContext);
- if (context.Process.HandleTable.GenerateHandle(BluetoothEventManager.UnknownBleDebugEvent.ReadableEvent, out BluetoothEventManager.UnknownBleDebugEventHandle) != KernelResult.Success)
+ if (context.Process.HandleTable.GenerateHandle(BluetoothEventManager.UnknownBleDebugEvent.ReadableEvent, out BluetoothEventManager.UnknownBleDebugEventHandle) != Result.Success)
{
throw new InvalidOperationException("Out of handles!");
}
@@ -50,7 +50,7 @@ namespace Ryujinx.HLE.HOS.Services.Bluetooth
{
BluetoothEventManager.RegisterBleDebugEvent = new KEvent(context.Device.System.KernelContext);
- if (context.Process.HandleTable.GenerateHandle(BluetoothEventManager.RegisterBleDebugEvent.ReadableEvent, out BluetoothEventManager.RegisterBleDebugEventHandle) != KernelResult.Success)
+ if (context.Process.HandleTable.GenerateHandle(BluetoothEventManager.RegisterBleDebugEvent.ReadableEvent, out BluetoothEventManager.RegisterBleDebugEventHandle) != Result.Success)
{
throw new InvalidOperationException("Out of handles!");
}
@@ -66,7 +66,7 @@ namespace Ryujinx.HLE.HOS.Services.Bluetooth
{
BluetoothEventManager.InitializeBleEvent = new KEvent(context.Device.System.KernelContext);
- if (context.Process.HandleTable.GenerateHandle(BluetoothEventManager.InitializeBleEvent.ReadableEvent, out BluetoothEventManager.InitializeBleEventHandle) != KernelResult.Success)
+ if (context.Process.HandleTable.GenerateHandle(BluetoothEventManager.InitializeBleEvent.ReadableEvent, out BluetoothEventManager.InitializeBleEventHandle) != Result.Success)
{
throw new InvalidOperationException("Out of handles!");
}
@@ -76,7 +76,7 @@ namespace Ryujinx.HLE.HOS.Services.Bluetooth
{
BluetoothEventManager.UnknownBleEvent = new KEvent(context.Device.System.KernelContext);
- if (context.Process.HandleTable.GenerateHandle(BluetoothEventManager.UnknownBleEvent.ReadableEvent, out BluetoothEventManager.UnknownBleEventHandle) != KernelResult.Success)
+ if (context.Process.HandleTable.GenerateHandle(BluetoothEventManager.UnknownBleEvent.ReadableEvent, out BluetoothEventManager.UnknownBleEventHandle) != Result.Success)
{
throw new InvalidOperationException("Out of handles!");
}
@@ -86,7 +86,7 @@ namespace Ryujinx.HLE.HOS.Services.Bluetooth
{
BluetoothEventManager.RegisterBleEvent = new KEvent(context.Device.System.KernelContext);
- if (context.Process.HandleTable.GenerateHandle(BluetoothEventManager.RegisterBleEvent.ReadableEvent, out BluetoothEventManager.RegisterBleEventHandle) != KernelResult.Success)
+ if (context.Process.HandleTable.GenerateHandle(BluetoothEventManager.RegisterBleEvent.ReadableEvent, out BluetoothEventManager.RegisterBleEventHandle) != Result.Success)
{
throw new InvalidOperationException("Out of handles!");
}
diff --git a/Ryujinx.HLE/HOS/Services/BluetoothManager/BtmUser/IBtmUserCore.cs b/Ryujinx.HLE/HOS/Services/BluetoothManager/BtmUser/IBtmUserCore.cs
index 8f138652..026b5bf1 100644
--- a/Ryujinx.HLE/HOS/Services/BluetoothManager/BtmUser/IBtmUserCore.cs
+++ b/Ryujinx.HLE/HOS/Services/BluetoothManager/BtmUser/IBtmUserCore.cs
@@ -1,7 +1,7 @@
using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS.Ipc;
-using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Threading;
+using Ryujinx.Horizon.Common;
namespace Ryujinx.HLE.HOS.Services.BluetoothManager.BtmUser
{
@@ -25,7 +25,7 @@ namespace Ryujinx.HLE.HOS.Services.BluetoothManager.BtmUser
// AcquireBleScanEvent() -> (byte<1>, handle<copy>)
public ResultCode AcquireBleScanEvent(ServiceCtx context)
{
- KernelResult result = KernelResult.Success;
+ Result result = Result.Success;
if (_bleScanEventHandle == 0)
{
@@ -33,7 +33,7 @@ namespace Ryujinx.HLE.HOS.Services.BluetoothManager.BtmUser
result = context.Process.HandleTable.GenerateHandle(_bleScanEvent.ReadableEvent, out _bleScanEventHandle);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
// NOTE: We use a Logging instead of an exception because the call return a boolean if succeed or not.
Logger.Error?.Print(LogClass.ServiceBsd, "Out of handles!");
@@ -42,7 +42,7 @@ namespace Ryujinx.HLE.HOS.Services.BluetoothManager.BtmUser
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_bleScanEventHandle);
- context.ResponseData.Write(result == KernelResult.Success ? 1 : 0);
+ context.ResponseData.Write(result == Result.Success ? 1 : 0);
return ResultCode.Success;
}
@@ -51,7 +51,7 @@ namespace Ryujinx.HLE.HOS.Services.BluetoothManager.BtmUser
// AcquireBleConnectionEvent() -> (byte<1>, handle<copy>)
public ResultCode AcquireBleConnectionEvent(ServiceCtx context)
{
- KernelResult result = KernelResult.Success;
+ Result result = Result.Success;
if (_bleConnectionEventHandle == 0)
{
@@ -59,7 +59,7 @@ namespace Ryujinx.HLE.HOS.Services.BluetoothManager.BtmUser
result = context.Process.HandleTable.GenerateHandle(_bleConnectionEvent.ReadableEvent, out _bleConnectionEventHandle);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
// NOTE: We use a Logging instead of an exception because the call return a boolean if succeed or not.
Logger.Error?.Print(LogClass.ServiceBsd, "Out of handles!");
@@ -68,7 +68,7 @@ namespace Ryujinx.HLE.HOS.Services.BluetoothManager.BtmUser
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_bleConnectionEventHandle);
- context.ResponseData.Write(result == KernelResult.Success ? 1 : 0);
+ context.ResponseData.Write(result == Result.Success ? 1 : 0);
return ResultCode.Success;
}
@@ -77,7 +77,7 @@ namespace Ryujinx.HLE.HOS.Services.BluetoothManager.BtmUser
// AcquireBleServiceDiscoveryEvent() -> (byte<1>, handle<copy>)
public ResultCode AcquireBleServiceDiscoveryEvent(ServiceCtx context)
{
- KernelResult result = KernelResult.Success;
+ Result result = Result.Success;
if (_bleServiceDiscoveryEventHandle == 0)
{
@@ -85,7 +85,7 @@ namespace Ryujinx.HLE.HOS.Services.BluetoothManager.BtmUser
result = context.Process.HandleTable.GenerateHandle(_bleServiceDiscoveryEvent.ReadableEvent, out _bleServiceDiscoveryEventHandle);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
// NOTE: We use a Logging instead of an exception because the call return a boolean if succeed or not.
Logger.Error?.Print(LogClass.ServiceBsd, "Out of handles!");
@@ -94,7 +94,7 @@ namespace Ryujinx.HLE.HOS.Services.BluetoothManager.BtmUser
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_bleServiceDiscoveryEventHandle);
- context.ResponseData.Write(result == KernelResult.Success ? 1 : 0);
+ context.ResponseData.Write(result == Result.Success ? 1 : 0);
return ResultCode.Success;
}
@@ -103,7 +103,7 @@ namespace Ryujinx.HLE.HOS.Services.BluetoothManager.BtmUser
// AcquireBleMtuConfigEvent() -> (byte<1>, handle<copy>)
public ResultCode AcquireBleMtuConfigEvent(ServiceCtx context)
{
- KernelResult result = KernelResult.Success;
+ Result result = Result.Success;
if (_bleMtuConfigEventHandle == 0)
{
@@ -111,7 +111,7 @@ namespace Ryujinx.HLE.HOS.Services.BluetoothManager.BtmUser
result = context.Process.HandleTable.GenerateHandle(_bleMtuConfigEvent.ReadableEvent, out _bleMtuConfigEventHandle);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
// NOTE: We use a Logging instead of an exception because the call return a boolean if succeed or not.
Logger.Error?.Print(LogClass.ServiceBsd, "Out of handles!");
@@ -120,7 +120,7 @@ namespace Ryujinx.HLE.HOS.Services.BluetoothManager.BtmUser
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_bleMtuConfigEventHandle);
- context.ResponseData.Write(result == KernelResult.Success ? 1 : 0);
+ context.ResponseData.Write(result == Result.Success ? 1 : 0);
return ResultCode.Success;
}
diff --git a/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/IFriendService.cs b/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/IFriendService.cs
index 8159d091..17a33b79 100644
--- a/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/IFriendService.cs
+++ b/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/IFriendService.cs
@@ -4,12 +4,11 @@ using Ryujinx.Common.Logging;
using Ryujinx.Common.Memory;
using Ryujinx.Common.Utilities;
using Ryujinx.HLE.HOS.Ipc;
-using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Threading;
using Ryujinx.HLE.HOS.Services.Account.Acc;
using Ryujinx.HLE.HOS.Services.Friend.ServiceCreator.FriendService;
+using Ryujinx.Horizon.Common;
using System;
-using System.IO;
using System.Runtime.InteropServices;
namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator
@@ -33,7 +32,7 @@ namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator
_completionEvent = new KEvent(context.Device.System.KernelContext);
}
- if (context.Process.HandleTable.GenerateHandle(_completionEvent.ReadableEvent, out int completionEventHandle) != KernelResult.Success)
+ if (context.Process.HandleTable.GenerateHandle(_completionEvent.ReadableEvent, out int completionEventHandle) != Result.Success)
{
throw new InvalidOperationException("Out of handles!");
}
diff --git a/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/INotificationService.cs b/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/INotificationService.cs
index f5614ddd..65cbd38e 100644
--- a/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/INotificationService.cs
+++ b/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/INotificationService.cs
@@ -1,9 +1,9 @@
using Ryujinx.Common;
using Ryujinx.HLE.HOS.Ipc;
-using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Threading;
using Ryujinx.HLE.HOS.Services.Account.Acc;
using Ryujinx.HLE.HOS.Services.Friend.ServiceCreator.NotificationService;
+using Ryujinx.Horizon.Common;
using System;
using System.Collections.Generic;
@@ -43,7 +43,7 @@ namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator
{
if (_notificationEventHandle == 0)
{
- if (context.Process.HandleTable.GenerateHandle(_notificationEvent.ReadableEvent, out _notificationEventHandle) != KernelResult.Success)
+ if (context.Process.HandleTable.GenerateHandle(_notificationEvent.ReadableEvent, out _notificationEventHandle) != Result.Success)
{
throw new InvalidOperationException("Out of handles!");
}
diff --git a/Ryujinx.HLE/HOS/Services/Hid/HidServer/IAppletResource.cs b/Ryujinx.HLE/HOS/Services/Hid/HidServer/IAppletResource.cs
index b38b25c3..29ee1706 100644
--- a/Ryujinx.HLE/HOS/Services/Hid/HidServer/IAppletResource.cs
+++ b/Ryujinx.HLE/HOS/Services/Hid/HidServer/IAppletResource.cs
@@ -1,6 +1,6 @@
using Ryujinx.HLE.HOS.Ipc;
-using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Memory;
+using Ryujinx.Horizon.Common;
using System;
namespace Ryujinx.HLE.HOS.Services.Hid.HidServer
@@ -21,7 +21,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid.HidServer
{
if (_hidSharedMemHandle == 0)
{
- if (context.Process.HandleTable.GenerateHandle(_hidSharedMem, out _hidSharedMemHandle) != KernelResult.Success)
+ if (context.Process.HandleTable.GenerateHandle(_hidSharedMem, out _hidSharedMemHandle) != Result.Success)
{
throw new InvalidOperationException("Out of handles!");
}
diff --git a/Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs b/Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs
index 957cd553..d347a3bd 100644
--- a/Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs
+++ b/Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs
@@ -1,11 +1,11 @@
using Ryujinx.Common;
using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS.Ipc;
-using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Threading;
using Ryujinx.HLE.HOS.Services.Hid.HidServer;
using Ryujinx.HLE.HOS.Services.Hid.Types;
using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Npad;
+using Ryujinx.Horizon.Common;
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
@@ -55,7 +55,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
// TODO: signal event at right place
_xpadIdEvent.ReadableEvent.Signal();
-
+
_vibrationPermitted = true;
}
@@ -170,7 +170,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
{
long xpadId = context.RequestData.ReadInt64();
- if (context.Process.HandleTable.GenerateHandle(_xpadIdEvent.ReadableEvent, out _xpadIdEventHandle) != KernelResult.Success)
+ if (context.Process.HandleTable.GenerateHandle(_xpadIdEvent.ReadableEvent, out _xpadIdEventHandle) != Result.Success)
{
throw new InvalidOperationException("Out of handles!");
}
@@ -761,7 +761,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
long npadStyleSet = context.RequestData.ReadInt64();
KEvent evnt = context.Device.Hid.Npads.GetStyleSetUpdateEvent(npadId);
- if (context.Process.HandleTable.GenerateHandle(evnt.ReadableEvent, out int handle) != KernelResult.Success)
+ if (context.Process.HandleTable.GenerateHandle(evnt.ReadableEvent, out int handle) != Result.Success)
{
throw new InvalidOperationException("Out of handles!");
}
@@ -1597,7 +1597,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
{
int palmaConnectionHandle = context.RequestData.ReadInt32();
- if (context.Process.HandleTable.GenerateHandle(_palmaOperationCompleteEvent.ReadableEvent, out int handle) != KernelResult.Success)
+ if (context.Process.HandleTable.GenerateHandle(_palmaOperationCompleteEvent.ReadableEvent, out int handle) != Result.Success)
{
throw new InvalidOperationException("Out of handles!");
}
diff --git a/Ryujinx.HLE/HOS/Services/Hid/Irs/IIrSensorServer.cs b/Ryujinx.HLE/HOS/Services/Hid/Irs/IIrSensorServer.cs
index a0bd6375..7af06431 100644
--- a/Ryujinx.HLE/HOS/Services/Hid/Irs/IIrSensorServer.cs
+++ b/Ryujinx.HLE/HOS/Services/Hid/Irs/IIrSensorServer.cs
@@ -1,9 +1,9 @@
using Ryujinx.Common;
using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS.Ipc;
-using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Services.Hid.HidServer;
using Ryujinx.HLE.HOS.Services.Hid.Irs.Types;
+using Ryujinx.Horizon.Common;
using System;
namespace Ryujinx.HLE.HOS.Services.Hid.Irs
@@ -50,7 +50,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid.Irs
if (_irsensorSharedMemoryHandle == 0)
{
- if (context.Process.HandleTable.GenerateHandle(context.Device.System.IirsSharedMem, out _irsensorSharedMemoryHandle) != KernelResult.Success)
+ if (context.Process.HandleTable.GenerateHandle(context.Device.System.IirsSharedMem, out _irsensorSharedMemoryHandle) != Result.Success)
{
throw new InvalidOperationException("Out of handles!");
}
@@ -172,8 +172,8 @@ namespace Ryujinx.HLE.HOS.Services.Hid.Irs
{
NpadIdType npadIdType = (NpadIdType)context.RequestData.ReadUInt32();
- if (npadIdType > NpadIdType.Player8 &&
- npadIdType != NpadIdType.Unknown &&
+ if (npadIdType > NpadIdType.Player8 &&
+ npadIdType != NpadIdType.Unknown &&
npadIdType != NpadIdType.Handheld)
{
return ResultCode.NpadIdOutOfRange;
@@ -183,7 +183,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid.Irs
context.ResponseData.Write((int)irCameraHandle);
- // NOTE: If the irCameraHandle pointer is null this error is returned, Doesn't occur in our case.
+ // NOTE: If the irCameraHandle pointer is null this error is returned, Doesn't occur in our case.
// return ResultCode.HandlePointerIsNull;
return ResultCode.Success;
diff --git a/Ryujinx.HLE/HOS/Services/Ldn/UserServiceCreator/IUserLocalCommunicationService.cs b/Ryujinx.HLE/HOS/Services/Ldn/UserServiceCreator/IUserLocalCommunicationService.cs
index dd3dad59..0c223c06 100644
--- a/Ryujinx.HLE/HOS/Services/Ldn/UserServiceCreator/IUserLocalCommunicationService.cs
+++ b/Ryujinx.HLE/HOS/Services/Ldn/UserServiceCreator/IUserLocalCommunicationService.cs
@@ -1,6 +1,6 @@
using Ryujinx.HLE.HOS.Ipc;
-using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Services.Ldn.Types;
+using Ryujinx.Horizon.Common;
using System;
using System.Net;
@@ -47,7 +47,7 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator
{
if (_stateChangeEventHandle == 0)
{
- if (context.Process.HandleTable.GenerateHandle(_networkInterface.StateChangeEvent.ReadableEvent, out _stateChangeEventHandle) != KernelResult.Success)
+ if (context.Process.HandleTable.GenerateHandle(_networkInterface.StateChangeEvent.ReadableEvent, out _stateChangeEventHandle) != Result.Success)
{
throw new InvalidOperationException("Out of handles!");
}
diff --git a/Ryujinx.HLE/HOS/Services/Nfc/Nfp/NfpManager/INfp.cs b/Ryujinx.HLE/HOS/Services/Nfc/Nfp/NfpManager/INfp.cs
index f4ad0366..a7f2dbb8 100644
--- a/Ryujinx.HLE/HOS/Services/Nfc/Nfp/NfpManager/INfp.cs
+++ b/Ryujinx.HLE/HOS/Services/Nfc/Nfp/NfpManager/INfp.cs
@@ -2,11 +2,11 @@
using Ryujinx.Cpu;
using Ryujinx.HLE.Exceptions;
using Ryujinx.HLE.HOS.Ipc;
-using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Threading;
using Ryujinx.HLE.HOS.Services.Hid;
using Ryujinx.HLE.HOS.Services.Hid.HidServer;
using Ryujinx.HLE.HOS.Services.Nfc.Nfp.NfpManager;
+using Ryujinx.Horizon.Common;
using System;
using System.Buffers.Binary;
using System.Globalization;
@@ -851,7 +851,7 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
{
context.Device.System.NfpDevices[i].ActivateEvent = new KEvent(context.Device.System.KernelContext);
- if (context.Process.HandleTable.GenerateHandle(context.Device.System.NfpDevices[i].ActivateEvent.ReadableEvent, out int activateEventHandle) != KernelResult.Success)
+ if (context.Process.HandleTable.GenerateHandle(context.Device.System.NfpDevices[i].ActivateEvent.ReadableEvent, out int activateEventHandle) != Result.Success)
{
throw new InvalidOperationException("Out of handles!");
}
@@ -877,7 +877,7 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
{
context.Device.System.NfpDevices[i].DeactivateEvent = new KEvent(context.Device.System.KernelContext);
- if (context.Process.HandleTable.GenerateHandle(context.Device.System.NfpDevices[i].DeactivateEvent.ReadableEvent, out int deactivateEventHandle) != KernelResult.Success)
+ if (context.Process.HandleTable.GenerateHandle(context.Device.System.NfpDevices[i].DeactivateEvent.ReadableEvent, out int deactivateEventHandle) != Result.Success)
{
throw new InvalidOperationException("Out of handles!");
}
@@ -960,7 +960,7 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
{
_availabilityChangeEvent = new KEvent(context.Device.System.KernelContext);
- if (context.Process.HandleTable.GenerateHandle(_availabilityChangeEvent.ReadableEvent, out int availabilityChangeEventHandle) != KernelResult.Success)
+ if (context.Process.HandleTable.GenerateHandle(_availabilityChangeEvent.ReadableEvent, out int availabilityChangeEventHandle) != Result.Success)
{
throw new InvalidOperationException("Out of handles!");
}
diff --git a/Ryujinx.HLE/HOS/Services/Nifm/StaticService/IRequest.cs b/Ryujinx.HLE/HOS/Services/Nifm/StaticService/IRequest.cs
index 7a3fdabd..88757bee 100644
--- a/Ryujinx.HLE/HOS/Services/Nifm/StaticService/IRequest.cs
+++ b/Ryujinx.HLE/HOS/Services/Nifm/StaticService/IRequest.cs
@@ -1,7 +1,7 @@
using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS.Ipc;
-using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Threading;
+using Ryujinx.Horizon.Common;
using System;
namespace Ryujinx.HLE.HOS.Services.Nifm.StaticService
@@ -66,7 +66,7 @@ namespace Ryujinx.HLE.HOS.Services.Nifm.StaticService
{
if (_event0Handle == 0)
{
- if (context.Process.HandleTable.GenerateHandle(_event0.ReadableEvent, out _event0Handle) != KernelResult.Success)
+ if (context.Process.HandleTable.GenerateHandle(_event0.ReadableEvent, out _event0Handle) != Result.Success)
{
throw new InvalidOperationException("Out of handles!");
}
@@ -74,7 +74,7 @@ namespace Ryujinx.HLE.HOS.Services.Nifm.StaticService
if (_event1Handle == 0)
{
- if (context.Process.HandleTable.GenerateHandle(_event1.ReadableEvent, out _event1Handle) != KernelResult.Success)
+ if (context.Process.HandleTable.GenerateHandle(_event1.ReadableEvent, out _event1Handle) != Result.Success)
{
throw new InvalidOperationException("Out of handles!");
}
diff --git a/Ryujinx.HLE/HOS/Services/Nim/IShopServiceAccessor.cs b/Ryujinx.HLE/HOS/Services/Nim/IShopServiceAccessor.cs
index 919639b6..d6843d12 100644
--- a/Ryujinx.HLE/HOS/Services/Nim/IShopServiceAccessor.cs
+++ b/Ryujinx.HLE/HOS/Services/Nim/IShopServiceAccessor.cs
@@ -1,8 +1,8 @@
using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS.Ipc;
-using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Threading;
using Ryujinx.HLE.HOS.Services.Nim.ShopServiceAccessServerInterface.ShopServiceAccessServer.ShopServiceAccessor;
+using Ryujinx.Horizon.Common;
using System;
namespace Ryujinx.HLE.HOS.Services.Nim.ShopServiceAccessServerInterface.ShopServiceAccessServer
@@ -26,7 +26,7 @@ namespace Ryujinx.HLE.HOS.Services.Nim.ShopServiceAccessServerInterface.ShopServ
if (_eventHandle == 0)
{
- if (context.Process.HandleTable.GenerateHandle(_event.ReadableEvent, out _eventHandle) != KernelResult.Success)
+ if (context.Process.HandleTable.GenerateHandle(_event.ReadableEvent, out _eventHandle) != Result.Success)
{
throw new InvalidOperationException("Out of handles!");
}
diff --git a/Ryujinx.HLE/HOS/Services/Nim/Ntc/StaticService/IEnsureNetworkClockAvailabilityService.cs b/Ryujinx.HLE/HOS/Services/Nim/Ntc/StaticService/IEnsureNetworkClockAvailabilityService.cs
index fb31bd1f..3b533f0f 100644
--- a/Ryujinx.HLE/HOS/Services/Nim/Ntc/StaticService/IEnsureNetworkClockAvailabilityService.cs
+++ b/Ryujinx.HLE/HOS/Services/Nim/Ntc/StaticService/IEnsureNetworkClockAvailabilityService.cs
@@ -1,12 +1,12 @@
using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS.Ipc;
-using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Threading;
+using Ryujinx.Horizon.Common;
using System;
namespace Ryujinx.HLE.HOS.Services.Nim.Ntc.StaticService
{
- class IEnsureNetworkClockAvailabilityService : IpcService
+ class IEnsureNetworkClockAvailabilityService : IpcService
{
private KEvent _finishNotificationEvent;
private ResultCode _taskResultCode;
@@ -43,7 +43,7 @@ namespace Ryujinx.HLE.HOS.Services.Nim.Ntc.StaticService
// GetFinishNotificationEvent() -> handle<copy>
public ResultCode GetFinishNotificationEvent(ServiceCtx context)
{
- if (context.Process.HandleTable.GenerateHandle(_finishNotificationEvent.ReadableEvent, out int finishNotificationEventHandle) != KernelResult.Success)
+ if (context.Process.HandleTable.GenerateHandle(_finishNotificationEvent.ReadableEvent, out int finishNotificationEventHandle) != Result.Success)
{
throw new InvalidOperationException("Out of handles!");
}
diff --git a/Ryujinx.HLE/HOS/Services/Ns/Aoc/IAddOnContentManager.cs b/Ryujinx.HLE/HOS/Services/Ns/Aoc/IAddOnContentManager.cs
index 53866a6b..0d552003 100644
--- a/Ryujinx.HLE/HOS/Services/Ns/Aoc/IAddOnContentManager.cs
+++ b/Ryujinx.HLE/HOS/Services/Ns/Aoc/IAddOnContentManager.cs
@@ -1,7 +1,7 @@
using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS.Ipc;
-using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Threading;
+using Ryujinx.Horizon.Common;
using System;
using System.Collections.Generic;
@@ -129,7 +129,7 @@ namespace Ryujinx.HLE.HOS.Services.Ns.Aoc
// TODO: Found where stored value is used.
ResultCode resultCode = GetAddOnContentBaseIdFromTitleId(context, context.Device.Application.TitleId);
-
+
if (resultCode != ResultCode.Success)
{
return resultCode;
@@ -327,7 +327,7 @@ namespace Ryujinx.HLE.HOS.Services.Ns.Aoc
{
if (_addOnContentListChangedEventHandle == 0)
{
- if (context.Process.HandleTable.GenerateHandle(_addOnContentListChangedEvent.ReadableEvent, out _addOnContentListChangedEventHandle) != KernelResult.Success)
+ if (context.Process.HandleTable.GenerateHandle(_addOnContentListChangedEvent.ReadableEvent, out _addOnContentListChangedEventHandle) != Result.Success)
{
throw new InvalidOperationException("Out of handles!");
}
diff --git a/Ryujinx.HLE/HOS/Services/Ns/Aoc/IPurchaseEventManager.cs b/Ryujinx.HLE/HOS/Services/Ns/Aoc/IPurchaseEventManager.cs
index 9b65e0f9..5ec43a3f 100644
--- a/Ryujinx.HLE/HOS/Services/Ns/Aoc/IPurchaseEventManager.cs
+++ b/Ryujinx.HLE/HOS/Services/Ns/Aoc/IPurchaseEventManager.cs
@@ -1,7 +1,7 @@
using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS.Ipc;
-using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Threading;
+using Ryujinx.Horizon.Common;
using System;
namespace Ryujinx.HLE.HOS.Services.Ns.Aoc
@@ -38,7 +38,7 @@ namespace Ryujinx.HLE.HOS.Services.Ns.Aoc
// GetPurchasedEventReadableHandle() -> handle<copy, event>
public ResultCode GetPurchasedEventReadableHandle(ServiceCtx context)
{
- if (context.Process.HandleTable.GenerateHandle(_purchasedEvent.ReadableEvent, out int purchasedEventReadableHandle) != KernelResult.Success)
+ if (context.Process.HandleTable.GenerateHandle(_purchasedEvent.ReadableEvent, out int purchasedEventReadableHandle) != Result.Success)
{
throw new InvalidOperationException("Out of handles!");
}
diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/NvHostGpuDeviceFile.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/NvHostGpuDeviceFile.cs
index 5bc3e3bd..f33cc460 100644
--- a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/NvHostGpuDeviceFile.cs
+++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/NvHostGpuDeviceFile.cs
@@ -1,6 +1,6 @@
-using Ryujinx.HLE.HOS.Kernel.Common;
-using Ryujinx.HLE.HOS.Kernel.Threading;
+using Ryujinx.HLE.HOS.Kernel.Threading;
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel.Types;
+using Ryujinx.Horizon.Common;
using Ryujinx.Memory;
using System;
@@ -27,7 +27,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel
{
KEvent evnt = new KEvent(context.Device.System.KernelContext);
- if (context.Process.HandleTable.GenerateHandle(evnt.ReadableEvent, out handle) != KernelResult.Success)
+ if (context.Process.HandleTable.GenerateHandle(evnt.ReadableEvent, out handle) != Result.Success)
{
throw new InvalidOperationException("Out of handles!");
}
diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrl/Types/NvHostEvent.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrl/Types/NvHostEvent.cs
index d332bb04..ac5512ed 100644
--- a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrl/Types/NvHostEvent.cs
+++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrl/Types/NvHostEvent.cs
@@ -2,9 +2,9 @@ using Ryujinx.Common.Logging;
using Ryujinx.Graphics.Gpu;
using Ryujinx.Graphics.Gpu.Synchronization;
using Ryujinx.HLE.HOS.Kernel;
-using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Threading;
using Ryujinx.HLE.HOS.Services.Nv.Types;
+using Ryujinx.Horizon.Common;
using System;
using System.Threading;
@@ -40,7 +40,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrl
Event = new KEvent(system.KernelContext);
- if (KernelStatic.GetCurrentProcess().HandleTable.GenerateHandle(Event.ReadableEvent, out EventHandle) != KernelResult.Success)
+ if (KernelStatic.GetCurrentProcess().HandleTable.GenerateHandle(Event.ReadableEvent, out EventHandle) != Result.Success)
{
throw new InvalidOperationException("Out of handles!");
}
diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrlGpu/NvHostCtrlGpuDeviceFile.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrlGpu/NvHostCtrlGpuDeviceFile.cs
index f1a6570b..d6a8e29f 100644
--- a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrlGpu/NvHostCtrlGpuDeviceFile.cs
+++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrlGpu/NvHostCtrlGpuDeviceFile.cs
@@ -1,7 +1,7 @@
using Ryujinx.Common.Logging;
-using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Threading;
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrlGpu.Types;
+using Ryujinx.Horizon.Common;
using Ryujinx.Memory;
using System;
using System.Diagnostics;
@@ -99,7 +99,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrlGpu
if (targetEvent != null)
{
- if (Context.Process.HandleTable.GenerateHandle(targetEvent.ReadableEvent, out eventHandle) != KernelResult.Success)
+ if (Context.Process.HandleTable.GenerateHandle(targetEvent.ReadableEvent, out eventHandle) != Result.Success)
{
throw new InvalidOperationException("Out of handles!");
}
diff --git a/Ryujinx.HLE/HOS/Services/Pcv/Clkrst/IClkrstManager.cs b/Ryujinx.HLE/HOS/Services/Pcv/Clkrst/IClkrstManager.cs
index 8c96c4ad..94ab49ca 100644
--- a/Ryujinx.HLE/HOS/Services/Pcv/Clkrst/IClkrstManager.cs
+++ b/Ryujinx.HLE/HOS/Services/Pcv/Clkrst/IClkrstManager.cs
@@ -1,7 +1,7 @@
using Ryujinx.HLE.HOS.Ipc;
-using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Services.Pcv.Clkrst.ClkrstManager;
using Ryujinx.HLE.HOS.Services.Pcv.Types;
+using Ryujinx.Horizon.Common;
using System;
namespace Ryujinx.HLE.HOS.Services.Pcv.Clkrst
@@ -34,7 +34,7 @@ namespace Ryujinx.HLE.HOS.Services.Pcv.Clkrst
{
if (_moduleStateTableEventHandle == 0)
{
- if (context.Process.HandleTable.GenerateHandle(context.Device.System.IirsSharedMem, out _moduleStateTableEventHandle) != KernelResult.Success)
+ if (context.Process.HandleTable.GenerateHandle(context.Device.System.IirsSharedMem, out _moduleStateTableEventHandle) != Result.Success)
{
throw new InvalidOperationException("Out of handles!");
}
diff --git a/Ryujinx.HLE/HOS/Services/Pm/IDebugMonitorInterface.cs b/Ryujinx.HLE/HOS/Services/Pm/IDebugMonitorInterface.cs
index 4b0df9b7..c9c6354d 100644
--- a/Ryujinx.HLE/HOS/Services/Pm/IDebugMonitorInterface.cs
+++ b/Ryujinx.HLE/HOS/Services/Pm/IDebugMonitorInterface.cs
@@ -1,7 +1,7 @@
using Ryujinx.HLE.HOS.Ipc;
using Ryujinx.HLE.HOS.Kernel;
-using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Process;
+using Ryujinx.Horizon.Common;
namespace Ryujinx.HLE.HOS.Services.Pm
{
@@ -18,7 +18,7 @@ namespace Ryujinx.HLE.HOS.Services.Pm
KProcess process = KernelStatic.GetProcessByPid(pid);
- if (context.Process.HandleTable.GenerateHandle(process, out int processHandle) != KernelResult.Success)
+ if (context.Process.HandleTable.GenerateHandle(process, out int processHandle) != Result.Success)
{
throw new System.Exception("Out of handles!");
}
diff --git a/Ryujinx.HLE/HOS/Services/Ptm/Psm/IPsmSession.cs b/Ryujinx.HLE/HOS/Services/Ptm/Psm/IPsmSession.cs
index 6015c6a4..9b4e996d 100644
--- a/Ryujinx.HLE/HOS/Services/Ptm/Psm/IPsmSession.cs
+++ b/Ryujinx.HLE/HOS/Services/Ptm/Psm/IPsmSession.cs
@@ -1,7 +1,7 @@
using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS.Ipc;
-using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Threading;
+using Ryujinx.Horizon.Common;
namespace Ryujinx.HLE.HOS.Services.Ptm.Psm
{
@@ -22,11 +22,11 @@ namespace Ryujinx.HLE.HOS.Services.Ptm.Psm
{
if (_stateChangeEventHandle == -1)
{
- KernelResult resultCode = context.Process.HandleTable.GenerateHandle(_stateChangeEvent.ReadableEvent, out _stateChangeEventHandle);
+ Result resultCode = context.Process.HandleTable.GenerateHandle(_stateChangeEvent.ReadableEvent, out _stateChangeEventHandle);
- if (resultCode != KernelResult.Success)
+ if (resultCode != Result.Success)
{
- return (ResultCode)resultCode;
+ return (ResultCode)resultCode.ErrorCode;
}
}
diff --git a/Ryujinx.HLE/HOS/Services/Ro/IRoInterface.cs b/Ryujinx.HLE/HOS/Services/Ro/IRoInterface.cs
index 36e1078f..263e1c4c 100644
--- a/Ryujinx.HLE/HOS/Services/Ro/IRoInterface.cs
+++ b/Ryujinx.HLE/HOS/Services/Ro/IRoInterface.cs
@@ -1,10 +1,10 @@
using LibHac.Tools.FsSystem;
using Ryujinx.Common;
using Ryujinx.Cpu;
-using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Memory;
using Ryujinx.HLE.HOS.Kernel.Process;
using Ryujinx.HLE.Loaders.Executables;
+using Ryujinx.Horizon.Common;
using Ryujinx.Memory;
using System;
using System.Collections.Generic;
@@ -217,7 +217,7 @@ namespace Ryujinx.HLE.HOS.Services.Ro
if (info.BssSize > 0)
{
- KernelResult bssMappingResult = memMgr.MapProcessCodeMemory(nroMappedAddress + info.NroSize, info.BssAddress, info.BssSize);
+ Result bssMappingResult = memMgr.MapProcessCodeMemory(nroMappedAddress + info.NroSize, info.BssAddress, info.BssSize);
if (bssMappingResult == KernelResult.InvalidMemState)
{
@@ -226,12 +226,12 @@ namespace Ryujinx.HLE.HOS.Services.Ro
continue;
}
- else if (bssMappingResult != KernelResult.Success)
+ else if (bssMappingResult != Result.Success)
{
memMgr.UnmapProcessCodeMemory(nroMappedAddress + info.NroSize, info.BssAddress, info.BssSize);
memMgr.UnmapProcessCodeMemory(nroMappedAddress, info.NroAddress, info.NroSize);
- return (ResultCode)bssMappingResult;
+ return (ResultCode)bssMappingResult.ErrorCode;
}
}
@@ -286,15 +286,15 @@ namespace Ryujinx.HLE.HOS.Services.Ro
}
}
- KernelResult result = memMgr.MapProcessCodeMemory(targetAddress, baseAddress, size);
+ Result result = memMgr.MapProcessCodeMemory(targetAddress, baseAddress, size);
if (result == KernelResult.InvalidMemState)
{
continue;
}
- else if (result != KernelResult.Success)
+ else if (result != Result.Success)
{
- return (ResultCode)result;
+ return (ResultCode)result.ErrorCode;
}
if (!CanAddGuardRegionsInProcess(process, targetAddress, size))
@@ -313,11 +313,11 @@ namespace Ryujinx.HLE.HOS.Services.Ro
return ResultCode.Success;
}
- private KernelResult SetNroMemoryPermissions(KProcess process, IExecutable relocatableObject, ulong baseAddress)
+ private Result SetNroMemoryPermissions(KProcess process, IExecutable relocatableObject, ulong baseAddress)
{
- ulong textStart = baseAddress + (ulong)relocatableObject.TextOffset;
- ulong roStart = baseAddress + (ulong)relocatableObject.RoOffset;
- ulong dataStart = baseAddress + (ulong)relocatableObject.DataOffset;
+ ulong textStart = baseAddress + relocatableObject.TextOffset;
+ ulong roStart = baseAddress + relocatableObject.RoOffset;
+ ulong dataStart = baseAddress + relocatableObject.DataOffset;
ulong bssStart = dataStart + (ulong)relocatableObject.Data.Length;
@@ -329,18 +329,18 @@ namespace Ryujinx.HLE.HOS.Services.Ro
MemoryHelper.FillWithZeros(process.CpuMemory, bssStart, (int)(bssEnd - bssStart));
- KernelResult result;
+ Result result;
result = process.MemoryManager.SetProcessMemoryPermission(textStart, roStart - textStart, KMemoryPermission.ReadAndExecute);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
return result;
}
result = process.MemoryManager.SetProcessMemoryPermission(roStart, dataStart - roStart, KMemoryPermission.Read);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
return result;
}
@@ -385,7 +385,7 @@ namespace Ryujinx.HLE.HOS.Services.Ro
ulong dataSize = (ulong)info.Executable.Data.Length;
ulong bssSize = (ulong)info.Executable.BssSize;
- KernelResult result = KernelResult.Success;
+ Result result = Result.Success;
if (info.Executable.BssSize != 0)
{
@@ -395,14 +395,14 @@ namespace Ryujinx.HLE.HOS.Services.Ro
bssSize);
}
- if (result == KernelResult.Success)
+ if (result == Result.Success)
{
result = _owner.MemoryManager.UnmapProcessCodeMemory(
info.NroMappedAddress + textSize + roSize,
info.Executable.SourceAddress + textSize + roSize,
dataSize);
- if (result == KernelResult.Success)
+ if (result == Result.Success)
{
result = _owner.MemoryManager.UnmapProcessCodeMemory(
info.NroMappedAddress,
@@ -411,7 +411,7 @@ namespace Ryujinx.HLE.HOS.Services.Ro
}
}
- return (ResultCode)result;
+ return (ResultCode)result.ErrorCode;
}
private ResultCode IsInitialized(ulong pid)
@@ -452,7 +452,7 @@ namespace Ryujinx.HLE.HOS.Services.Ro
if (result == ResultCode.Success)
{
- result = (ResultCode)SetNroMemoryPermissions(_owner, info.Executable, nroMappedAddress);
+ result = (ResultCode)SetNroMemoryPermissions(_owner, info.Executable, nroMappedAddress).ErrorCode;
if (result == ResultCode.Success)
{
diff --git a/Ryujinx.HLE/HOS/Services/Sdb/Pl/ISharedFontManager.cs b/Ryujinx.HLE/HOS/Services/Sdb/Pl/ISharedFontManager.cs
index 82e246b7..f95c1d1f 100644
--- a/Ryujinx.HLE/HOS/Services/Sdb/Pl/ISharedFontManager.cs
+++ b/Ryujinx.HLE/HOS/Services/Sdb/Pl/ISharedFontManager.cs
@@ -1,6 +1,6 @@
using Ryujinx.HLE.HOS.Ipc;
-using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Services.Sdb.Pl.Types;
+using Ryujinx.Horizon.Common;
using System;
namespace Ryujinx.HLE.HOS.Services.Sdb.Pl
@@ -67,7 +67,7 @@ namespace Ryujinx.HLE.HOS.Services.Sdb.Pl
if (_fontSharedMemHandle == 0)
{
- if (context.Process.HandleTable.GenerateHandle(context.Device.System.FontSharedMem, out _fontSharedMemHandle) != KernelResult.Success)
+ if (context.Process.HandleTable.GenerateHandle(context.Device.System.FontSharedMem, out _fontSharedMemHandle) != Result.Success)
{
throw new InvalidOperationException("Out of handles!");
}
@@ -107,7 +107,7 @@ namespace Ryujinx.HLE.HOS.Services.Sdb.Pl
// GetSharedFontInOrderOfPriorityForSystem(bytes<8, 1>) -> (u8, u32, buffer<unknown, 6>, buffer<unknown, 6>, buffer<unknown, 6>)
public ResultCode GetSharedFontInOrderOfPriorityForSystem(ServiceCtx context)
{
- // TODO: Check the differencies with GetSharedFontInOrderOfPriority.
+ // TODO: Check the differencies with GetSharedFontInOrderOfPriority.
return GetSharedFontInOrderOfPriority(context);
}
diff --git a/Ryujinx.HLE/HOS/Services/ServerBase.cs b/Ryujinx.HLE/HOS/Services/ServerBase.cs
index 3c53abec..50f6c99e 100644
--- a/Ryujinx.HLE/HOS/Services/ServerBase.cs
+++ b/Ryujinx.HLE/HOS/Services/ServerBase.cs
@@ -1,9 +1,9 @@
using Ryujinx.HLE.HOS.Ipc;
using Ryujinx.HLE.HOS.Kernel;
-using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Ipc;
using Ryujinx.HLE.HOS.Kernel.Process;
using Ryujinx.HLE.HOS.Kernel.Threading;
+using Ryujinx.Horizon.Common;
using System;
using System.Buffers.Binary;
using System.Collections.Generic;
@@ -129,7 +129,7 @@ namespace Ryujinx.HLE.HOS.Services
replyTargetHandle = 0;
- if (rc == KernelResult.Success && signaledIndex >= portHandles.Length)
+ if (rc == Result.Success && signaledIndex >= portHandles.Length)
{
// We got a IPC request, process it, pass to the appropriate service if needed.
int signaledHandle = handles[signaledIndex];
@@ -141,10 +141,10 @@ namespace Ryujinx.HLE.HOS.Services
}
else
{
- if (rc == KernelResult.Success)
+ if (rc == Result.Success)
{
// We got a new connection, accept the session to allow servicing future requests.
- if (_context.Syscall.AcceptSession(out int serverSessionHandle, handles[signaledIndex]) == KernelResult.Success)
+ if (_context.Syscall.AcceptSession(out int serverSessionHandle, handles[signaledIndex]) == Result.Success)
{
IpcService obj = _ports[handles[signaledIndex]].Invoke();
diff --git a/Ryujinx.HLE/HOS/Services/Sm/IUserInterface.cs b/Ryujinx.HLE/HOS/Services/Sm/IUserInterface.cs
index 8e66b28d..86031a70 100644
--- a/Ryujinx.HLE/HOS/Services/Sm/IUserInterface.cs
+++ b/Ryujinx.HLE/HOS/Services/Sm/IUserInterface.cs
@@ -1,8 +1,8 @@
using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS.Ipc;
using Ryujinx.HLE.HOS.Kernel;
-using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Ipc;
+using Ryujinx.Horizon.Common;
using System;
using System.Collections.Generic;
using System.IO;
@@ -72,14 +72,14 @@ namespace Ryujinx.HLE.HOS.Services.Sm
if (_registry.TryGetService(name, out KPort port))
{
- KernelResult result = port.EnqueueIncomingSession(session.ServerSession);
+ Result result = port.EnqueueIncomingSession(session.ServerSession);
- if (result != KernelResult.Success)
+ if (result != Result.Success)
{
throw new InvalidOperationException($"Session enqueue on port returned error \"{result}\".");
}
- if (context.Process.HandleTable.GenerateHandle(session.ClientSession, out int handle) != KernelResult.Success)
+ if (context.Process.HandleTable.GenerateHandle(session.ClientSession, out int handle) != Result.Success)
{
throw new InvalidOperationException("Out of handles!");
}
@@ -113,7 +113,7 @@ namespace Ryujinx.HLE.HOS.Services.Sm
}
}
- if (context.Process.HandleTable.GenerateHandle(session.ClientSession, out int handle) != KernelResult.Success)
+ if (context.Process.HandleTable.GenerateHandle(session.ClientSession, out int handle) != Result.Success)
{
throw new InvalidOperationException("Out of handles!");
}
@@ -182,14 +182,14 @@ namespace Ryujinx.HLE.HOS.Services.Sm
Logger.Info?.Print(LogClass.ServiceSm, $"Register \"{name}\".");
- KPort port = new KPort(context.Device.System.KernelContext, maxSessions, isLight, 0);
+ KPort port = new KPort(context.Device.System.KernelContext, maxSessions, isLight, null);
if (!_registry.TryRegister(name, port))
{
return ResultCode.AlreadyRegistered;
}
- if (context.Process.HandleTable.GenerateHandle(port.ServerPort, out int handle) != KernelResult.Success)
+ if (context.Process.HandleTable.GenerateHandle(port.ServerPort, out int handle) != Result.Success)
{
throw new InvalidOperationException("Out of handles!");
}
diff --git a/Ryujinx.HLE/HOS/Services/SurfaceFlinger/IHOSBinderDriver.cs b/Ryujinx.HLE/HOS/Services/SurfaceFlinger/IHOSBinderDriver.cs
index c3dcbee7..d641f7f0 100644
--- a/Ryujinx.HLE/HOS/Services/SurfaceFlinger/IHOSBinderDriver.cs
+++ b/Ryujinx.HLE/HOS/Services/SurfaceFlinger/IHOSBinderDriver.cs
@@ -1,6 +1,6 @@
using Ryujinx.HLE.HOS.Ipc;
-using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Threading;
+using Ryujinx.Horizon.Common;
using System;
namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
@@ -59,7 +59,7 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
GetNativeHandle(binderId, typeId, out KReadableEvent readableEvent);
- if (context.Process.HandleTable.GenerateHandle(readableEvent, out int handle) != KernelResult.Success)
+ if (context.Process.HandleTable.GenerateHandle(readableEvent, out int handle) != Result.Success)
{
throw new InvalidOperationException("Out of handles!");
}
diff --git a/Ryujinx.HLE/HOS/Services/Time/IStaticServiceForPsc.cs b/Ryujinx.HLE/HOS/Services/Time/IStaticServiceForPsc.cs
index 4f351812..abb5bb40 100644
--- a/Ryujinx.HLE/HOS/Services/Time/IStaticServiceForPsc.cs
+++ b/Ryujinx.HLE/HOS/Services/Time/IStaticServiceForPsc.cs
@@ -1,10 +1,10 @@
using Ryujinx.Common;
using Ryujinx.Cpu;
using Ryujinx.HLE.HOS.Ipc;
-using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Services.Time.Clock;
using Ryujinx.HLE.HOS.Services.Time.StaticService;
using Ryujinx.HLE.HOS.Services.Time.TimeZone;
+using Ryujinx.Horizon.Common;
using System;
using System.Diagnostics;
using System.IO;
@@ -102,7 +102,7 @@ namespace Ryujinx.HLE.HOS.Services.Time
{
if (_timeSharedMemoryNativeHandle == 0)
{
- if (context.Process.HandleTable.GenerateHandle(_timeManager.SharedMemory.GetSharedMemory(), out _timeSharedMemoryNativeHandle) != KernelResult.Success)
+ if (context.Process.HandleTable.GenerateHandle(_timeManager.SharedMemory.GetSharedMemory(), out _timeSharedMemoryNativeHandle) != Result.Success)
{
throw new InvalidOperationException("Out of handles!");
}
diff --git a/Ryujinx.HLE/HOS/Services/Time/ITimeServiceManager.cs b/Ryujinx.HLE/HOS/Services/Time/ITimeServiceManager.cs
index 1ff5b2d6..aae9aaaf 100644
--- a/Ryujinx.HLE/HOS/Services/Time/ITimeServiceManager.cs
+++ b/Ryujinx.HLE/HOS/Services/Time/ITimeServiceManager.cs
@@ -2,9 +2,9 @@
using Ryujinx.Cpu;
using Ryujinx.HLE.Exceptions;
using Ryujinx.HLE.HOS.Ipc;
-using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Services.Time.Clock;
using Ryujinx.HLE.Utilities;
+using Ryujinx.Horizon.Common;
using System;
using System.IO;
@@ -180,7 +180,7 @@ namespace Ryujinx.HLE.HOS.Services.Time
{
if (_automaticCorrectionEvent == 0)
{
- if (context.Process.HandleTable.GenerateHandle(_timeManager.StandardUserSystemClock.GetAutomaticCorrectionReadableEvent(), out _automaticCorrectionEvent) != KernelResult.Success)
+ if (context.Process.HandleTable.GenerateHandle(_timeManager.StandardUserSystemClock.GetAutomaticCorrectionReadableEvent(), out _automaticCorrectionEvent) != Result.Success)
{
throw new InvalidOperationException("Out of handles!");
}
diff --git a/Ryujinx.HLE/HOS/Services/Time/StaticService/ISystemClock.cs b/Ryujinx.HLE/HOS/Services/Time/StaticService/ISystemClock.cs
index 085cc71d..c43c1582 100644
--- a/Ryujinx.HLE/HOS/Services/Time/StaticService/ISystemClock.cs
+++ b/Ryujinx.HLE/HOS/Services/Time/StaticService/ISystemClock.cs
@@ -1,9 +1,9 @@
using Ryujinx.Common;
using Ryujinx.Cpu;
using Ryujinx.HLE.HOS.Ipc;
-using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Threading;
using Ryujinx.HLE.HOS.Services.Time.Clock;
+using Ryujinx.Horizon.Common;
using System;
namespace Ryujinx.HLE.HOS.Services.Time.StaticService
@@ -117,7 +117,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.StaticService
_clockCore.RegisterOperationEvent(kEvent.WritableEvent);
- if (context.Process.HandleTable.GenerateHandle(kEvent.ReadableEvent, out _operationEventReadableHandle) != KernelResult.Success)
+ if (context.Process.HandleTable.GenerateHandle(kEvent.ReadableEvent, out _operationEventReadableHandle) != Result.Success)
{
throw new InvalidOperationException("Out of handles!");
}
diff --git a/Ryujinx.HLE/HOS/Services/Vi/RootService/IApplicationDisplayService.cs b/Ryujinx.HLE/HOS/Services/Vi/RootService/IApplicationDisplayService.cs
index 885a4cd7..d6feb33f 100644
--- a/Ryujinx.HLE/HOS/Services/Vi/RootService/IApplicationDisplayService.cs
+++ b/Ryujinx.HLE/HOS/Services/Vi/RootService/IApplicationDisplayService.cs
@@ -14,6 +14,7 @@ using System.Diagnostics;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Text;
+using Ryujinx.Horizon.Common;
namespace Ryujinx.HLE.HOS.Services.Vi.RootService
{
@@ -471,7 +472,7 @@ namespace Ryujinx.HLE.HOS.Services.Vi.RootService
if (_vsyncEventHandle == 0)
{
- if (context.Process.HandleTable.GenerateHandle(context.Device.System.VsyncEvent.ReadableEvent, out _vsyncEventHandle) != KernelResult.Success)
+ if (context.Process.HandleTable.GenerateHandle(context.Device.System.VsyncEvent.ReadableEvent, out _vsyncEventHandle) != Result.Success)
{
throw new InvalidOperationException("Out of handles!");
}
diff --git a/Ryujinx.HLE/Ryujinx.HLE.csproj b/Ryujinx.HLE/Ryujinx.HLE.csproj
index f1f295a2..5e3aa0ea 100644
--- a/Ryujinx.HLE/Ryujinx.HLE.csproj
+++ b/Ryujinx.HLE/Ryujinx.HLE.csproj
@@ -11,7 +11,9 @@
<ProjectReference Include="..\Ryujinx.Graphics.Host1x\Ryujinx.Graphics.Host1x.csproj" />
<ProjectReference Include="..\Ryujinx.Graphics.Nvdec\Ryujinx.Graphics.Nvdec.csproj" />
<ProjectReference Include="..\Ryujinx.Graphics.Vic\Ryujinx.Graphics.Vic.csproj" />
- <ProjectReference Include="..\Ryujinx.Horizon.Generators\Ryujinx.Horizon.Generators.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
+ <ProjectReference Include="..\Ryujinx.Horizon.Common\Ryujinx.Horizon.Common.csproj" />
+ <ProjectReference Include="..\Ryujinx.Horizon.Kernel.Generators\Ryujinx.Horizon.Kernel.Generators.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
+ <ProjectReference Include="..\Ryujinx.Horizon\Ryujinx.Horizon.csproj" />
<ProjectReference Include="..\Ryujinx.Memory\Ryujinx.Memory.csproj" />
<ProjectReference Include="..\ARMeilleure\ARMeilleure.csproj" />
<ProjectReference Include="..\Ryujinx.Graphics.Gpu\Ryujinx.Graphics.Gpu.csproj" />
diff --git a/Ryujinx.HLE/Switch.cs b/Ryujinx.HLE/Switch.cs
index 46af68f4..61e5e572 100644
--- a/Ryujinx.HLE/Switch.cs
+++ b/Ryujinx.HLE/Switch.cs
@@ -19,7 +19,7 @@ namespace Ryujinx.HLE
public MemoryBlock Memory { get; }
public GpuContext Gpu { get; }
public VirtualFileSystem FileSystem { get; }
- public Horizon System { get; }
+ public HOS.Horizon System { get; }
public ApplicationLoader Application { get; }
public PerformanceStatistics Statistics { get; }
public Hid Hid { get; }
@@ -47,7 +47,7 @@ namespace Ryujinx.HLE
AudioDeviceDriver = new CompatLayerHardwareDeviceDriver(Configuration.AudioDeviceDriver);
Memory = new MemoryBlock(Configuration.MemoryConfiguration.ToDramSize(), memoryAllocationFlags);
Gpu = new GpuContext(Configuration.GpuRenderer);
- System = new Horizon(this);
+ System = new HOS.Horizon(this);
Statistics = new PerformanceStatistics();
Hid = new Hid(this, System.HidStorage);
Application = new ApplicationLoader(this);
diff --git a/Ryujinx.Horizon.Common/ISyscallApi.cs b/Ryujinx.Horizon.Common/ISyscallApi.cs
new file mode 100644
index 00000000..8fa276b5
--- /dev/null
+++ b/Ryujinx.Horizon.Common/ISyscallApi.cs
@@ -0,0 +1,33 @@
+using System;
+
+namespace Ryujinx.Horizon.Common
+{
+ public interface ISyscallApi
+ {
+ Result SetHeapSize(out ulong address, ulong size);
+
+ void SleepThread(long timeout);
+
+ Result CloseHandle(int handle);
+
+ Result WaitSynchronization(out int handleIndex, ReadOnlySpan<int> handles, long timeout);
+ Result CancelSynchronization(int handle);
+
+ Result GetProcessId(out ulong pid, int handle);
+
+ Result ConnectToNamedPort(out int handle, string name);
+ Result SendSyncRequest(int handle);
+ Result CreateSession(out int serverSessionHandle, out int clientSessionHandle, bool isLight, string name);
+ Result AcceptSession(out int sessionHandle, int portHandle);
+ Result ReplyAndReceive(out int handleIndex, ReadOnlySpan<int> handles, int replyTargetHandle, long timeout);
+
+ Result CreateEvent(out int writableHandle, out int readableHandle);
+ Result SignalEvent(int handle);
+ Result ClearEvent(int handle);
+ Result ResetSignal(int handle);
+
+ Result CreatePort(out int serverPortHandle, out int clientPortHandle, int maxSessions, bool isLight, string name);
+ Result ManageNamedPort(out int handle, string name, int maxSessions);
+ Result ConnectToPort(out int clientSessionHandle, int clientPortHandle);
+ }
+}
diff --git a/Ryujinx.Horizon.Common/IThreadContext.cs b/Ryujinx.Horizon.Common/IThreadContext.cs
new file mode 100644
index 00000000..47aea1a3
--- /dev/null
+++ b/Ryujinx.Horizon.Common/IThreadContext.cs
@@ -0,0 +1,11 @@
+namespace Ryujinx.Horizon.Common
+{
+ public interface IThreadContext
+ {
+ bool Running { get; }
+
+ ulong TlsAddress { get; }
+
+ ulong GetX(int index);
+ }
+}
diff --git a/Ryujinx.Horizon.Common/InvalidResultException.cs b/Ryujinx.Horizon.Common/InvalidResultException.cs
new file mode 100644
index 00000000..cf38b640
--- /dev/null
+++ b/Ryujinx.Horizon.Common/InvalidResultException.cs
@@ -0,0 +1,23 @@
+using System;
+
+namespace Ryujinx.Horizon.Common
+{
+ public class InvalidResultException : Exception
+ {
+ public InvalidResultException()
+ {
+ }
+
+ public InvalidResultException(Result result) : base($"Unexpected result code {result} returned.")
+ {
+ }
+
+ public InvalidResultException(string message) : base(message)
+ {
+ }
+
+ public InvalidResultException(string message, Exception innerException) : base(message, innerException)
+ {
+ }
+ }
+}
diff --git a/Ryujinx.Horizon.Common/KernelResult.cs b/Ryujinx.Horizon.Common/KernelResult.cs
new file mode 100644
index 00000000..51fec205
--- /dev/null
+++ b/Ryujinx.Horizon.Common/KernelResult.cs
@@ -0,0 +1,39 @@
+namespace Ryujinx.Horizon.Common
+{
+ public static class KernelResult
+ {
+ private const int ModuleId = 1;
+
+ public static Result SessionCountExceeded => new Result(ModuleId, 7);
+ public static Result InvalidCapability => new Result(ModuleId, 14);
+ public static Result ThreadNotStarted => new Result(ModuleId, 57);
+ public static Result ThreadTerminating => new Result(ModuleId, 59);
+ public static Result InvalidSize => new Result(ModuleId, 101);
+ public static Result InvalidAddress => new Result(ModuleId, 102);
+ public static Result OutOfResource => new Result(ModuleId, 103);
+ public static Result OutOfMemory => new Result(ModuleId, 104);
+ public static Result HandleTableFull => new Result(ModuleId, 105);
+ public static Result InvalidMemState => new Result(ModuleId, 106);
+ public static Result InvalidPermission => new Result(ModuleId, 108);
+ public static Result InvalidMemRange => new Result(ModuleId, 110);
+ public static Result InvalidPriority => new Result(ModuleId, 112);
+ public static Result InvalidCpuCore => new Result(ModuleId, 113);
+ public static Result InvalidHandle => new Result(ModuleId, 114);
+ public static Result UserCopyFailed => new Result(ModuleId, 115);
+ public static Result InvalidCombination => new Result(ModuleId, 116);
+ public static Result TimedOut => new Result(ModuleId, 117);
+ public static Result Cancelled => new Result(ModuleId, 118);
+ public static Result MaximumExceeded => new Result(ModuleId, 119);
+ public static Result InvalidEnumValue => new Result(ModuleId, 120);
+ public static Result NotFound => new Result(ModuleId, 121);
+ public static Result InvalidThread => new Result(ModuleId, 122);
+ public static Result PortRemoteClosed => new Result(ModuleId, 123);
+ public static Result InvalidState => new Result(ModuleId, 125);
+ public static Result ReservedValue => new Result(ModuleId, 126);
+ public static Result PortClosed => new Result(ModuleId, 131);
+ public static Result ResLimitExceeded => new Result(ModuleId, 132);
+ public static Result ReceiveListBroken => new Result(ModuleId, 258);
+ public static Result OutOfVaSpace => new Result(ModuleId, 259);
+ public static Result CmdBufferTooSmall => new Result(ModuleId, 260);
+ }
+}
diff --git a/Ryujinx.Horizon.Common/OnScopeExit.cs b/Ryujinx.Horizon.Common/OnScopeExit.cs
new file mode 100644
index 00000000..2b81e492
--- /dev/null
+++ b/Ryujinx.Horizon.Common/OnScopeExit.cs
@@ -0,0 +1,19 @@
+using System;
+
+namespace Ryujinx.Horizon.Common
+{
+ public struct OnScopeExit : IDisposable
+ {
+ private readonly Action _action;
+
+ public OnScopeExit(Action action)
+ {
+ _action = action;
+ }
+
+ public void Dispose()
+ {
+ _action();
+ }
+ }
+}
diff --git a/Ryujinx.Horizon.Common/Result.cs b/Ryujinx.Horizon.Common/Result.cs
new file mode 100644
index 00000000..04281199
--- /dev/null
+++ b/Ryujinx.Horizon.Common/Result.cs
@@ -0,0 +1,118 @@
+using System;
+
+namespace Ryujinx.Horizon.Common
+{
+ public struct Result : IEquatable<Result>
+ {
+ private const int ModuleBits = 9;
+ private const int DescriptionBits = 13;
+ private const int ModuleMax = 1 << ModuleBits;
+ private const int DescriptionMax = 1 << DescriptionBits;
+
+ public static Result Success { get; } = new Result(0, 0);
+
+ public int ErrorCode { get; }
+
+ public bool IsSuccess => ErrorCode == 0;
+ public bool IsFailure => ErrorCode != 0;
+
+ public int Module => ErrorCode & (ModuleMax - 1);
+ public int Description => (ErrorCode >> ModuleBits) & (DescriptionMax - 1);
+
+ public string PrintableResult => $"{2000 + Module:D4}-{Description:D4}";
+
+ public Result(int module, int description)
+ {
+ if ((uint)module >= ModuleMax)
+ {
+ throw new ArgumentOutOfRangeException(nameof(module));
+ }
+
+ if ((uint)description >= DescriptionMax)
+ {
+ throw new ArgumentOutOfRangeException(nameof(description));
+ }
+
+ ErrorCode = module | (description << ModuleBits);
+ }
+
+ public override bool Equals(object obj)
+ {
+ return obj is Result result && result.Equals(this);
+ }
+
+ public bool Equals(Result other)
+ {
+ return other.ErrorCode == ErrorCode;
+ }
+
+ public override int GetHashCode()
+ {
+ return ErrorCode;
+ }
+
+ public static bool operator ==(Result lhs, Result rhs)
+ {
+ return lhs.Equals(rhs);
+ }
+
+ public static bool operator !=(Result lhs, Result rhs)
+ {
+ return !lhs.Equals(rhs);
+ }
+
+ public bool InRange(int minInclusive, int maxInclusive)
+ {
+ return (uint)(Description - minInclusive) <= (uint)(maxInclusive - minInclusive);
+ }
+
+ public void AbortOnSuccess()
+ {
+ if (IsSuccess)
+ {
+ ThrowInvalidResult();
+ }
+ }
+
+ public void AbortOnFailure()
+ {
+ if (this == KernelResult.ThreadTerminating)
+ {
+ throw new ThreadTerminatedException();
+ }
+
+ AbortUnless(Success);
+ }
+
+ public void AbortUnless(Result result)
+ {
+ if (this != result)
+ {
+ ThrowInvalidResult();
+ }
+ }
+
+ public void AbortUnless(Result result, Result result2)
+ {
+ if (this != result && this != result2)
+ {
+ ThrowInvalidResult();
+ }
+ }
+
+ private void ThrowInvalidResult()
+ {
+ throw new InvalidResultException(this);
+ }
+
+ public override string ToString()
+ {
+ if (ResultNames.TryGet(ErrorCode, out string name))
+ {
+ return name;
+ }
+
+ return PrintableResult;
+ }
+ }
+}
diff --git a/Ryujinx.Horizon.Common/ResultNames.cs b/Ryujinx.Horizon.Common/ResultNames.cs
new file mode 100644
index 00000000..8f8173ed
--- /dev/null
+++ b/Ryujinx.Horizon.Common/ResultNames.cs
@@ -0,0 +1,1701 @@
+using System.Collections.Generic;
+
+namespace Ryujinx.Horizon.Common
+{
+ static class ResultNames
+ {
+ // Reference: https://github.com/Thealexbarney/LibHac/blob/master/build/CodeGen/results.csv
+ private static readonly IReadOnlyDictionary<int, string> _names = new Dictionary<int, string>()
+ {
+ { 0x0, "Success" },
+ { 0xE01, "OutOfSessions" },
+ { 0x1C01, "InvalidArgument" },
+ { 0x4201, "NotImplemented" },
+ { 0x6C01, "StopProcessingException" },
+ { 0x7201, "NoSynchronizationObject" },
+ { 0x7601, "TerminationRequested" },
+ { 0x8C01, "NoEvent" },
+ { 0xCA01, "InvalidSize" },
+ { 0xCC01, "InvalidAddress" },
+ { 0xCE01, "OutOfResource" },
+ { 0xD001, "OutOfMemory" },
+ { 0xD201, "OutOfHandles" },
+ { 0xD401, "InvalidCurrentMemory" },
+ { 0xD801, "InvalidNewMemoryPermission" },
+ { 0xDC01, "InvalidMemoryRegion" },
+ { 0xE001, "InvalidPriority" },
+ { 0xE201, "InvalidCoreId" },
+ { 0xE401, "InvalidHandle" },
+ { 0xE601, "InvalidPointer" },
+ { 0xE801, "InvalidCombination" },
+ { 0xEA01, "TimedOut" },
+ { 0xEC01, "Cancelled" },
+ { 0xEE01, "OutOfRange" },
+ { 0xF001, "InvalidEnumValue" },
+ { 0xF201, "NotFound" },
+ { 0xF401, "Busy" },
+ { 0xF601, "SessionClosed" },
+ { 0xF801, "NotHandled" },
+ { 0xFA01, "InvalidState" },
+ { 0xFC01, "ReservedUsed" },
+ { 0xFE01, "NotSupported" },
+ { 0x10001, "Debug" },
+ { 0x10201, "NoThread" },
+ { 0x10401, "UnknownThread" },
+ { 0x10601, "PortClosed" },
+ { 0x10801, "LimitReached" },
+ { 0x10A01, "InvalidMemoryPool" },
+ { 0x20401, "ReceiveListBroken" },
+ { 0x20601, "OutOfAddressSpace" },
+ { 0x20801, "MessageTooLarge" },
+ { 0x40A01, "InvalidProcessId" },
+ { 0x40C01, "InvalidThreadId" },
+ { 0x40E01, "InvalidId" },
+ { 0x41001, "ProcessTerminated" },
+ { 0x2, "HandledByAllProcess" },
+ { 0x202, "PathNotFound" },
+ { 0x402, "PathAlreadyExists" },
+ { 0x1002, "DirectoryNotEmpty" },
+ { 0x1A02, "DirectoryStatusChanged" },
+ { 0x3C02, "UsableSpaceNotEnough" },
+ { 0x3E02, "UsableSpaceNotEnoughForSaveData" },
+ { 0x4002, "UsableSpaceNotEnoughForSaveDataEvenAssistanceSuccess" },
+ { 0x4202, "UsableSpaceNotEnoughForCacheStorage" },
+ { 0x4402, "UsableSpaceNotEnoughMmc" },
+ { 0x4602, "UsableSpaceNotEnoughMmcCalibration" },
+ { 0x4802, "UsableSpaceNotEnoughMmcSafe" },
+ { 0x4A02, "UsableSpaceNotEnoughMmcUser" },
+ { 0x4C02, "UsableSpaceNotEnoughMmcSystem" },
+ { 0x4E02, "UsableSpaceNotEnoughSdCard" },
+ { 0x6402, "UnsupportedSdkVersion" },
+ { 0x7802, "MountNameAlreadyExists" },
+ { 0x8C02, "IndividualFileDataCacheAlreadyEnabled" },
+ { 0x7D002, "HandledBySystemProcess" },
+ { 0x7D202, "PartitionNotFound" },
+ { 0x7D402, "TargetNotFound" },
+ { 0x7D602, "HasNotGottenPatrolCount" },
+ { 0x7D802, "NcaExternalKeyUnregistered" },
+ { 0xFA002, "SdCardAccessFailed" },
+ { 0xFA202, "PortSdCardNoDevice" },
+ { 0xFA402, "PortSdCardNotActivated" },
+ { 0xFA602, "PortSdCardDeviceRemoved" },
+ { 0xFA802, "PortSdCardNotAwakened" },
+ { 0xFE002, "PortSdCardCommunicationError" },
+ { 0xFE202, "PortSdCardCommunicationNotAttained" },
+ { 0xFE402, "PortSdCardResponseIndexError" },
+ { 0xFE602, "PortSdCardResponseEndBitError" },
+ { 0xFE802, "PortSdCardResponseCrcError" },
+ { 0xFEA02, "PortSdCardResponseTimeoutError" },
+ { 0xFEC02, "PortSdCardDataEndBitError" },
+ { 0xFEE02, "PortSdCardDataCrcError" },
+ { 0xFF002, "PortSdCardDataTimeoutError" },
+ { 0xFF202, "PortSdCardAutoCommandResponseIndexError" },
+ { 0xFF402, "PortSdCardAutoCommandResponseEndBitError" },
+ { 0xFF602, "PortSdCardAutoCommandResponseCrcError" },
+ { 0xFF802, "PortSdCardAutoCommandResponseTimeoutError" },
+ { 0xFFA02, "PortSdCardCommandCompleteSwTimeout" },
+ { 0xFFC02, "PortSdCardTransferCompleteSwTimeout" },
+ { 0x100002, "PortSdCardDeviceStatusHasError" },
+ { 0x100202, "PortSdCardDeviceStatusAddressOutOfRange" },
+ { 0x100402, "PortSdCardDeviceStatusAddressMisalign" },
+ { 0x100602, "PortSdCardDeviceStatusBlockLenError" },
+ { 0x100802, "PortSdCardDeviceStatusEraseSeqError" },
+ { 0x100A02, "PortSdCardDeviceStatusEraseParam" },
+ { 0x100C02, "PortSdCardDeviceStatusWpViolation" },
+ { 0x100E02, "PortSdCardDeviceStatusLockUnlockFailed" },
+ { 0x101002, "PortSdCardDeviceStatusComCrcError" },
+ { 0x101202, "PortSdCardDeviceStatusIllegalCommand" },
+ { 0x101402, "PortSdCardDeviceStatusDeviceEccFailed" },
+ { 0x101602, "PortSdCardDeviceStatusCcError" },
+ { 0x101802, "PortSdCardDeviceStatusError" },
+ { 0x101A02, "PortSdCardDeviceStatusCidCsdOverwrite" },
+ { 0x101C02, "PortSdCardDeviceStatusWpEraseSkip" },
+ { 0x101E02, "PortSdCardDeviceStatusEraseReset" },
+ { 0x102002, "PortSdCardDeviceStatusSwitchError" },
+ { 0x103002, "PortSdCardUnexpectedDeviceState" },
+ { 0x103202, "PortSdCardUnexpectedDeviceCsdValue" },
+ { 0x103402, "PortSdCardAbortTransactionSwTimeout" },
+ { 0x103602, "PortSdCardCommandInhibitCmdSwTimeout" },
+ { 0x103802, "PortSdCardCommandInhibitDatSwTimeout" },
+ { 0x103A02, "PortSdCardBusySwTimeout" },
+ { 0x103C02, "PortSdCardIssueTuningCommandSwTimeout" },
+ { 0x103E02, "PortSdCardTuningFailed" },
+ { 0x104002, "PortSdCardMmcInitializationSwTimeout" },
+ { 0x104202, "PortSdCardMmcNotSupportExtendedCsd" },
+ { 0x104402, "PortSdCardUnexpectedMmcExtendedCsdValue" },
+ { 0x104602, "PortSdCardMmcEraseSwTimeout" },
+ { 0x104802, "PortSdCardSdCardValidationError" },
+ { 0x104A02, "PortSdCardSdCardInitializationSwTimeout" },
+ { 0x104C02, "PortSdCardSdCardGetValidRcaSwTimeout" },
+ { 0x104E02, "PortSdCardUnexpectedSdCardAcmdDisabled" },
+ { 0x105002, "PortSdCardSdCardNotSupportSwitchFunctionStatus" },
+ { 0x105202, "PortSdCardUnexpectedSdCardSwitchFunctionStatus" },
+ { 0x105402, "PortSdCardSdCardNotSupportAccessMode" },
+ { 0x105602, "PortSdCardSdCardNot4BitBusWidthAtUhsIMode" },
+ { 0x105802, "PortSdCardSdCardNotSupportSdr104AndSdr50" },
+ { 0x105A02, "PortSdCardSdCardCannotSwitchedAccessMode" },
+ { 0x105C02, "PortSdCardSdCardFailedSwitchedAccessMode" },
+ { 0x105E02, "PortSdCardSdCardUnacceptableCurrentConsumption" },
+ { 0x106002, "PortSdCardSdCardNotReadyToVoltageSwitch" },
+ { 0x106202, "PortSdCardSdCardNotCompleteVoltageSwitch" },
+ { 0x10A002, "PortSdCardHostControllerUnexpected" },
+ { 0x10A202, "PortSdCardInternalClockStableSwTimeout" },
+ { 0x10A402, "PortSdCardSdHostStandardUnknownAutoCmdError" },
+ { 0x10A602, "PortSdCardSdHostStandardUnknownError" },
+ { 0x10A802, "PortSdCardSdmmcDllCalibrationSwTimeout" },
+ { 0x10AA02, "PortSdCardSdmmcDllApplicationSwTimeout" },
+ { 0x10AC02, "PortSdCardSdHostStandardFailSwitchTo18V" },
+ { 0x10E002, "PortSdCardInternalError" },
+ { 0x10E202, "PortSdCardNoWaitedInterrupt" },
+ { 0x10E402, "PortSdCardWaitInterruptSwTimeout" },
+ { 0x112002, "PortSdCardAbortCommandIssued" },
+ { 0x113002, "PortSdCardNotSupported" },
+ { 0x113202, "PortSdCardNotImplemented" },
+ { 0x138002, "PortSdCardStorageDeviceInvalidated" },
+ { 0x138202, "PortSdCardWriteVerifyError" },
+ { 0x138402, "PortSdCardFileSystemInvalidatedByRemoved" },
+ { 0x138602, "PortSdCardUnexpected" },
+ { 0x138802, "GameCardAccessFailed" },
+ { 0x138A02, "GameCardUnknown" },
+ { 0x138C02, "GameCardUnexpectedDeadCode" },
+ { 0x138E02, "GameCardPreconditionViolation" },
+ { 0x139002, "GameCardNotImplemented" },
+ { 0x139C02, "GameCardQueueFullFailure" },
+ { 0x139E02, "GameCardLockerOutOfRange" },
+ { 0x13A802, "GameCardFailedIoMappingForGpio" },
+ { 0x13B002, "GameCardCardNotInserted" },
+ { 0x13B202, "GameCardCardIdMismatch" },
+ { 0x13B402, "GameCardCardNotActivated" },
+ { 0x13B602, "GameCardNotAwakened" },
+ { 0x13C402, "GameCardCardAccessFailure" },
+ { 0x13C602, "GameCardCardAccessTimeout" },
+ { 0x13C802, "GameCardCardFatal" },
+ { 0x13CA02, "GameCardCardNeedRetry" },
+ { 0x13CC02, "GameCardCardRetryFailure" },
+ { 0x13D002, "GameCardRetryLimitOut" },
+ { 0x13D202, "GameCardNeedRefresh" },
+ { 0x13D402, "GameCardNeedRefreshAndCardNeedRetry" },
+ { 0x13D802, "GameCardInvalidSecureAccess" },
+ { 0x13DA02, "GameCardInvalidNormalAccess" },
+ { 0x13DC02, "GameCardInvalidAccessAcrossMode" },
+ { 0x13DE02, "GameCardWrongCard" },
+ { 0x13E002, "GameCardInitialDataMismatch" },
+ { 0x13E202, "GameCardInitialNotFilledWithZero" },
+ { 0x13E402, "GameCardKekIndexMismatch" },
+ { 0x13E802, "GameCardInvalidGetCardDeviceCertificate" },
+ { 0x13EA02, "GameCardUnregisteredCardSecureMethod" },
+ { 0x13EC02, "GameCardCardNeedRetryAfterAsicReinitialize" },
+ { 0x13EE02, "GameCardCardHeaderReadFailure" },
+ { 0x13F002, "GameCardCardReinitializeFailure" },
+ { 0x13F202, "GameCardInvalidChallengeCardExistenceMode" },
+ { 0x13F402, "GameCardInvalidCardHeader" },
+ { 0x13F602, "GameCardInvalidT1CardCertificate" },
+ { 0x13FA02, "GameCardInvalidCa10Certificate" },
+ { 0x13FC02, "GameCardInvalidCa10CardHeader" },
+ { 0x140A02, "GameCardCommunicationFailure" },
+ { 0x140C02, "GameCardFinishOperationFailed" },
+ { 0x144A02, "GameCardStateTransitionFailure" },
+ { 0x144C02, "GameCardAlreadyTransitionedState" },
+ { 0x144E02, "GameCardShouldTransitFromAsicInitialToSecure" },
+ { 0x145002, "GameCardShouldTransitFromInitialToNormal" },
+ { 0x145202, "GameCardShouldTransitFromNormalModeToSecure" },
+ { 0x145402, "GameCardShouldTransitFromNormalModeToDebug" },
+ { 0x148A02, "GameCardInitializeAsicFailure" },
+ { 0x148C02, "GameCardAlreadyInitializedAsic" },
+ { 0x148E02, "GameCardActivateAsicFailure" },
+ { 0x149002, "GameCardAsicBootFailure" },
+ { 0x149402, "GameCardSendFirmwareFailure" },
+ { 0x149802, "GameCardVerifyCertificateFailure" },
+ { 0x149A02, "GameCardReceiveCertificateFailure" },
+ { 0x149C02, "GameCardParseCertificateFailure" },
+ { 0x149E02, "GameCardInvalidCertificate" },
+ { 0x14A002, "GameCardSendSocCertificateFailure" },
+ { 0x14A802, "GameCardGenerateCommonKeyFailure" },
+ { 0x14AA02, "GameCardReceiveRandomValueFailure" },
+ { 0x14AC02, "GameCardSendRandomValueFailure" },
+ { 0x14AE02, "GameCardDecryptRandomValueFailure" },
+ { 0x14B402, "GameCardAuthenticateMutuallyFailure" },
+ { 0x14B602, "GameCardReceiveDeviceChallengeFailure" },
+ { 0x14B802, "GameCardRespondDeviceChallengeFailure" },
+ { 0x14BA02, "GameCardSendHostChallengeFailure" },
+ { 0x14BC02, "GameCardReceiveChallengeResponseFailure" },
+ { 0x14BE02, "GameCardChallengeAndResponseFailure" },
+ { 0x14C402, "GameCardChangeModeToSecureFailure" },
+ { 0x14C602, "GameCardExchangeRandomValuesFailure" },
+ { 0x14C802, "GameCardAsicChallengeCardExistenceFailure" },
+ { 0x14CE02, "GameCardInitializeAsicTimeOut" },
+ { 0x14D202, "GameCardSplFailure" },
+ { 0x14D402, "GameCardSplDecryptAesKeyFailure" },
+ { 0x14D602, "GameCardSplDecryptAndStoreGcKeyFailure" },
+ { 0x14D802, "GameCardSplGenerateRandomBytesFailure" },
+ { 0x14DA02, "GameCardSplDecryptGcMessageFailure" },
+ { 0x14DE02, "GameCardReadRegisterFailure" },
+ { 0x14E002, "GameCardWriteRegisterFailure" },
+ { 0x14E202, "GameCardEnableCardBusFailure" },
+ { 0x14E402, "GameCardGetCardHeaderFailure" },
+ { 0x14E602, "GameCardAsicStatusError" },
+ { 0x14E802, "GameCardChangeGcModeToSecureFailure" },
+ { 0x14EA02, "GameCardChangeGcModeToDebugFailure" },
+ { 0x14EC02, "GameCardReadRmaInfoFailure" },
+ { 0x14F002, "GameCardUpdateKeyFailure" },
+ { 0x14F202, "GameCardKeySourceNotFound" },
+ { 0x150402, "GameCardStateFailure" },
+ { 0x150602, "GameCardStateCardNormalModeRequired" },
+ { 0x150802, "GameCardStateCardSecureModeRequired" },
+ { 0x150A02, "GameCardStateCardDebugModeRequired" },
+ { 0x150C02, "GameCardStateAsicInitialRequired" },
+ { 0x150E02, "GameCardStateAsicSecureRequired" },
+ { 0x151802, "GameCardGeneralIoFailure" },
+ { 0x151A02, "GameCardGeneralIoReleaseAsicResetFailure" },
+ { 0x151C02, "GameCardGeneralIoHoldAsicResetFailure" },
+ { 0x151E02, "GameCardSetVoltageFailure" },
+ { 0x152C02, "GameCardDataIoFailure" },
+ { 0x152E02, "GameCardDataIoActivateFailure" },
+ { 0x155402, "GameCardCardCommandFailure" },
+ { 0x155602, "GameCardCommandReadId1Failure" },
+ { 0x155802, "GameCardCommandReadId2Failure" },
+ { 0x155A02, "GameCardCommandReadId3Failure" },
+ { 0x155C02, "GameCardSendCardReadUidFailure" },
+ { 0x155E02, "GameCardCommandReadPageFailure" },
+ { 0x156002, "GameCardCommandReadPageUnalignedFailure" },
+ { 0x156202, "GameCardCommandWritePageFailure" },
+ { 0x156402, "GameCardCommandRefreshFailure" },
+ { 0x156602, "GameCardCommandUpdateKeyFailure" },
+ { 0x156802, "GameCardSendCardSelfRefreshFailure" },
+ { 0x156A02, "GameCardSendCardReadRefreshStatusFailure" },
+ { 0x156C02, "GameCardCommandReadCrcFailure" },
+ { 0x156E02, "GameCardCommandEraseFailure" },
+ { 0x157002, "GameCardCommandReadDevParamFailure" },
+ { 0x157202, "GameCardCommandWriteDevParamFailure" },
+ { 0x157402, "GameCardSendCardReadErrorCountFailure" },
+ { 0x16A802, "GameCardDevCardUnexpectedFailure" },
+ { 0x16AA02, "GameCardDebugParameterMismatch" },
+ { 0x16AC02, "GameCardDebugEraseFailure" },
+ { 0x16AE02, "GameCardDebugWriteCrcMismatch" },
+ { 0x16B002, "GameCardDebugCardReceivedIdMismatch" },
+ { 0x16B202, "GameCardDebugCardId1Mismatch" },
+ { 0x16B402, "GameCardDebugCardId2Mismatch" },
+ { 0x170C02, "GameCardFsFailure" },
+ { 0x170E02, "GameCardFsGetHandleFailure" },
+ { 0x171002, "GameCardFsCheckHandleInReadFailure" },
+ { 0x171202, "GameCardFsCheckHandleInWriteFailure" },
+ { 0x171402, "GameCardFsCheckHandleInGetStatusFailure" },
+ { 0x171602, "GameCardFsCheckHandleInGetDeviceCertFailure" },
+ { 0x171802, "GameCardFsCheckHandleInGetCardImageHashFailure" },
+ { 0x171A02, "GameCardFsCheckHandleInChallengeCardExistence" },
+ { 0x171C02, "GameCardFsCheckHandleInOnAcquireLock" },
+ { 0x171E02, "GameCardFsCheckModeInOnAcquireSecureLock" },
+ { 0x172002, "GameCardFsCheckHandleInCreateReadOnlyFailure" },
+ { 0x172202, "GameCardFsCheckHandleInCreateSecureReadOnlyFailure" },
+ { 0x172402, "GameCardFsInvalidCompatibilityType" },
+ { 0x172602, "GameCardNotSupportedOnDeviceModel" },
+ { 0x177002, "Internal" },
+ { 0x177202, "NotImplemented" },
+ { 0x177402, "UnsupportedVersion" },
+ { 0x177602, "AlreadyExists" },
+ { 0x177A02, "OutOfRange" },
+ { 0x183602, "StorageDeviceInvalidOperation" },
+ { 0x183802, "SystemPartitionNotReady" },
+ { 0x183A02, "StorageDeviceNotReady" },
+ { 0x190002, "AllocationMemoryFailed" },
+ { 0x190202, "AllocationMemoryFailedInFatFileSystemA" },
+ { 0x190602, "AllocationMemoryFailedInFatFileSystemC" },
+ { 0x190802, "AllocationMemoryFailedInFatFileSystemD" },
+ { 0x190A02, "AllocationMemoryFailedInFatFileSystemE" },
+ { 0x190C02, "AllocationMemoryFailedInFatFileSystemF" },
+ { 0x191002, "AllocationMemoryFailedInFatFileSystemH" },
+ { 0x191602, "AllocationMemoryFailedInFileSystemAccessorA" },
+ { 0x191802, "AllocationMemoryFailedInFileSystemAccessorB" },
+ { 0x191A02, "AllocationMemoryFailedInApplicationA" },
+ { 0x191C02, "AllocationMemoryFailedInBcatSaveDataA" },
+ { 0x191E02, "AllocationMemoryFailedInBisA" },
+ { 0x192002, "AllocationMemoryFailedInBisB" },
+ { 0x192202, "AllocationMemoryFailedInBisC" },
+ { 0x192402, "AllocationMemoryFailedInCodeA" },
+ { 0x192602, "AllocationMemoryFailedInContentA" },
+ { 0x192802, "AllocationMemoryFailedInContentStorageA" },
+ { 0x192A02, "AllocationMemoryFailedInContentStorageB" },
+ { 0x192C02, "AllocationMemoryFailedInDataA" },
+ { 0x192E02, "AllocationMemoryFailedInDataB" },
+ { 0x193002, "AllocationMemoryFailedInDeviceSaveDataA" },
+ { 0x193202, "AllocationMemoryFailedInGameCardA" },
+ { 0x193402, "AllocationMemoryFailedInGameCardB" },
+ { 0x193602, "AllocationMemoryFailedInGameCardC" },
+ { 0x193802, "AllocationMemoryFailedInGameCardD" },
+ { 0x193A02, "AllocationMemoryFailedInHostA" },
+ { 0x193C02, "AllocationMemoryFailedInHostB" },
+ { 0x193E02, "AllocationMemoryFailedInHostC" },
+ { 0x194002, "AllocationMemoryFailedInImageDirectoryA" },
+ { 0x194202, "AllocationMemoryFailedInLogoA" },
+ { 0x194402, "AllocationMemoryFailedInRomA" },
+ { 0x194602, "AllocationMemoryFailedInRomB" },
+ { 0x194802, "AllocationMemoryFailedInRomC" },
+ { 0x194A02, "AllocationMemoryFailedInRomD" },
+ { 0x194C02, "AllocationMemoryFailedInRomE" },
+ { 0x194E02, "AllocationMemoryFailedInRomF" },
+ { 0x195402, "AllocationMemoryFailedInSaveDataManagementA" },
+ { 0x195602, "AllocationMemoryFailedInSaveDataThumbnailA" },
+ { 0x195802, "AllocationMemoryFailedInSdCardA" },
+ { 0x195A02, "AllocationMemoryFailedInSdCardB" },
+ { 0x195C02, "AllocationMemoryFailedInSystemSaveDataA" },
+ { 0x195E02, "AllocationMemoryFailedInRomFsFileSystemA" },
+ { 0x196002, "AllocationMemoryFailedInRomFsFileSystemB" },
+ { 0x196202, "AllocationMemoryFailedInRomFsFileSystemC" },
+ { 0x196602, "AllocationMemoryFailedInGuidPartitionTableA" },
+ { 0x196802, "AllocationMemoryFailedInDeviceDetectionEventManagerA" },
+ { 0x196A02, "AllocationMemoryFailedInSaveDataFileSystemServiceImplA" },
+ { 0x196C02, "AllocationMemoryFailedInFileSystemProxyCoreImplB" },
+ { 0x196E02, "AllocationMemoryFailedInSdCardProxyFileSystemCreatorA" },
+ { 0x197002, "AllocationMemoryFailedInNcaFileSystemServiceImplA" },
+ { 0x197202, "AllocationMemoryFailedInNcaFileSystemServiceImplB" },
+ { 0x197402, "AllocationMemoryFailedInProgramRegistryManagerA" },
+ { 0x197602, "AllocationMemoryFailedInSdmmcStorageServiceA" },
+ { 0x197802, "AllocationMemoryFailedInBuiltInStorageCreatorA" },
+ { 0x197A02, "AllocationMemoryFailedInBuiltInStorageCreatorB" },
+ { 0x197C02, "AllocationMemoryFailedInBuiltInStorageCreatorC" },
+ { 0x198002, "AllocationMemoryFailedFatFileSystemWithBufferA" },
+ { 0x198202, "AllocationMemoryFailedInFatFileSystemCreatorA" },
+ { 0x198402, "AllocationMemoryFailedInFatFileSystemCreatorB" },
+ { 0x198602, "AllocationMemoryFailedInGameCardFileSystemCreatorA" },
+ { 0x198802, "AllocationMemoryFailedInGameCardFileSystemCreatorB" },
+ { 0x198A02, "AllocationMemoryFailedInGameCardFileSystemCreatorC" },
+ { 0x198C02, "AllocationMemoryFailedInGameCardFileSystemCreatorD" },
+ { 0x198E02, "AllocationMemoryFailedInGameCardFileSystemCreatorE" },
+ { 0x199002, "AllocationMemoryFailedInGameCardFileSystemCreatorF" },
+ { 0x199202, "AllocationMemoryFailedInGameCardManagerA" },
+ { 0x199402, "AllocationMemoryFailedInGameCardManagerB" },
+ { 0x199602, "AllocationMemoryFailedInGameCardManagerC" },
+ { 0x199802, "AllocationMemoryFailedInGameCardManagerD" },
+ { 0x199A02, "AllocationMemoryFailedInGameCardManagerE" },
+ { 0x199C02, "AllocationMemoryFailedInGameCardManagerF" },
+ { 0x199E02, "AllocationMemoryFailedInLocalFileSystemCreatorA" },
+ { 0x19A002, "AllocationMemoryFailedInPartitionFileSystemCreatorA" },
+ { 0x19A202, "AllocationMemoryFailedInRomFileSystemCreatorA" },
+ { 0x19A402, "AllocationMemoryFailedInSaveDataFileSystemCreatorA" },
+ { 0x19A602, "AllocationMemoryFailedInSaveDataFileSystemCreatorB" },
+ { 0x19A802, "AllocationMemoryFailedInSaveDataFileSystemCreatorC" },
+ { 0x19AA02, "AllocationMemoryFailedInSaveDataFileSystemCreatorD" },
+ { 0x19AC02, "AllocationMemoryFailedInSaveDataFileSystemCreatorE" },
+ { 0x19B002, "AllocationMemoryFailedInStorageOnNcaCreatorA" },
+ { 0x19B202, "AllocationMemoryFailedInStorageOnNcaCreatorB" },
+ { 0x19B402, "AllocationMemoryFailedInSubDirectoryFileSystemCreatorA" },
+ { 0x19B602, "AllocationMemoryFailedInTargetManagerFileSystemCreatorA" },
+ { 0x19B802, "AllocationMemoryFailedInSaveDataIndexerA" },
+ { 0x19BA02, "AllocationMemoryFailedInSaveDataIndexerB" },
+ { 0x19BC02, "AllocationMemoryFailedInFileSystemBuddyHeapA" },
+ { 0x19BE02, "AllocationMemoryFailedInFileSystemBufferManagerA" },
+ { 0x19C002, "AllocationMemoryFailedInBlockCacheBufferedStorageA" },
+ { 0x19C202, "AllocationMemoryFailedInBlockCacheBufferedStorageB" },
+ { 0x19C402, "AllocationMemoryFailedInDuplexStorageA" },
+ { 0x19D002, "AllocationMemoryFailedInIntegrityVerificationStorageA" },
+ { 0x19D202, "AllocationMemoryFailedInIntegrityVerificationStorageB" },
+ { 0x19D402, "AllocationMemoryFailedInJournalStorageA" },
+ { 0x19D602, "AllocationMemoryFailedInJournalStorageB" },
+ { 0x19DC02, "AllocationMemoryFailedInSaveDataFileSystemCoreA" },
+ { 0x19DE02, "AllocationMemoryFailedInSaveDataFileSystemCoreB" },
+ { 0x19E002, "AllocationMemoryFailedInAesXtsFileA" },
+ { 0x19E202, "AllocationMemoryFailedInAesXtsFileB" },
+ { 0x19E402, "AllocationMemoryFailedInAesXtsFileC" },
+ { 0x19E602, "AllocationMemoryFailedInAesXtsFileD" },
+ { 0x19E802, "AllocationMemoryFailedInAesXtsFileSystemA" },
+ { 0x19EE02, "AllocationMemoryFailedInConcatenationFileSystemA" },
+ { 0x19F002, "AllocationMemoryFailedInConcatenationFileSystemB" },
+ { 0x19F202, "AllocationMemoryFailedInDirectorySaveDataFileSystemA" },
+ { 0x19F402, "AllocationMemoryFailedInLocalFileSystemA" },
+ { 0x19F602, "AllocationMemoryFailedInLocalFileSystemB" },
+ { 0x1A1A02, "AllocationMemoryFailedInNcaFileSystemDriverI" },
+ { 0x1A2602, "AllocationMemoryFailedInPartitionFileSystemA" },
+ { 0x1A2802, "AllocationMemoryFailedInPartitionFileSystemB" },
+ { 0x1A2A02, "AllocationMemoryFailedInPartitionFileSystemC" },
+ { 0x1A2C02, "AllocationMemoryFailedInPartitionFileSystemMetaA" },
+ { 0x1A2E02, "AllocationMemoryFailedInPartitionFileSystemMetaB" },
+ { 0x1A3002, "AllocationMemoryFailedInRomFsFileSystemD" },
+ { 0x1A3602, "AllocationMemoryFailedInSubdirectoryFileSystemA" },
+ { 0x1A3802, "AllocationMemoryFailedInTmFileSystemA" },
+ { 0x1A3A02, "AllocationMemoryFailedInTmFileSystemB" },
+ { 0x1A3E02, "AllocationMemoryFailedInProxyFileSystemA" },
+ { 0x1A4002, "AllocationMemoryFailedInProxyFileSystemB" },
+ { 0x1A4402, "AllocationMemoryFailedInSaveDataExtraDataAccessorCacheManagerA" },
+ { 0x1A4602, "AllocationMemoryFailedInNcaReaderA" },
+ { 0x1A4A02, "AllocationMemoryFailedInRegisterA" },
+ { 0x1A4C02, "AllocationMemoryFailedInRegisterB" },
+ { 0x1A4E02, "AllocationMemoryFailedInPathNormalizer" },
+ { 0x1A5E02, "AllocationMemoryFailedInDbmRomKeyValueStorage" },
+ { 0x1A6002, "AllocationMemoryFailedInDbmHierarchicalRomFileTable" },
+ { 0x1A6202, "AllocationMemoryFailedInRomFsFileSystemE" },
+ { 0x1A6402, "AllocationMemoryFailedInISaveFileSystemA" },
+ { 0x1A6602, "AllocationMemoryFailedInISaveFileSystemB" },
+ { 0x1A6802, "AllocationMemoryFailedInRomOnFileA" },
+ { 0x1A6A02, "AllocationMemoryFailedInRomOnFileB" },
+ { 0x1A6C02, "AllocationMemoryFailedInRomOnFileC" },
+ { 0x1A6E02, "AllocationMemoryFailedInAesXtsFileE" },
+ { 0x1A7002, "AllocationMemoryFailedInAesXtsFileF" },
+ { 0x1A7202, "AllocationMemoryFailedInAesXtsFileG" },
+ { 0x1A7402, "AllocationMemoryFailedInReadOnlyFileSystemA" },
+ { 0x1A8402, "AllocationMemoryFailedInEncryptedFileSystemCreatorA" },
+ { 0x1A8E02, "AllocationMemoryFailedInAesCtrCounterExtendedStorageA" },
+ { 0x1A9002, "AllocationMemoryFailedInAesCtrCounterExtendedStorageB" },
+ { 0x1A9C02, "AllocationMemoryFailedInSdmmcStorageServiceB" },
+ { 0x1A9E02, "AllocationMemoryFailedInFileSystemInterfaceAdapterA" },
+ { 0x1AA002, "AllocationMemoryFailedInGameCardFileSystemCreatorG" },
+ { 0x1AA202, "AllocationMemoryFailedInGameCardFileSystemCreatorH" },
+ { 0x1AA402, "AllocationMemoryFailedInAesXtsFileSystemB" },
+ { 0x1AA602, "AllocationMemoryFailedInBufferedStorageA" },
+ { 0x1AA802, "AllocationMemoryFailedInIntegrityRomFsStorageA" },
+ { 0x1AB002, "AllocationMemoryFailedInSaveDataFileSystemServiceImplB" },
+ { 0x1AB802, "AllocationMemoryFailedNew" },
+ { 0x1ABA02, "AllocationMemoryFailedInFileSystemProxyImplA" },
+ { 0x1ABC02, "AllocationMemoryFailedMakeUnique" },
+ { 0x1ABE02, "AllocationMemoryFailedAllocateShared" },
+ { 0x1AC002, "AllocationPooledBufferNotEnoughSize" },
+ { 0x1AC802, "AllocationMemoryFailedInWriteThroughCacheStorageA" },
+ { 0x1ACA02, "AllocationMemoryFailedInSaveDataTransferManagerA" },
+ { 0x1ACC02, "AllocationMemoryFailedInSaveDataTransferManagerB" },
+ { 0x1ACE02, "AllocationMemoryFailedInHtcFileSystemA" },
+ { 0x1AD002, "AllocationMemoryFailedInHtcFileSystemB" },
+ { 0x1AD202, "AllocationMemoryFailedInGameCardManagerG" },
+ { 0x1B5802, "MmcAccessFailed" },
+ { 0x1B5A02, "PortMmcNoDevice" },
+ { 0x1B5C02, "PortMmcNotActivated" },
+ { 0x1B5E02, "PortMmcDeviceRemoved" },
+ { 0x1B6002, "PortMmcNotAwakened" },
+ { 0x1B9802, "PortMmcCommunicationError" },
+ { 0x1B9A02, "PortMmcCommunicationNotAttained" },
+ { 0x1B9C02, "PortMmcResponseIndexError" },
+ { 0x1B9E02, "PortMmcResponseEndBitError" },
+ { 0x1BA002, "PortMmcResponseCrcError" },
+ { 0x1BA202, "PortMmcResponseTimeoutError" },
+ { 0x1BA402, "PortMmcDataEndBitError" },
+ { 0x1BA602, "PortMmcDataCrcError" },
+ { 0x1BA802, "PortMmcDataTimeoutError" },
+ { 0x1BAA02, "PortMmcAutoCommandResponseIndexError" },
+ { 0x1BAC02, "PortMmcAutoCommandResponseEndBitError" },
+ { 0x1BAE02, "PortMmcAutoCommandResponseCrcError" },
+ { 0x1BB002, "PortMmcAutoCommandResponseTimeoutError" },
+ { 0x1BB202, "PortMmcCommandCompleteSwTimeout" },
+ { 0x1BB402, "PortMmcTransferCompleteSwTimeout" },
+ { 0x1BB802, "PortMmcDeviceStatusHasError" },
+ { 0x1BBA02, "PortMmcDeviceStatusAddressOutOfRange" },
+ { 0x1BBC02, "PortMmcDeviceStatusAddressMisalign" },
+ { 0x1BBE02, "PortMmcDeviceStatusBlockLenError" },
+ { 0x1BC002, "PortMmcDeviceStatusEraseSeqError" },
+ { 0x1BC202, "PortMmcDeviceStatusEraseParam" },
+ { 0x1BC402, "PortMmcDeviceStatusWpViolation" },
+ { 0x1BC602, "PortMmcDeviceStatusLockUnlockFailed" },
+ { 0x1BC802, "PortMmcDeviceStatusComCrcError" },
+ { 0x1BCA02, "PortMmcDeviceStatusIllegalCommand" },
+ { 0x1BCC02, "PortMmcDeviceStatusDeviceEccFailed" },
+ { 0x1BCE02, "PortMmcDeviceStatusCcError" },
+ { 0x1BD002, "PortMmcDeviceStatusError" },
+ { 0x1BD202, "PortMmcDeviceStatusCidCsdOverwrite" },
+ { 0x1BD402, "PortMmcDeviceStatusWpEraseSkip" },
+ { 0x1BD602, "PortMmcDeviceStatusEraseReset" },
+ { 0x1BD802, "PortMmcDeviceStatusSwitchError" },
+ { 0x1BE802, "PortMmcUnexpectedDeviceState" },
+ { 0x1BEA02, "PortMmcUnexpectedDeviceCsdValue" },
+ { 0x1BEC02, "PortMmcAbortTransactionSwTimeout" },
+ { 0x1BEE02, "PortMmcCommandInhibitCmdSwTimeout" },
+ { 0x1BF002, "PortMmcCommandInhibitDatSwTimeout" },
+ { 0x1BF202, "PortMmcBusySwTimeout" },
+ { 0x1BF402, "PortMmcIssueTuningCommandSwTimeout" },
+ { 0x1BF602, "PortMmcTuningFailed" },
+ { 0x1BF802, "PortMmcMmcInitializationSwTimeout" },
+ { 0x1BFA02, "PortMmcMmcNotSupportExtendedCsd" },
+ { 0x1BFC02, "PortMmcUnexpectedMmcExtendedCsdValue" },
+ { 0x1BFE02, "PortMmcMmcEraseSwTimeout" },
+ { 0x1C0002, "PortMmcSdCardValidationError" },
+ { 0x1C0202, "PortMmcSdCardInitializationSwTimeout" },
+ { 0x1C0402, "PortMmcSdCardGetValidRcaSwTimeout" },
+ { 0x1C0602, "PortMmcUnexpectedSdCardAcmdDisabled" },
+ { 0x1C0802, "PortMmcSdCardNotSupportSwitchFunctionStatus" },
+ { 0x1C0A02, "PortMmcUnexpectedSdCardSwitchFunctionStatus" },
+ { 0x1C0C02, "PortMmcSdCardNotSupportAccessMode" },
+ { 0x1C0E02, "PortMmcSdCardNot4BitBusWidthAtUhsIMode" },
+ { 0x1C1002, "PortMmcSdCardNotSupportSdr104AndSdr50" },
+ { 0x1C1202, "PortMmcSdCardCannotSwitchedAccessMode" },
+ { 0x1C1402, "PortMmcSdCardFailedSwitchedAccessMode" },
+ { 0x1C1602, "PortMmcSdCardUnacceptableCurrentConsumption" },
+ { 0x1C1802, "PortMmcSdCardNotReadyToVoltageSwitch" },
+ { 0x1C1A02, "PortMmcSdCardNotCompleteVoltageSwitch" },
+ { 0x1C5802, "PortMmcHostControllerUnexpected" },
+ { 0x1C5A02, "PortMmcInternalClockStableSwTimeout" },
+ { 0x1C5C02, "PortMmcSdHostStandardUnknownAutoCmdError" },
+ { 0x1C5E02, "PortMmcSdHostStandardUnknownError" },
+ { 0x1C6002, "PortMmcSdmmcDllCalibrationSwTimeout" },
+ { 0x1C6202, "PortMmcSdmmcDllApplicationSwTimeout" },
+ { 0x1C6402, "PortMmcSdHostStandardFailSwitchTo18V" },
+ { 0x1C9802, "PortMmcInternalError" },
+ { 0x1C9A02, "PortMmcNoWaitedInterrupt" },
+ { 0x1C9C02, "PortMmcWaitInterruptSwTimeout" },
+ { 0x1CD802, "PortMmcAbortCommandIssued" },
+ { 0x1CE802, "PortMmcNotSupported" },
+ { 0x1CEA02, "PortMmcNotImplemented" },
+ { 0x1F3C02, "PortMmcStorageDeviceInvalidated" },
+ { 0x1F3E02, "PortMmcUnexpected" },
+ { 0x1F4002, "DataCorrupted" },
+ { 0x1F4202, "RomCorrupted" },
+ { 0x1F4402, "UnsupportedRomVersion" },
+ { 0x1F5602, "AesCtrCounterExtendedStorageCorrupted" },
+ { 0x1F5802, "InvalidAesCtrCounterExtendedEntryOffset" },
+ { 0x1F5A02, "InvalidAesCtrCounterExtendedTableSize" },
+ { 0x1F5C02, "InvalidAesCtrCounterExtendedGeneration" },
+ { 0x1F5E02, "InvalidAesCtrCounterExtendedOffset" },
+ { 0x1F6002, "InvalidAesCtrCounterExtendedDataStorageSize" },
+ { 0x1F6202, "InvalidAesCtrCounterExtendedMetaStorageSize" },
+ { 0x1F6A02, "IndirectStorageCorrupted" },
+ { 0x1F6C02, "InvalidIndirectEntryOffset" },
+ { 0x1F6E02, "InvalidIndirectEntryStorageIndex" },
+ { 0x1F7002, "InvalidIndirectStorageSize" },
+ { 0x1F7202, "InvalidIndirectVirtualOffset" },
+ { 0x1F7402, "InvalidIndirectPhysicalOffset" },
+ { 0x1F7602, "InvalidIndirectStorageIndex" },
+ { 0x1F7802, "InvalidIndirectStorageBucketTreeSize" },
+ { 0x1F7E02, "BucketTreeCorrupted" },
+ { 0x1F8002, "InvalidBucketTreeSignature" },
+ { 0x1F8202, "InvalidBucketTreeEntryCount" },
+ { 0x1F8402, "InvalidBucketTreeNodeEntryCount" },
+ { 0x1F8602, "InvalidBucketTreeNodeOffset" },
+ { 0x1F8802, "InvalidBucketTreeEntryOffset" },
+ { 0x1F8A02, "InvalidBucketTreeEntrySetOffset" },
+ { 0x1F8C02, "InvalidBucketTreeNodeIndex" },
+ { 0x1F8E02, "InvalidBucketTreeVirtualOffset" },
+ { 0x1F9202, "RomNcaCorrupted" },
+ { 0x1FA602, "RomNcaFileSystemCorrupted" },
+ { 0x1FA802, "InvalidRomNcaFileSystemType" },
+ { 0x1FAA02, "InvalidRomAcidFileSize" },
+ { 0x1FAC02, "InvalidRomAcidSize" },
+ { 0x1FAE02, "InvalidRomAcid" },
+ { 0x1FB002, "RomAcidVerificationFailed" },
+ { 0x1FB202, "InvalidRomNcaSignature" },
+ { 0x1FB402, "RomNcaHeaderSignature1VerificationFailed" },
+ { 0x1FB602, "RomNcaHeaderSignature2VerificationFailed" },
+ { 0x1FB802, "RomNcaFsHeaderHashVerificationFailed" },
+ { 0x1FBA02, "InvalidRomNcaKeyIndex" },
+ { 0x1FBC02, "InvalidRomNcaFsHeaderHashType" },
+ { 0x1FBE02, "InvalidRomNcaFsHeaderEncryptionType" },
+ { 0x1FC002, "InvalidRomNcaPatchInfoIndirectSize" },
+ { 0x1FC202, "InvalidRomNcaPatchInfoAesCtrExSize" },
+ { 0x1FC402, "InvalidRomNcaPatchInfoAesCtrExOffset" },
+ { 0x1FC602, "InvalidRomNcaId" },
+ { 0x1FC802, "InvalidRomNcaHeader" },
+ { 0x1FCA02, "InvalidRomNcaFsHeader" },
+ { 0x1FCC02, "InvalidRomNcaPatchInfoIndirectOffset" },
+ { 0x1FCE02, "RomNcaHierarchicalSha256StorageCorrupted" },
+ { 0x1FD002, "InvalidRomHierarchicalSha256BlockSize" },
+ { 0x1FD202, "InvalidRomHierarchicalSha256LayerCount" },
+ { 0x1FD402, "RomHierarchicalSha256BaseStorageTooLarge" },
+ { 0x1FD602, "RomHierarchicalSha256HashVerificationFailed" },
+ { 0x1FE202, "InvalidRomHierarchicalIntegrityVerificationLayerCount" },
+ { 0x1FE402, "RomNcaIndirectStorageOutOfRange" },
+ { 0x1FE602, "RomNcaInvalidCompressionInfo" },
+ { 0x205A02, "RomIntegrityVerificationStorageCorrupted" },
+ { 0x205C02, "IncorrectRomIntegrityVerificationMagicCode" },
+ { 0x205E02, "InvalidRomZeroSignature" },
+ { 0x206002, "RomNonRealDataVerificationFailed" },
+ { 0x206E02, "RomRealDataVerificationFailed" },
+ { 0x207002, "ClearedRomRealDataVerificationFailed" },
+ { 0x207202, "UnclearedRomRealDataVerificationFailed" },
+ { 0x20AA02, "RomPartitionFileSystemCorrupted" },
+ { 0x20AC02, "InvalidRomSha256PartitionHashTarget" },
+ { 0x20AE02, "RomSha256PartitionHashVerificationFailed" },
+ { 0x20B002, "RomPartitionSignatureVerificationFailed" },
+ { 0x20B202, "RomSha256PartitionSignatureVerificationFailed" },
+ { 0x20B402, "InvalidRomPartitionEntryOffset" },
+ { 0x20B602, "InvalidRomSha256PartitionMetaDataSize" },
+ { 0x20D202, "RomBuiltInStorageCorrupted" },
+ { 0x20D402, "RomGptHeaderSignatureVerificationFailed" },
+ { 0x212202, "RomHostFileSystemCorrupted" },
+ { 0x212402, "RomHostEntryCorrupted" },
+ { 0x212602, "RomHostFileDataCorrupted" },
+ { 0x212802, "RomHostFileCorrupted" },
+ { 0x212A02, "InvalidRomHostHandle" },
+ { 0x214A02, "RomDatabaseCorrupted" },
+ { 0x214C02, "InvalidRomAllocationTableBlock" },
+ { 0x214E02, "InvalidRomKeyValueListElementIndex" },
+ { 0x217002, "RomStorageCorrupted" },
+ { 0x217202, "InvalidRomStorageSize" },
+ { 0x219A02, "SaveDataCorrupted" },
+ { 0x219C02, "UnsupportedSaveDataVersion" },
+ { 0x219E02, "InvalidSaveDataEntryType" },
+ { 0x21A002, "ReconstructibleSaveDataCorrupted" },
+ { 0x21AE02, "SaveDataFileSystemCorrupted" },
+ { 0x21B002, "InvalidJournalIntegritySaveDataHashSize" },
+ { 0x21B202, "InvalidJournalIntegritySaveDataCommitState" },
+ { 0x21B402, "InvalidJournalIntegritySaveDataControlAreaSize" },
+ { 0x21B602, "JournalIntegritySaveDataControlAreaVerificationFailed" },
+ { 0x21B802, "JournalIntegritySaveDataMasterSignatureVerificationFailed" },
+ { 0x21BA02, "IncorrectJournalIntegritySaveDataMagicCode" },
+ { 0x21C202, "SaveDataDuplexStorageCorrupted" },
+ { 0x21C402, "IncorrectDuplexMagicCode" },
+ { 0x21C602, "DuplexStorageAccessOutOfRange" },
+ { 0x21D602, "SaveDataMapCorrupted" },
+ { 0x21D802, "InvalidMapEntryCount" },
+ { 0x21DA02, "InvalidMapOffset" },
+ { 0x21DC02, "InvalidMapSize" },
+ { 0x21DE02, "InvalidMapAlignment" },
+ { 0x21E002, "InvalidMapStorageType" },
+ { 0x21E202, "MapAddressAlreadyRegistered" },
+ { 0x21E402, "MapStorageNotFound" },
+ { 0x21E602, "InvalidMapStorageSize" },
+ { 0x21EA02, "SaveDataLogCorrupted" },
+ { 0x21EC02, "InvalidLogBlockSize" },
+ { 0x21EE02, "InvalidLogOffset" },
+ { 0x21F002, "UnexpectedEndOfLog" },
+ { 0x21F202, "LogNotFound" },
+ { 0x220002, "ThumbnailHashVerificationFailed" },
+ { 0x220A02, "InvalidSaveDataInternalStorageIntegritySeedSize" },
+ { 0x220C02, "InvalidSaveDataInternalStorageAllocationTableFreeBitmapSizeA" },
+ { 0x220E02, "InvalidSaveDataInternalStorageAllocationTableFreeBitmapSizeB" },
+ { 0x221202, "SaveDataIntegrityVerificationStorageCorrupted" },
+ { 0x221402, "IncorrectSaveDataIntegrityVerificationMagicCode" },
+ { 0x221602, "InvalidSaveDataZeroHash" },
+ { 0x221802, "SaveDataNonRealDataVerificationFailed" },
+ { 0x222602, "SaveDataRealDataVerificationFailed" },
+ { 0x222802, "ClearedSaveDataRealDataVerificationFailed" },
+ { 0x222A02, "UnclearedSaveDataRealDataVerificationFailed" },
+ { 0x226202, "SaveDataBuiltInStorageCorrupted" },
+ { 0x226402, "SaveDataGptHeaderSignatureVerificationFailed" },
+ { 0x227602, "SaveDataCoreFileSystemCorrupted" },
+ { 0x227802, "IncorrectSaveDataFileSystemMagicCode" },
+ { 0x227A02, "InvalidSaveDataFileReadOffset" },
+ { 0x227C02, "InvalidSaveDataCoreDataStorageSize" },
+ { 0x229602, "IncompleteBlockInZeroBitmapHashStorageFileSaveData" },
+ { 0x229E02, "JournalStorageCorrupted" },
+ { 0x22A002, "JournalStorageAccessOutOfRange" },
+ { 0x22A202, "InvalidJournalStorageDataStorageSize" },
+ { 0x22B202, "SaveDataHostFileSystemCorrupted" },
+ { 0x22B402, "SaveDataHostEntryCorrupted" },
+ { 0x22B602, "SaveDataHostFileDataCorrupted" },
+ { 0x22B802, "SaveDataHostFileCorrupted" },
+ { 0x22BA02, "InvalidSaveDataHostHandle" },
+ { 0x22C602, "MappingTableCorrupted" },
+ { 0x22C802, "InvalidMappingTableEntryCount" },
+ { 0x22CA02, "InvalidMappingTablePhysicalIndex" },
+ { 0x22CC02, "InvalidMappingTableVirtualIndex" },
+ { 0x22DA02, "SaveDataDatabaseCorrupted" },
+ { 0x22DC02, "InvalidSaveDataAllocationTableBlock" },
+ { 0x22DE02, "InvalidSaveDataKeyValueListElementIndex" },
+ { 0x22E002, "InvalidSaveDataAllocationTableChainEntry" },
+ { 0x22E202, "InvalidSaveDataAllocationTableOffset" },
+ { 0x22E402, "InvalidSaveDataAllocationTableBlockCount" },
+ { 0x22E602, "InvalidSaveDataKeyValueListEntryIndex" },
+ { 0x22E802, "InvalidSaveDataBitmapIndex" },
+ { 0x230202, "SaveDataExtensionContextCorrupted" },
+ { 0x230402, "IncorrectSaveDataExtensionContextMagicCode" },
+ { 0x230602, "InvalidSaveDataExtensionContextState" },
+ { 0x230802, "DifferentSaveDataExtensionContextParameter" },
+ { 0x230A02, "InvalidSaveDataExtensionContextParameter" },
+ { 0x231602, "IntegritySaveDataCorrupted" },
+ { 0x231802, "InvalidIntegritySaveDataHashSize" },
+ { 0x231C02, "InvalidIntegritySaveDataControlAreaSize" },
+ { 0x231E02, "IntegritySaveDataControlAreaVerificationFailed" },
+ { 0x232002, "IntegritySaveDataMasterSignatureVerificationFailed" },
+ { 0x232202, "IncorrectIntegritySaveDataMagicCode" },
+ { 0x232A02, "NcaCorrupted" },
+ { 0x233802, "NcaBaseStorageOutOfRangeA" },
+ { 0x233A02, "NcaBaseStorageOutOfRangeB" },
+ { 0x233C02, "NcaBaseStorageOutOfRangeC" },
+ { 0x233E02, "NcaFileSystemCorrupted" },
+ { 0x234002, "InvalidNcaFileSystemType" },
+ { 0x234202, "InvalidAcidFileSize" },
+ { 0x234402, "InvalidAcidSize" },
+ { 0x234602, "InvalidAcid" },
+ { 0x234802, "AcidVerificationFailed" },
+ { 0x234A02, "InvalidNcaSignature" },
+ { 0x234C02, "NcaHeaderSignature1VerificationFailed" },
+ { 0x234E02, "NcaHeaderSignature2VerificationFailed" },
+ { 0x235002, "NcaFsHeaderHashVerificationFailed" },
+ { 0x235202, "InvalidNcaKeyIndex" },
+ { 0x235402, "InvalidNcaFsHeaderHashType" },
+ { 0x235602, "InvalidNcaFsHeaderEncryptionType" },
+ { 0x235802, "InvalidNcaPatchInfoIndirectSize" },
+ { 0x235A02, "InvalidNcaPatchInfoAesCtrExSize" },
+ { 0x235C02, "InvalidNcaPatchInfoAesCtrExOffset" },
+ { 0x235E02, "InvalidNcaId" },
+ { 0x236002, "InvalidNcaHeader" },
+ { 0x236202, "InvalidNcaFsHeader" },
+ { 0x236402, "InvalidNcaPatchInfoIndirectOffset" },
+ { 0x236602, "NcaHierarchicalSha256StorageCorrupted" },
+ { 0x236802, "InvalidHierarchicalSha256BlockSize" },
+ { 0x236A02, "InvalidHierarchicalSha256LayerCount" },
+ { 0x236C02, "HierarchicalSha256BaseStorageTooLarge" },
+ { 0x236E02, "HierarchicalSha256HashVerificationFailed" },
+ { 0x237A02, "InvalidHierarchicalIntegrityVerificationLayerCount" },
+ { 0x237C02, "NcaIndirectStorageOutOfRange" },
+ { 0x237E02, "InvalidNcaHeader1SignatureKeyGeneration" },
+ { 0x238202, "InvalidNspdVerificationData" },
+ { 0x238402, "MissingNspdVerificationData" },
+ { 0x238602, "NcaInvalidCompressionInfo" },
+ { 0x23F202, "IntegrityVerificationStorageCorrupted" },
+ { 0x23F402, "IncorrectIntegrityVerificationMagicCode" },
+ { 0x23F602, "InvalidZeroHash" },
+ { 0x23F802, "NonRealDataVerificationFailed" },
+ { 0x240602, "RealDataVerificationFailed" },
+ { 0x240802, "ClearedRealDataVerificationFailed" },
+ { 0x240A02, "UnclearedRealDataVerificationFailed" },
+ { 0x244202, "PartitionFileSystemCorrupted" },
+ { 0x244402, "InvalidSha256PartitionHashTarget" },
+ { 0x244602, "Sha256PartitionHashVerificationFailed" },
+ { 0x244802, "PartitionSignatureVerificationFailed" },
+ { 0x244A02, "Sha256PartitionSignatureVerificationFailed" },
+ { 0x244C02, "InvalidPartitionEntryOffset" },
+ { 0x244E02, "InvalidSha256PartitionMetaDataSize" },
+ { 0x246A02, "BuiltInStorageCorrupted" },
+ { 0x246C02, "GptHeaderSignatureVerificationFailed" },
+ { 0x247002, "GptHeaderInvalidPartitionSize" },
+ { 0x249202, "FatFileSystemCorrupted" },
+ { 0x249602, "InvalidFatFormat" },
+ { 0x249802, "InvalidFatFileNumber" },
+ { 0x249A02, "ExFatUnavailable" },
+ { 0x249C02, "InvalidFatFormatBisUser" },
+ { 0x249E02, "InvalidFatFormatBisSystem" },
+ { 0x24A002, "InvalidFatFormatBisSafe" },
+ { 0x24A202, "InvalidFatFormatBisCalibration" },
+ { 0x24A402, "InvalidFatFormatSd" },
+ { 0x24BA02, "HostFileSystemCorrupted" },
+ { 0x24BC02, "HostEntryCorrupted" },
+ { 0x24BE02, "HostFileDataCorrupted" },
+ { 0x24C002, "HostFileCorrupted" },
+ { 0x24C202, "InvalidHostHandle" },
+ { 0x24E202, "DatabaseCorrupted" },
+ { 0x24E402, "InvalidAllocationTableBlock" },
+ { 0x24E602, "InvalidKeyValueListElementIndex" },
+ { 0x24E802, "InvalidAllocationTableChainEntry" },
+ { 0x24EA02, "InvalidAllocationTableOffset" },
+ { 0x24EC02, "InvalidAllocationTableBlockCount" },
+ { 0x24EE02, "InvalidKeyValueListEntryIndex" },
+ { 0x24F002, "InvalidBitmapIndex" },
+ { 0x250A02, "AesXtsFileSystemCorrupted" },
+ { 0x250C02, "AesXtsFileSystemFileHeaderSizeCorruptedOnFileOpen" },
+ { 0x250E02, "AesXtsFileSystemFileHeaderCorruptedOnFileOpen" },
+ { 0x251002, "AesXtsFileSystemFileNoHeaderOnFileOpen" },
+ { 0x251202, "AesXtsFileSystemFileSizeCorruptedOnFileOpen" },
+ { 0x251402, "AesXtsFileSystemFileSizeCorruptedOnFileSetSize" },
+ { 0x251602, "AesXtsFileSystemFileHeaderCorruptedOnRename" },
+ { 0x251802, "AesXtsFileSystemFileHeaderCorruptedOnFileSetSize" },
+ { 0x253202, "SaveDataTransferDataCorrupted" },
+ { 0x253402, "SaveDataTransferTokenMacVerificationFailed" },
+ { 0x253602, "SaveDataTransferTokenSignatureVerificationFailed" },
+ { 0x253802, "SaveDataTransferTokenChallengeVerificationFailed" },
+ { 0x253A02, "SaveDataTransferImportMacVerificationFailed" },
+ { 0x253C02, "SaveDataTransferInitialDataMacVerificationFailed" },
+ { 0x253E02, "SaveDataTransferInitialDataVersionVerificationFailed" },
+ { 0x254602, "SignedSystemPartitionDataCorrupted" },
+ { 0x254802, "SignedSystemPartitionInvalidSize" },
+ { 0x254A02, "SignedSystemPartitionSignatureVerificationFailed" },
+ { 0x254C02, "SignedSystemPartitionHashVerificationFailed" },
+ { 0x254E02, "SignedSystemPartitionPackage2HashVerificationFailed" },
+ { 0x255002, "SignedSystemPartitionInvalidAppendHashCount" },
+ { 0x255A02, "GameCardLogoDataCorrupted" },
+ { 0x256202, "SimulatedDeviceDataCorrupted" },
+ { 0x256C02, "MultiCommitContextCorrupted" },
+ { 0x256E02, "InvalidMultiCommitContextVersion" },
+ { 0x257002, "InvalidMultiCommitContextState" },
+ { 0x258402, "ConcatenationFsInvalidInternalFileCount" },
+ { 0x259602, "ZeroBitmapFileCorrupted" },
+ { 0x259802, "IncompleteBlockInZeroBitmapHashStorageFile" },
+ { 0x271002, "Unexpected" },
+ { 0x271202, "FatFsUnexpected" },
+ { 0x271402, "FatFsUnclassified" },
+ { 0x271602, "FatFsStorageStateMissmatch" },
+ { 0x274002, "FatFsTooManyFilesOpenedS" },
+ { 0x274202, "FatFsTooManyFilesOpenedU" },
+ { 0x274402, "FatFsNotAFile" },
+ { 0x274802, "FatFsLockError" },
+ { 0x274A02, "FatFsInternalError" },
+ { 0x277E02, "FatFsModuleSafeError" },
+ { 0x27EC02, "FatFsUnexpectedSystemError" },
+ { 0x280002, "FatFsFormatUnexpected" },
+ { 0x280202, "FatFsFormatUnsupportedSize" },
+ { 0x280402, "FatFsFormatInvalidBpb" },
+ { 0x280602, "FatFsFormatInvalidParameter" },
+ { 0x280802, "FatFsFormatIllegalSectorsA" },
+ { 0x280A02, "FatFsFormatIllegalSectorsB" },
+ { 0x280C02, "FatFsFormatIllegalSectorsC" },
+ { 0x280E02, "FatFsFormatIllegalSectorsD" },
+ { 0x281602, "FatFsWriteVerifyError" },
+ { 0x296A02, "UnexpectedInMountTableA" },
+ { 0x296C02, "UnexpectedInJournalIntegritySaveDataFileSystemA" },
+ { 0x296E02, "UnexpectedInJournalIntegritySaveDataFileSystemB" },
+ { 0x297002, "UnexpectedInJournalIntegritySaveDataFileSystemC" },
+ { 0x297202, "UnexpectedInLocalFileSystemA" },
+ { 0x297402, "UnexpectedInLocalFileSystemB" },
+ { 0x297602, "UnexpectedInLocalFileSystemC" },
+ { 0x297802, "UnexpectedInLocalFileSystemD" },
+ { 0x297A02, "UnexpectedInLocalFileSystemE" },
+ { 0x297C02, "UnexpectedInLocalFileSystemF" },
+ { 0x297E02, "UnexpectedInPathToolA" },
+ { 0x298002, "UnexpectedInPathOnExecutionDirectoryA" },
+ { 0x298202, "UnexpectedInPathOnExecutionDirectoryB" },
+ { 0x298402, "UnexpectedInPathOnExecutionDirectoryC" },
+ { 0x298602, "UnexpectedInAesCtrStorageA" },
+ { 0x298802, "UnexpectedInAesXtsStorageA" },
+ { 0x298A02, "UnexpectedInSaveDataInternalStorageFileSystemA" },
+ { 0x298C02, "UnexpectedInSaveDataInternalStorageFileSystemB" },
+ { 0x298E02, "UnexpectedInMountUtilityA" },
+ { 0x299002, "UnexpectedInNcaFileSystemServiceImplA" },
+ { 0x299202, "UnexpectedInRamDiskFileSystemA" },
+ { 0x299402, "UnexpectedInBisWiperA" },
+ { 0x299602, "UnexpectedInBisWiperB" },
+ { 0x299802, "UnexpectedInCompressedStorageA" },
+ { 0x299A02, "UnexpectedInCompressedStorageB" },
+ { 0x299C02, "UnexpectedInCompressedStorageC" },
+ { 0x299E02, "UnexpectedInCompressedStorageD" },
+ { 0x29A002, "UnexpectedInPathA" },
+ { 0x2EE002, "PreconditionViolation" },
+ { 0x2EE202, "InvalidArgument" },
+ { 0x2EE402, "InvalidPath" },
+ { 0x2EE602, "TooLongPath" },
+ { 0x2EE802, "InvalidCharacter" },
+ { 0x2EEA02, "InvalidPathFormat" },
+ { 0x2EEC02, "DirectoryUnobtainable" },
+ { 0x2EEE02, "NotNormalized" },
+ { 0x2F1C02, "InvalidPathForOperation" },
+ { 0x2F1E02, "DirectoryUndeletable" },
+ { 0x2F2002, "DirectoryUnrenamable" },
+ { 0x2F2202, "IncompatiblePath" },
+ { 0x2F2402, "RenameToOtherFileSystem" },
+ { 0x2F5A02, "InvalidOffset" },
+ { 0x2F5C02, "InvalidSize" },
+ { 0x2F5E02, "NullptrArgument" },
+ { 0x2F6002, "InvalidAlignment" },
+ { 0x2F6202, "InvalidMountName" },
+ { 0x2F6402, "ExtensionSizeTooLarge" },
+ { 0x2F6602, "ExtensionSizeInvalid" },
+ { 0x2F6802, "InvalidHandle" },
+ { 0x2F6A02, "CacheStorageSizeTooLarge" },
+ { 0x2F6C02, "CacheStorageIndexTooLarge" },
+ { 0x2F6E02, "InvalidCommitNameCount" },
+ { 0x2F7002, "InvalidModeForFileOpen" },
+ { 0x2F7202, "InvalidFileSize" },
+ { 0x2F7402, "InvalidModeForDirectoryOpen" },
+ { 0x2F7602, "InvalidCommitOption" },
+ { 0x2F8002, "InvalidEnumValue" },
+ { 0x2F8202, "InvalidSaveDataState" },
+ { 0x2F8402, "InvalidSaveDataSpaceId" },
+ { 0x2FAA02, "GameCardLogoDataTooLarge" },
+ { 0x2FAC02, "FileDataCacheMemorySizeTooSmall" },
+ { 0x307002, "InvalidOperationForOpenMode" },
+ { 0x307202, "FileExtensionWithoutOpenModeAllowAppend" },
+ { 0x307402, "ReadUnpermitted" },
+ { 0x307602, "WriteUnpermitted" },
+ { 0x313802, "UnsupportedOperation" },
+ { 0x313A02, "UnsupportedCommitTarget" },
+ { 0x313C02, "UnsupportedSetSizeForNotResizableSubStorage" },
+ { 0x313E02, "UnsupportedSetSizeForResizableSubStorage" },
+ { 0x314002, "UnsupportedSetSizeForMemoryStorage" },
+ { 0x314202, "UnsupportedOperateRangeForMemoryStorage" },
+ { 0x314402, "UnsupportedOperateRangeForFileStorage" },
+ { 0x314602, "UnsupportedOperateRangeForFileHandleStorage" },
+ { 0x314802, "UnsupportedOperateRangeForSwitchStorage" },
+ { 0x314A02, "UnsupportedOperateRangeForStorageServiceObjectAdapter" },
+ { 0x314C02, "UnsupportedWriteForAesCtrCounterExtendedStorage" },
+ { 0x314E02, "UnsupportedSetSizeForAesCtrCounterExtendedStorage" },
+ { 0x315002, "UnsupportedOperateRangeForAesCtrCounterExtendedStorage" },
+ { 0x315202, "UnsupportedWriteForAesCtrStorageExternal" },
+ { 0x315402, "UnsupportedSetSizeForAesCtrStorageExternal" },
+ { 0x315602, "UnsupportedSetSizeForAesCtrStorage" },
+ { 0x315802, "UnsupportedSetSizeForHierarchicalIntegrityVerificationStorage" },
+ { 0x315A02, "UnsupportedOperateRangeForHierarchicalIntegrityVerificationStorage" },
+ { 0x315C02, "UnsupportedSetSizeForIntegrityVerificationStorage" },
+ { 0x315E02, "UnsupportedOperateRangeForWritableIntegrityVerificationStorage" },
+ { 0x316002, "UnsupportedOperateRangeForIntegrityVerificationStorage" },
+ { 0x316202, "UnsupportedSetSizeForBlockCacheBufferedStorage" },
+ { 0x316402, "UnsupportedOperateRangeForWritableBlockCacheBufferedStorage" },
+ { 0x316602, "UnsupportedOperateRangeForBlockCacheBufferedStorage" },
+ { 0x316802, "UnsupportedWriteForIndirectStorage" },
+ { 0x316A02, "UnsupportedSetSizeForIndirectStorage" },
+ { 0x316C02, "UnsupportedOperateRangeForIndirectStorage" },
+ { 0x316E02, "UnsupportedWriteForZeroStorage" },
+ { 0x317002, "UnsupportedSetSizeForZeroStorage" },
+ { 0x317202, "UnsupportedSetSizeForHierarchicalSha256Storage" },
+ { 0x317402, "UnsupportedWriteForReadOnlyBlockCacheStorage" },
+ { 0x317602, "UnsupportedSetSizeForReadOnlyBlockCacheStorage" },
+ { 0x317802, "UnsupportedSetSizeForIntegrityRomFsStorage" },
+ { 0x317A02, "UnsupportedSetSizeForDuplexStorage" },
+ { 0x317C02, "UnsupportedOperateRangeForDuplexStorage" },
+ { 0x317E02, "UnsupportedSetSizeForHierarchicalDuplexStorage" },
+ { 0x318002, "UnsupportedGetSizeForRemapStorage" },
+ { 0x318202, "UnsupportedSetSizeForRemapStorage" },
+ { 0x318402, "UnsupportedOperateRangeForRemapStorage" },
+ { 0x318602, "UnsupportedSetSizeForIntegritySaveDataStorage" },
+ { 0x318802, "UnsupportedOperateRangeForIntegritySaveDataStorage" },
+ { 0x318A02, "UnsupportedSetSizeForJournalIntegritySaveDataStorage" },
+ { 0x318C02, "UnsupportedOperateRangeForJournalIntegritySaveDataStorage" },
+ { 0x318E02, "UnsupportedGetSizeForJournalStorage" },
+ { 0x319002, "UnsupportedSetSizeForJournalStorage" },
+ { 0x319202, "UnsupportedOperateRangeForJournalStorage" },
+ { 0x319402, "UnsupportedSetSizeForUnionStorage" },
+ { 0x319602, "UnsupportedSetSizeForAllocationTableStorage" },
+ { 0x319802, "UnsupportedReadForWriteOnlyGameCardStorage" },
+ { 0x319A02, "UnsupportedSetSizeForWriteOnlyGameCardStorage" },
+ { 0x319C02, "UnsupportedWriteForReadOnlyGameCardStorage" },
+ { 0x319E02, "UnsupportedSetSizeForReadOnlyGameCardStorage" },
+ { 0x31A002, "UnsupportedOperateRangeForReadOnlyGameCardStorage" },
+ { 0x31A202, "UnsupportedSetSizeForSdmmcStorage" },
+ { 0x31A402, "UnsupportedOperateRangeForSdmmcStorage" },
+ { 0x31A602, "UnsupportedOperateRangeForFatFile" },
+ { 0x31A802, "UnsupportedOperateRangeForStorageFile" },
+ { 0x31AA02, "UnsupportedSetSizeForInternalStorageConcatenationFile" },
+ { 0x31AC02, "UnsupportedOperateRangeForInternalStorageConcatenationFile" },
+ { 0x31AE02, "UnsupportedQueryEntryForConcatenationFileSystem" },
+ { 0x31B002, "UnsupportedOperateRangeForConcatenationFile" },
+ { 0x31B202, "UnsupportedSetSizeForZeroBitmapFile" },
+ { 0x31B402, "UnsupportedOperateRangeForFileServiceObjectAdapter" },
+ { 0x31B602, "UnsupportedOperateRangeForAesXtsFile" },
+ { 0x31B802, "UnsupportedWriteForRomFsFileSystem" },
+ { 0x31BA02, "UnsupportedCommitProvisionallyForRomFsFileSystem" },
+ { 0x31BC02, "UnsupportedGetTotalSpaceSizeForRomFsFileSystem" },
+ { 0x31BE02, "UnsupportedWriteForRomFsFile" },
+ { 0x31C002, "UnsupportedOperateRangeForRomFsFile" },
+ { 0x31C202, "UnsupportedWriteForReadOnlyFileSystem" },
+ { 0x31C402, "UnsupportedCommitProvisionallyForReadOnlyFileSystem" },
+ { 0x31C602, "UnsupportedGetTotalSpaceSizeForReadOnlyFileSystem" },
+ { 0x31C802, "UnsupportedWriteForReadOnlyFile" },
+ { 0x31CA02, "UnsupportedOperateRangeForReadOnlyFile" },
+ { 0x31CC02, "UnsupportedWriteForPartitionFileSystem" },
+ { 0x31CE02, "UnsupportedCommitProvisionallyForPartitionFileSystem" },
+ { 0x31D002, "UnsupportedWriteForPartitionFile" },
+ { 0x31D202, "UnsupportedOperateRangeForPartitionFile" },
+ { 0x31D402, "UnsupportedOperateRangeForTmFileSystemFile" },
+ { 0x31D602, "UnsupportedWriteForSaveDataInternalStorageFileSystem" },
+ { 0x31DC02, "UnsupportedCommitProvisionallyForApplicationTemporaryFileSystem" },
+ { 0x31DE02, "UnsupportedCommitProvisionallyForSaveDataFileSystem" },
+ { 0x31E002, "UnsupportedCommitProvisionallyForDirectorySaveDataFileSystem" },
+ { 0x31E202, "UnsupportedWriteForZeroBitmapHashStorageFile" },
+ { 0x31E402, "UnsupportedSetSizeForZeroBitmapHashStorageFile" },
+ { 0x31E602, "UnsupportedWriteForCompressedStorage" },
+ { 0x31E802, "UnsupportedOperateRangeForCompressedStorage" },
+ { 0x31F602, "UnsupportedRollbackOnlyModifiedForApplicationTemporaryFileSystem" },
+ { 0x31F802, "UnsupportedRollbackOnlyModifiedForDirectorySaveDataFileSystem" },
+ { 0x31FA02, "UnsupportedOperateRangeForRegionSwitchStorage" },
+ { 0x320002, "PermissionDenied" },
+ { 0x320602, "HostFileSystemOperationDisabled" },
+ { 0x326402, "PortAcceptableCountLimited" },
+ { 0x326802, "NcaExternalKeyInconsistent" },
+ { 0x326C02, "NeedFlush" },
+ { 0x326E02, "FileNotClosed" },
+ { 0x327002, "DirectoryNotClosed" },
+ { 0x327202, "WriteModeFileNotClosed" },
+ { 0x327402, "AllocatorAlreadyRegistered" },
+ { 0x327602, "DefaultAllocatorAlreadyUsed" },
+ { 0x327802, "GameCardLogoDataSizeInvalid" },
+ { 0x327A02, "AllocatorAlignmentViolation" },
+ { 0x327C02, "GlobalFileDataCacheAlreadyEnabled" },
+ { 0x327E02, "MultiCommitHasOverlappingTargets" },
+ { 0x328002, "MultiCommitAlreadyInProgress" },
+ { 0x328202, "UserNotExist" },
+ { 0x328402, "DefaultGlobalFileDataCacheEnabled" },
+ { 0x328602, "SaveDataRootPathUnavailable" },
+ { 0x339002, "NotFound" },
+ { 0x339402, "FileNotFound" },
+ { 0x339602, "DirectoryNotFound" },
+ { 0x339802, "DatabaseKeyNotFound" },
+ { 0x339A02, "ProgramInfoNotFound" },
+ { 0x339C02, "ProgramIndexNotFound" },
+ { 0x345802, "OutOfResource" },
+ { 0x346202, "BufferAllocationFailed" },
+ { 0x346402, "MappingTableFull" },
+ { 0x346602, "AllocationTableFull" },
+ { 0x346A02, "OpenCountLimit" },
+ { 0x346C02, "MultiCommitFileSystemLimit" },
+ { 0x352002, "MappingFailed" },
+ { 0x353602, "MapFull" },
+ { 0x35E802, "BadState" },
+ { 0x35EC02, "NotInitialized" },
+ { 0x35EE02, "BisProxyInvalidated" },
+ { 0x35F002, "NcaDigestInconsistent" },
+ { 0x35F202, "NotMounted" },
+ { 0x35F402, "SaveDataExtending" },
+ { 0x35F602, "SaveDataToExpandIsProvisionallyCommitted" },
+ { 0x36B402, "SaveDataTransferV2KeySeedPackageMacVerificationFailed" },
+ { 0x36B602, "SaveDataTransferV2KeySeedPackageSignatureVerificationFailed" },
+ { 0x36B802, "SaveDataTransferV2KeySeedPackageChallengeVerificationFailed" },
+ { 0x36BA02, "SaveDataTransferV2ImportDataVerificationFailed" },
+ { 0x36BC02, "SaveDataTransferV2InitialDataGcmMacVerificationFailed" },
+ { 0x36C202, "SaveDataTransferV2InitialDataMacVerificationFailed" },
+ { 0x36C402, "SaveDataTransferV2ImportDataDecompressionFailed" },
+ { 0x36C602, "SaveDataTransferV2PortContextMacVerificationFailed" },
+ { 0x36EE02, "SaveDataPorterInvalidated" },
+ { 0x36F002, "SaveDataDivisionExporterChunkExportIncomplete" },
+ { 0x36F202, "SaveDataDivisionImporterChunkImportIncomplete" },
+ { 0x36F402, "SaveDataPorterInitialDataVersionVerificationFailed" },
+ { 0x36F602, "SaveDataChunkDecryptorGcmStreamVersionVerificationFailed" },
+ { 0x36F802, "SaveDataPorterSaveDataModified" },
+ { 0x36FA02, "SaveDataPorterVersionUnsupported" },
+ { 0x36FC02, "SaveDataTransferV2SecondarySaveCorrupted" },
+ { 0x372C02, "SaveDataTransferForSaveDataRepairKeyPackageMacVerificationFailed" },
+ { 0x372E02, "SaveDataTransferForSaveDataRepairKeyPackageSignatureVerificationFailed" },
+ { 0x373002, "SaveDataTransferForSaveDataRepairKeyPackageChallengeVerificationFailed" },
+ { 0x373202, "SaveDataTransferForSaveDataRepairUnsupportedKeyGeneration" },
+ { 0x373402, "SaveDataTransferForSaveDataRepairInitialDataMacVerificationFailed" },
+ { 0x373A02, "SaveDataTransferForSaveDataRepairIncorrectInitialData" },
+ { 0x373C02, "SaveDataTransferForSaveDataRepairInconsistentInitialData" },
+ { 0x373E02, "SaveDataTransferForSaveDataRepairInitialDataIncorrectUserId" },
+ { 0x377802, "RamDiskCorrupted" },
+ { 0x377A02, "RamDiskVerifiedStorageVerificationFailed" },
+ { 0x378E02, "RamDiskSaveDataCoreFileSystemCorrupted" },
+ { 0x379002, "IncorrectRamDiskSaveDataFileSystemMagicCode" },
+ { 0x379202, "InvalidRamDiskSaveDataFileReadOffset" },
+ { 0x379402, "InvalidRamDiskSaveDataCoreDataStorageSize" },
+ { 0x37A202, "RamDiskDatabaseCorrupted" },
+ { 0x37A402, "InvalidRamDiskAllocationTableBlock" },
+ { 0x37A602, "InvalidRamDiskKeyValueListElementIndex" },
+ { 0x37A802, "InvalidRamDiskAllocationTableChainEntry" },
+ { 0x37AA02, "InvalidRamDiskAllocationTableOffset" },
+ { 0x37AC02, "InvalidRamDiskAllocationTableBlockCount" },
+ { 0x37AE02, "InvalidRamDiskKeyValueListEntryIndex" },
+ { 0x37CC02, "SaveDataTransferForRepairInitialDataMacVerificationFailed" },
+ { 0x3DB802, "Unknown" },
+ { 0x3DBA02, "DbmNotFound" },
+ { 0x3DBC02, "DbmKeyNotFound" },
+ { 0x3DBE02, "DbmFileNotFound" },
+ { 0x3DC002, "DbmDirectoryNotFound" },
+ { 0x3DC402, "DbmAlreadyExists" },
+ { 0x3DC602, "DbmKeyFull" },
+ { 0x3DC802, "DbmDirectoryEntryFull" },
+ { 0x3DCA02, "DbmFileEntryFull" },
+ { 0x3DCC02, "DbmFindFinished" },
+ { 0x3DCE02, "DbmFindKeyFinished" },
+ { 0x3DD002, "DbmIterationFinished" },
+ { 0x3DD402, "DbmInvalidOperation" },
+ { 0x3DD602, "DbmInvalidPathFormat" },
+ { 0x3DD802, "DbmDirectoryNameTooLong" },
+ { 0x3DDA02, "DbmFileNameTooLong" },
+ { 0x803, "Busy" },
+ { 0x1003, "OutOfMemory" },
+ { 0x1203, "OutOfResource" },
+ { 0x1803, "OutOfVirtualAddressSpace" },
+ { 0x1A03, "ResourceLimit" },
+ { 0x3E803, "OutOfHandles" },
+ { 0x3EA03, "InvalidHandle" },
+ { 0x3EC03, "InvalidCurrentMemoryState" },
+ { 0x3EE03, "InvalidTransferMemoryState" },
+ { 0x3F003, "InvalidTransferMemorySize" },
+ { 0x3F203, "OutOfTransferMemory" },
+ { 0x3F403, "OutOfAddressSpace" },
+ { 0x3FC03, "SessionClosedForReceive" },
+ { 0x3FE03, "SessionClosedForReply" },
+ { 0x40003, "ReceiveListBroken" },
+ { 0x1204, "InvalidHandle" },
+ { 0xFA204, "InvalidArgument" },
+ { 0xFA604, "InvalidServerHandle" },
+ { 0xFBC04, "InvalidSize" },
+ { 0xFCA04, "Cancelled" },
+ { 0xFCE04, "Completed" },
+ { 0x106E04, "InvalidTask" },
+ { 0x205, "InvalidContentStorageBase" },
+ { 0x405, "PlaceHolderAlreadyExists" },
+ { 0x605, "PlaceHolderNotFound" },
+ { 0x805, "ContentAlreadyExists" },
+ { 0xA05, "ContentNotFound" },
+ { 0xE05, "ContentMetaNotFound" },
+ { 0x1005, "AllocationFailed" },
+ { 0x1805, "UnknownStorage" },
+ { 0xC805, "InvalidContentStorage" },
+ { 0xDC05, "InvalidContentMetaDatabase" },
+ { 0x10405, "InvalidPackageFormat" },
+ { 0x11805, "InvalidContentHash" },
+ { 0x14005, "InvalidInstallTaskState" },
+ { 0x15405, "InvalidPlaceHolderFile" },
+ { 0x16805, "BufferInsufficient" },
+ { 0x17C05, "WriteToReadOnlyContentStorage" },
+ { 0x19005, "NotEnoughInstallSpace" },
+ { 0x1A405, "SystemUpdateNotFoundInPackage" },
+ { 0x1B805, "ContentInfoNotFound" },
+ { 0x1DA05, "DeltaNotFound" },
+ { 0x1E005, "InvalidContentMetaKey" },
+ { 0x1F405, "ContentStorageNotActive" },
+ { 0x1F605, "GameCardContentStorageNotActive" },
+ { 0x1F805, "BuiltInSystemContentStorageNotActive" },
+ { 0x1FA05, "BuiltInUserContentStorageNotActive" },
+ { 0x1FC05, "SdCardContentStorageNotActive" },
+ { 0x20405, "UnknownContentStorageNotActive" },
+ { 0x20805, "ContentMetaDatabaseNotActive" },
+ { 0x20A05, "GameCardContentMetaDatabaseNotActive" },
+ { 0x20C05, "BuiltInSystemContentMetaDatabaseNotActive" },
+ { 0x20E05, "BuiltInUserContentMetaDatabaseNotActive" },
+ { 0x21005, "SdCardContentMetaDatabaseNotActive" },
+ { 0x21805, "UnknownContentMetaDatabaseNotActive" },
+ { 0x23005, "IgnorableInstallTicketFailure" },
+ { 0x24405, "InstallTaskCancelled" },
+ { 0x24605, "CreatePlaceHolderCancelled" },
+ { 0x24805, "WritePlaceHolderCancelled" },
+ { 0x26C05, "ContentStorageBaseNotFound" },
+ { 0x29405, "ListPartiallyNotCommitted" },
+ { 0x2D005, "UnexpectedContentMetaPrepared" },
+ { 0x2F805, "InvalidFirmwareVariation" },
+ { 0x3FEA05, "InvalidArgument" },
+ { 0x3FEC05, "InvalidOffset" },
+ { 0x206, "EndOfQuery" },
+ { 0x406, "InvalidCurrentMemory" },
+ { 0x606, "NotSingleRegion" },
+ { 0x806, "InvalidMemoryState" },
+ { 0xA06, "OutOfMemory" },
+ { 0xC06, "OutOfResource" },
+ { 0xE06, "NotSupported" },
+ { 0x1006, "InvalidHandle" },
+ { 0x7FE06, "InternalError" },
+ { 0x208, "ResolverNotFound" },
+ { 0x408, "ProgramNotFound" },
+ { 0x608, "DataNotFound" },
+ { 0x808, "UnknownResolver" },
+ { 0xA08, "ApplicationNotFound" },
+ { 0xC08, "HtmlDocumentNotFound" },
+ { 0xE08, "AddOnContentNotFound" },
+ { 0x1008, "ControlNotFound" },
+ { 0x1208, "LegalInformationNotFound" },
+ { 0x1408, "DebugProgramNotFound" },
+ { 0xB408, "TooManyRegisteredPaths" },
+ { 0x209, "TooLongArgument" },
+ { 0x409, "TooManyArguments" },
+ { 0x609, "TooLargeMeta" },
+ { 0x809, "InvalidMeta" },
+ { 0xA09, "InvalidNso" },
+ { 0xC09, "InvalidPath" },
+ { 0xE09, "TooManyProcesses" },
+ { 0x1009, "NotPinned" },
+ { 0x1209, "InvalidProgramId" },
+ { 0x1409, "InvalidVersion" },
+ { 0x1609, "InvalidAcidSignature" },
+ { 0x1809, "InvalidNcaSignature" },
+ { 0x6609, "InsufficientAddressSpace" },
+ { 0x6809, "InvalidNro" },
+ { 0x6A09, "InvalidNrr" },
+ { 0x6C09, "InvalidSignature" },
+ { 0x6E09, "InsufficientNroRegistrations" },
+ { 0x7009, "InsufficientNrrRegistrations" },
+ { 0x7209, "NroAlreadyLoaded" },
+ { 0xA209, "InvalidAddress" },
+ { 0xA409, "InvalidSize" },
+ { 0xA809, "NotLoaded" },
+ { 0xAA09, "NotRegistered" },
+ { 0xAC09, "InvalidSession" },
+ { 0xAE09, "InvalidProcess" },
+ { 0xC809, "UnknownCapability" },
+ { 0xCE09, "InvalidCapabilityKernelFlags" },
+ { 0xD009, "InvalidCapabilitySyscallMask" },
+ { 0xD409, "InvalidCapabilityMapRange" },
+ { 0xD609, "InvalidCapabilityMapPage" },
+ { 0xDE09, "InvalidCapabilityInterruptPair" },
+ { 0xE209, "InvalidCapabilityApplicationType" },
+ { 0xE409, "InvalidCapabilityKernelVersion" },
+ { 0xE609, "InvalidCapabilityHandleTable" },
+ { 0xE809, "InvalidCapabilityDebugFlags" },
+ { 0x19009, "InternalError" },
+ { 0x20A, "NotSupported" },
+ { 0x60A, "PreconditionViolation" },
+ { 0x140A, "MemoryAllocationFailed" },
+ { 0x160A, "CmifProxyAllocationFailed" },
+ { 0x1940A, "InvalidCmifHeaderSize" },
+ { 0x1A60A, "InvalidCmifInHeader" },
+ { 0x1A80A, "InvalidCmifOutHeader" },
+ { 0x1BA0A, "UnknownMethodId" },
+ { 0x1CE0A, "InvalidInRawSize" },
+ { 0x1D00A, "InvalidOutRawSize" },
+ { 0x1D60A, "InvalidInObjectCount" },
+ { 0x1D80A, "InvalidOutObjectCount" },
+ { 0x1DE0A, "InvalidInObject" },
+ { 0x20A0A, "TargetObjectNotFound" },
+ { 0x25A0A, "OutOfDomainEntry" },
+ { 0x6400A, "RequestContextChanged" },
+ { 0x6420A, "RequestInvalidated" },
+ { 0x6440A, "RequestInvalidatedByUser" },
+ { 0x6560A, "RequestDeferred" },
+ { 0x6580A, "RequestDeferredByUser" },
+ { 0x20B, "NotSupported" },
+ { 0xC80B, "OutOfResource" },
+ { 0xCC0B, "OutOfSessionMemory" },
+ { 0x1060B, "OutOfSessions" },
+ { 0x11A0B, "InsufficientPointerTransferBuffer" },
+ { 0x1900B, "OutOfDomains" },
+ { 0x2580B, "CommunicationError" },
+ { 0x25A0B, "SessionClosed" },
+ { 0x3240B, "InvalidRequestSize" },
+ { 0x3260B, "UnknownCommandType" },
+ { 0x3480B, "InvalidCmifRequest" },
+ { 0x3D60B, "TargetNotDomain" },
+ { 0x3D80B, "DomainObjectNotFound" },
+ { 0x20C, "Unknown" },
+ { 0x20D, "Unknown" },
+ { 0x40D, "DebuggingDisabled" },
+ { 0x20F, "ProcessNotFound" },
+ { 0x40F, "AlreadyStarted" },
+ { 0x60F, "NotTerminated" },
+ { 0x80F, "DebugHookInUse" },
+ { 0xA0F, "ApplicationRunning" },
+ { 0xC0F, "InvalidSize" },
+ { 0xB410, "Canceled" },
+ { 0xDC10, "OutOfMaxRunningTask" },
+ { 0x21C10, "CardUpdateNotSetup" },
+ { 0x23010, "CardUpdateNotPrepared" },
+ { 0x24410, "CardUpdateAlreadySetup" },
+ { 0x39810, "PrepareCardUpdateAlreadyRequested" },
+ { 0x212, "ConnectionFailure" },
+ { 0x412, "NotFound" },
+ { 0x612, "NotEnoughBuffer" },
+ { 0xCA12, "Cancelled" },
+ { 0x7FE12, "" },
+ { 0xFA212, "" },
+ { 0xFA612, "InvalidTaskId" },
+ { 0xFB612, "InvalidSize" },
+ { 0xFCA12, "TaskCancelled" },
+ { 0xFCC12, "TaskNotCompleted" },
+ { 0xFCE12, "TaskQueueNotAvailable" },
+ { 0x106A12, "" },
+ { 0x106C12, "OutOfRpcTask" },
+ { 0x109612, "InvalidCategory" },
+ { 0x214, "OutOfKeyResource" },
+ { 0x414, "KeyNotFound" },
+ { 0x814, "AllocationFailed" },
+ { 0xA14, "InvalidKeyValue" },
+ { 0xC14, "BufferInsufficient" },
+ { 0x1014, "InvalidFileSystemState" },
+ { 0x1214, "NotCreated" },
+ { 0x215, "OutOfProcesses" },
+ { 0x415, "InvalidClient" },
+ { 0x615, "OutOfSessions" },
+ { 0x815, "AlreadyRegistered" },
+ { 0xA15, "OutOfServices" },
+ { 0xC15, "InvalidServiceName" },
+ { 0xE15, "NotRegistered" },
+ { 0x1015, "NotAllowed" },
+ { 0x1215, "TooLargeAccessControl" },
+ { 0x216, "RoError" },
+ { 0x416, "OutOfAddressSpace" },
+ { 0x616, "AlreadyLoaded" },
+ { 0x816, "InvalidNro" },
+ { 0xC16, "InvalidNrr" },
+ { 0xE16, "TooManyNro" },
+ { 0x1016, "TooManyNrr" },
+ { 0x1216, "NotAuthorized" },
+ { 0x1416, "InvalidNrrKind" },
+ { 0x7FE16, "InternalError" },
+ { 0x80216, "InvalidAddress" },
+ { 0x80416, "InvalidSize" },
+ { 0x80816, "NotLoaded" },
+ { 0x80A16, "NotRegistered" },
+ { 0x80C16, "InvalidSession" },
+ { 0x80E16, "InvalidProcess" },
+ { 0x218, "NoDevice" },
+ { 0x418, "NotActivated" },
+ { 0x618, "DeviceRemoved" },
+ { 0x818, "NotAwakened" },
+ { 0x4018, "CommunicationError" },
+ { 0x4218, "CommunicationNotAttained" },
+ { 0x4418, "ResponseIndexError" },
+ { 0x4618, "ResponseEndBitError" },
+ { 0x4818, "ResponseCrcError" },
+ { 0x4A18, "ResponseTimeoutError" },
+ { 0x4C18, "DataEndBitError" },
+ { 0x4E18, "DataCrcError" },
+ { 0x5018, "DataTimeoutError" },
+ { 0x5218, "AutoCommandResponseIndexError" },
+ { 0x5418, "AutoCommandResponseEndBitError" },
+ { 0x5618, "AutoCommandResponseCrcError" },
+ { 0x5818, "AutoCommandResponseTimeoutError" },
+ { 0x5A18, "CommandCompleteSoftwareTimeout" },
+ { 0x5C18, "TransferCompleteSoftwareTimeout" },
+ { 0x6018, "DeviceStatusHasError" },
+ { 0x6218, "DeviceStatusAddressOutOfRange" },
+ { 0x6418, "DeviceStatusAddressMisaligned" },
+ { 0x6618, "DeviceStatusBlockLenError" },
+ { 0x6818, "DeviceStatusEraseSeqError" },
+ { 0x6A18, "DeviceStatusEraseParam" },
+ { 0x6C18, "DeviceStatusWpViolation" },
+ { 0x6E18, "DeviceStatusLockUnlockFailed" },
+ { 0x7018, "DeviceStatusComCrcError" },
+ { 0x7218, "DeviceStatusIllegalCommand" },
+ { 0x7418, "DeviceStatusDeviceEccFailed" },
+ { 0x7618, "DeviceStatusCcError" },
+ { 0x7818, "DeviceStatusError" },
+ { 0x7A18, "DeviceStatusCidCsdOverwrite" },
+ { 0x7C18, "DeviceStatusWpEraseSkip" },
+ { 0x7E18, "DeviceStatusEraseReset" },
+ { 0x8018, "DeviceStatusSwitchError" },
+ { 0x9018, "UnexpectedDeviceState" },
+ { 0x9218, "UnexpectedDeviceCsdValue" },
+ { 0x9418, "AbortTransactionSoftwareTimeout" },
+ { 0x9618, "CommandInhibitCmdSoftwareTimeout" },
+ { 0x9818, "CommandInhibitDatSoftwareTimeout" },
+ { 0x9A18, "BusySoftwareTimeout" },
+ { 0x9C18, "IssueTuningCommandSoftwareTimeout" },
+ { 0x9E18, "TuningFailed" },
+ { 0xA018, "MmcInitializationSoftwareTimeout" },
+ { 0xA218, "MmcNotSupportExtendedCsd" },
+ { 0xA418, "UnexpectedMmcExtendedCsdValue" },
+ { 0xA618, "MmcEraseSoftwareTimeout" },
+ { 0xA818, "SdCardValidationError" },
+ { 0xAA18, "SdCardInitializationSoftwareTimeout" },
+ { 0xAC18, "SdCardGetValidRcaSoftwareTimeout" },
+ { 0xAE18, "UnexpectedSdCardAcmdDisabled" },
+ { 0xB018, "SdCardNotSupportSwitchFunctionStatus" },
+ { 0xB218, "UnexpectedSdCardSwitchFunctionStatus" },
+ { 0xB418, "SdCardNotSupportAccessMode" },
+ { 0xB618, "SdCardNot4BitBusWidthAtUhsIMode" },
+ { 0xB818, "SdCardNotSupportSdr104AndSdr50" },
+ { 0xBA18, "SdCardCannotSwitchAccessMode" },
+ { 0xBC18, "SdCardFailedSwitchAccessMode" },
+ { 0xBE18, "SdCardUnacceptableCurrentConsumption" },
+ { 0xC018, "SdCardNotReadyToVoltageSwitch" },
+ { 0xC218, "SdCardNotCompleteVoltageSwitch" },
+ { 0x10018, "HostControllerUnexpected" },
+ { 0x10218, "InternalClockStableSoftwareTimeout" },
+ { 0x10418, "SdHostStandardUnknownAutoCmdError" },
+ { 0x10618, "SdHostStandardUnknownError" },
+ { 0x10818, "SdmmcDllCalibrationSoftwareTimeout" },
+ { 0x10A18, "SdmmcDllApplicationSoftwareTimeout" },
+ { 0x10C18, "SdHostStandardFailSwitchTo18V" },
+ { 0x10E18, "DriveStrengthCalibrationNotCompleted" },
+ { 0x11018, "DriveStrengthCalibrationSoftwareTimeout" },
+ { 0x11218, "SdmmcCompShortToGnd" },
+ { 0x11418, "SdmmcCompOpen" },
+ { 0x14018, "InternalError" },
+ { 0x14218, "NoWaitedInterrupt" },
+ { 0x14418, "WaitInterruptSoftwareTimeout" },
+ { 0x18018, "AbortCommandIssued" },
+ { 0x19018, "NotSupported" },
+ { 0x19218, "NotImplemented" },
+ { 0x1A, "SecureMonitorError" },
+ { 0x21A, "SecureMonitorNotImplemented" },
+ { 0x41A, "SecureMonitorInvalidArgument" },
+ { 0x61A, "SecureMonitorBusy" },
+ { 0x81A, "SecureMonitorNoAsyncOperation" },
+ { 0xA1A, "SecureMonitorInvalidAsyncOperation" },
+ { 0xC1A, "SecureMonitorNotPermitted" },
+ { 0xE1A, "SecureMonitorNotInitialized" },
+ { 0xC81A, "InvalidSize" },
+ { 0xCA1A, "UnknownSecureMonitorError" },
+ { 0xCC1A, "DecryptionFailed" },
+ { 0xD01A, "OutOfKeySlots" },
+ { 0xD21A, "InvalidKeySlot" },
+ { 0xD41A, "BootReasonAlreadySet" },
+ { 0xD61A, "BootReasonNotSet" },
+ { 0xD81A, "InvalidArgument" },
+ { 0x21B, "InsufficientProvidedMemory" },
+ { 0x21D, "ConnectionFailure" },
+ { 0x61D, "UnknownDriverType" },
+ { 0xA1D, "NonBlockingReceiveFailed" },
+ { 0x101D, "ChannelWaitCancelled" },
+ { 0x121D, "ChannelAlreadyExist" },
+ { 0x141D, "ChannelNotExist" },
+ { 0x12E1D, "OutOfChannel" },
+ { 0x1301D, "OutOfTask" },
+ { 0x1901D, "InvalidChannelState" },
+ { 0x1921D, "InvalidChannelStateDisconnected" },
+ { 0x7D01D, "InternalError" },
+ { 0x7D21D, "Overflow" },
+ { 0x7D41D, "OutOfMemory" },
+ { 0x7D61D, "InvalidArgument" },
+ { 0x7D81D, "ProtocolError" },
+ { 0x7DA1D, "Cancelled" },
+ { 0x8981D, "MuxError" },
+ { 0x89A1D, "ChannelBufferOverflow" },
+ { 0x89C1D, "ChannelBufferHasNotEnoughData" },
+ { 0x89E1D, "ChannelVersionNotMatched" },
+ { 0x8A01D, "ChannelStateTransitionError" },
+ { 0x8A41D, "ChannelReceiveBufferEmpty" },
+ { 0x8A61D, "ChannelSequenceIdNotMatched" },
+ { 0x8A81D, "ChannelCannotDiscard" },
+ { 0x9601D, "DriverError" },
+ { 0x9621D, "DriverOpened" },
+ { 0xA281D, "SocketDriverError" },
+ { 0xA2A1D, "SocketSocketExemptError" },
+ { 0xA2C1D, "SocketBindError" },
+ { 0xA301D, "SocketListenError" },
+ { 0xA321D, "SocketAcceptError" },
+ { 0xA341D, "SocketReceiveError" },
+ { 0xA361D, "SocketSendError" },
+ { 0xA381D, "SocketReceiveFromError" },
+ { 0xA3A1D, "SocketSendToError" },
+ { 0xA3C1D, "SocketSetSockOptError" },
+ { 0xA3E1D, "SocketGetSockNameError" },
+ { 0xAF01D, "UsbDriverError" },
+ { 0xAF21D, "UsbDriverUnknownError" },
+ { 0xAF41D, "UsbDriverBusyError" },
+ { 0xAF61D, "UsbDriverReceiveError" },
+ { 0xAF81D, "UsbDriverSendError" },
+ { 0xFA01D, "HtcctrlError" },
+ { 0xFA21D, "HtcctrlStateTransitionNotAllowed" },
+ { 0xFA41D, "HtcctrlReceiveUnexpectedPacket" },
+ { 0x21E, "OutOfResource" },
+ { 0x41E, "NotSupported" },
+ { 0x61E, "InvalidArgument" },
+ { 0x81E, "PermissionDenied" },
+ { 0xA1E, "AccessModeDenied" },
+ { 0xC1E, "DeviceCodeNotFound" },
+ { 0x61F, "InvalidArgument" },
+ { 0xC81F, "ConnectionFailure" },
+ { 0xCA1F, "HtclowChannelClosed" },
+ { 0xDC1F, "UnexpectedResponse" },
+ { 0xDE1F, "UnexpectedResponseProtocolId" },
+ { 0xE01F, "UnexpectedResponseProtocolVersion" },
+ { 0xE21F, "UnexpectedResponsePacketCategory" },
+ { 0xE41F, "UnexpectedResponsePacketType" },
+ { 0xE61F, "UnexpectedResponseBodySize" },
+ { 0xE81F, "UnexpectedResponseBody" },
+ { 0x1901F, "InternalError" },
+ { 0x1921F, "InvalidSize" },
+ { 0x1A61F, "UnknownError" },
+ { 0x1A81F, "UnsupportedProtocolVersion" },
+ { 0x1AA1F, "InvalidRequest" },
+ { 0x1AC1F, "InvalidHandle" },
+ { 0x1AE1F, "OutOfHandle" },
+ { 0x265, "NoAck" },
+ { 0x465, "BusBusy" },
+ { 0x665, "CommandListFull" },
+ { 0xA65, "UnknownDevice" },
+ { 0x1FA65, "Timeout" },
+ { 0x266, "AlreadyBound" },
+ { 0x466, "AlreadyOpen" },
+ { 0x666, "DeviceNotFound" },
+ { 0x866, "InvalidArgument" },
+ { 0xC66, "NotOpen" },
+ { 0x1669, "SettingsItemNotFound" },
+ { 0xC869, "InternalError" },
+ { 0xCA69, "SettingsItemKeyAllocationFailed" },
+ { 0xCC69, "SettingsItemValueAllocationFailed" },
+ { 0x19069, "InvalidArgument" },
+ { 0x19269, "SettingsNameNull" },
+ { 0x19469, "SettingsItemKeyNull" },
+ { 0x19669, "SettingsItemValueNull" },
+ { 0x19869, "SettingsItemKeyBufferNull" },
+ { 0x19A69, "SettingsItemValueBufferNull" },
+ { 0x1BA69, "SettingsNameEmpty" },
+ { 0x1BC69, "SettingsItemKeyEmpty" },
+ { 0x1E269, "SettingsNameTooLong" },
+ { 0x1E469, "SettingsItemKeyTooLong" },
+ { 0x20A69, "SettingsNameInvalidFormat" },
+ { 0x20C69, "SettingsItemKeyInvalidFormat" },
+ { 0x20E69, "SettingsItemValueInvalidFormat" },
+ { 0x48869, "CalibrationDataError" },
+ { 0x48A69, "CalibrationDataFileSystemCorrupted" },
+ { 0x48C69, "CalibrationDataCrcError" },
+ { 0x48E69, "CalibrationDataShaError" },
+ { 0x272, "OperationFailed" },
+ { 0xC72, "NotSupported" },
+ { 0xE72, "NotFound" },
+ { 0x74, "NotInitialized" },
+ { 0x274, "NoCapability" },
+ { 0xCC74, "OffsetInvalid" },
+ { 0xCE74, "UninitializedClock" },
+ { 0x19074, "NotComparable" },
+ { 0x19274, "Overflowed" },
+ { 0x64274, "OutOfMemory" },
+ { 0x70874, "InvalidArgument" },
+ { 0x70A74, "InvalidPointer" },
+ { 0x70C74, "OutOfRange" },
+ { 0x70E74, "InvalidTimeZoneBinary" },
+ { 0x7BA74, "NotFound" },
+ { 0x7BC74, "NotImplemented" },
+ { 0x27A, "InvalidArgument" },
+ { 0x47A, "NotFound" },
+ { 0x67A, "TargetLocked" },
+ { 0x87A, "TargetAlreadyMounted" },
+ { 0xA7A, "TargetNotMounted" },
+ { 0xC7A, "AlreadyOpen" },
+ { 0xE7A, "NotOpen" },
+ { 0x107A, "InternetRequestDenied" },
+ { 0x127A, "ServiceOpenLimitReached" },
+ { 0x147A, "SaveDataNotFound" },
+ { 0x3E7A, "NetworkServiceAccountNotAvailable" },
+ { 0xA07A, "PassphrasePathNotFound" },
+ { 0xA27A, "DataVerificationFailed" },
+ { 0xB47A, "PermissionDenied" },
+ { 0xB67A, "AllocationFailed" },
+ { 0xC47A, "InvalidOperation" },
+ { 0x1987A, "InvalidDeliveryCacheStorageFile" },
+ { 0x19A7A, "StorageOpenLimitReached" },
+ { 0x7B, "SslService" },
+ { 0x7C, "Cancelled" },
+ { 0x27C, "CancelledByUser" },
+ { 0xC87C, "UserNotExist" },
+ { 0x1907C, "NetworkServiceAccountUnavailable" },
+ { 0x35C7C, "TokenCacheUnavailable" },
+ { 0x17707C, "NetworkCommunicationError" },
+ { 0x2085, "IllegalRequest" },
+ { 0x8C89, "HttpConnectionCanceled" },
+ { 0x48A, "AlreadyInitialized" },
+ { 0x68A, "NotInitialized" },
+ { 0x8C, "NotInitialized" },
+ { 0x28C, "AlreadyInitialized" },
+ { 0xC88C, "InvalidParameter" },
+ { 0xCE8C, "AlignmentError" },
+ { 0x1928C, "OperationDenied" },
+ { 0x1948C, "MemAllocFailure" },
+ { 0x19C8C, "ResourceBusy" },
+ { 0x19E8C, "InternalStateError" },
+ { 0x3228C, "TransactionError" },
+ { 0x3328C, "Interrupted" },
+ { 0x293, "NotInitialized" },
+ { 0x493, "AlreadyInitialized" },
+ { 0x693, "OutOfArraySpace" },
+ { 0x893, "OutOfFieldSpace" },
+ { 0xA93, "OutOfMemory" },
+ { 0xC93, "NotSupported" },
+ { 0xE93, "InvalidArgument" },
+ { 0x1093, "NotFound" },
+ { 0x1293, "FieldCategoryMismatch" },
+ { 0x1493, "FieldTypeMismatch" },
+ { 0x1693, "AlreadyExists" },
+ { 0x1893, "CorruptJournal" },
+ { 0x1A93, "CategoryNotFound" },
+ { 0x1C93, "RequiredContextMissing" },
+ { 0x1E93, "RequiredFieldMissing" },
+ { 0x2093, "FormatterError" },
+ { 0x2293, "InvalidPowerState" },
+ { 0x2493, "ArrayFieldTooLarge" },
+ { 0x2693, "AlreadyOwned" },
+ { 0x49E, "BootImagePackageNotFound" },
+ { 0x69E, "InvalidBootImagePackage" },
+ { 0x89E, "TooSmallWorkBuffer" },
+ { 0xA9E, "NotAlignedWorkBuffer" },
+ { 0xC9E, "NeedsRepairBootImages" },
+ { 0x2A2, "ApplicationAborted" },
+ { 0x4A2, "SystemModuleAborted" },
+ { 0x2A3, "AllocationFailed" },
+ { 0x4A3, "NullGraphicsBuffer" },
+ { 0x6A3, "AlreadyThrown" },
+ { 0x8A3, "TooManyEvents" },
+ { 0xAA3, "InRepairWithoutVolHeld" },
+ { 0xCA3, "InRepairWithoutTimeReviserCartridge" },
+ { 0xA8, "UndefinedInstruction" },
+ { 0x2A8, "InstructionAbort" },
+ { 0x4A8, "DataAbort" },
+ { 0x6A8, "AlignmentFault" },
+ { 0x8A8, "DebuggerAttached" },
+ { 0xAA8, "BreakPoint" },
+ { 0xCA8, "UserBreak" },
+ { 0xEA8, "DebuggerBreak" },
+ { 0x10A8, "UndefinedSystemCall" },
+ { 0x12A8, "MemorySystemError" },
+ { 0xC6A8, "IncompleteReport" },
+ { 0x2B7, "CannotDebug" },
+ { 0x4B7, "AlreadyAttached" },
+ { 0x6B7, "Cancelled" },
+ { 0x4BD, "InvalidArgument" },
+ { 0x2C6, "NotSupported" },
+ { 0x4C6, "InvalidArgument" },
+ { 0x6C6, "NotAvailable" },
+ { 0xCAC6, "CalibrationDataCrcError" },
+ { 0x118CA, "Invalid" },
+ { 0x4B2CA, "DualConnected" },
+ { 0x4B4CA, "SameJoyTypeConnected" },
+ { 0x4B6CA, "ColorNotAvailable" },
+ { 0x4B8CA, "ControllerNotConnected" },
+ { 0x183ACA, "Canceled" },
+ { 0x183CCA, "NotSupportedNpadStyle" },
+ { 0x1900CA, "ControllerFirmwareUpdateError" },
+ { 0x1902CA, "ControllerFirmwareUpdateFailed" },
+ { 0x4CC, "UnknownCommand" },
+ { 0x8CC, "OutOfResource" },
+ { 0xECC, "NoSocket" },
+ { 0xDCCD, "IrsensorUnavailable" },
+ { 0xDECD, "IrsensorUnsupported" },
+ { 0xF0CD, "IrsensorNotReady" },
+ { 0xF4CD, "IrsensorDeviceError" },
+ { 0x4CE, "AlbumError" },
+ { 0x6CE, "AlbumWorkMemoryError" },
+ { 0xECE, "AlbumAlreadyOpened" },
+ { 0x10CE, "AlbumOutOfRange" },
+ { 0x14CE, "AlbumInvalidFileId" },
+ { 0x16CE, "AlbumInvalidApplicationId" },
+ { 0x18CE, "AlbumInvalidTimestamp" },
+ { 0x1ACE, "AlbumInvalidStorage" },
+ { 0x1CCE, "AlbumInvalidFileContents" },
+ { 0x2ACE, "AlbumIsNotMounted" },
+ { 0x2CCE, "AlbumIsFull" },
+ { 0x2ECE, "AlbumFileNotFound" },
+ { 0x30CE, "AlbumInvalidFileData" },
+ { 0x32CE, "AlbumFileCountLimit" },
+ { 0x34CE, "AlbumFileNoThumbnail" },
+ { 0x3CCE, "AlbumReadBufferShortage" },
+ { 0xB4CE, "AlbumFileSystemError" },
+ { 0xBCCE, "AlbumAccessCorrupted" },
+ { 0xC0CE, "AlbumDestinationAccessCorrupted" },
+ { 0x640CE, "ControlError" },
+ { 0x668CE, "ControlResourceLimit" },
+ { 0x66CCE, "ControlNotOpened" },
+ { 0x7FECE, "NotSupported" },
+ { 0x800CE, "InternalError" },
+ { 0x974CE, "InternalJpegEncoderError" },
+ { 0x978CE, "InternalJpegWorkMemoryShortage" },
+ { 0xA28CE, "InternalFileDataVerificationError" },
+ { 0xA2ACE, "InternalFileDataVerificationEmptyFileData" },
+ { 0xA2CCE, "InternalFileDataVerificationExifExtractionFailed" },
+ { 0xA2ECE, "InternalFileDataVerificationExifAnalyzationFailed" },
+ { 0xA30CE, "InternalFileDataVerificationDateTimeExtractionFailed" },
+ { 0xA32CE, "InternalFileDataVerificationInvalidDateTimeLength" },
+ { 0xA34CE, "InternalFileDataVerificationInconsistentDateTime" },
+ { 0xA36CE, "InternalFileDataVerificationMakerNoteExtractionFailed" },
+ { 0xA38CE, "InternalFileDataVerificationInconsistentApplicationId" },
+ { 0xA3ACE, "InternalFileDataVerificationInconsistentSignature" },
+ { 0xA3CCE, "InternalFileDataVerificationUnsupportedOrientation" },
+ { 0xA3ECE, "InternalFileDataVerificationInvalidDataDimension" },
+ { 0xA40CE, "InternalFileDataVerificationInconsistentOrientation" },
+ { 0xAF0CE, "InternalAlbumLimitationError" },
+ { 0xAF2CE, "InternalAlbumLimitationFileCountLimit" },
+ { 0xBB8CE, "InternalSignatureError" },
+ { 0xBBACE, "InternalSignatureExifExtractionFailed" },
+ { 0xBBCCE, "InternalSignatureMakerNoteExtractionFailed" },
+ { 0xD48CE, "InternalAlbumSessionError" },
+ { 0xD4ACE, "InternalAlbumLimitationSessionCountLimit" },
+ { 0xED8CE, "InternalAlbumTemporaryFileError" },
+ { 0xEDACE, "InternalAlbumTemporaryFileCountLimit" },
+ { 0xEDCCE, "InternalAlbumTemporaryFileCreateError" },
+ { 0xEDECE, "InternalAlbumTemporaryFileCreateRetryCountLimit" },
+ { 0xEE0CE, "InternalAlbumTemporaryFileOpenError" },
+ { 0xEE2CE, "InternalAlbumTemporaryFileGetFileSizeError" },
+ { 0xEE4CE, "InternalAlbumTemporaryFileSetFileSizeError" },
+ { 0xEE6CE, "InternalAlbumTemporaryFileReadFileError" },
+ { 0xEE8CE, "InternalAlbumTemporaryFileWriteFileError" },
+ { 0x2E4, "NotImplemented" },
+ { 0x4E4, "NotAvailable" },
+ { 0x6E4, "ApplicationNotRunning" },
+ { 0x8E4, "BufferNotEnough" },
+ { 0xAE4, "ApplicationContentNotFound" },
+ { 0xCE4, "ContentMetaNotFound" },
+ { 0xEE4, "OutOfMemory" },
+ { 0x3AC, "InvalidArgument" },
+ { 0x5AC, "NullArgument" },
+ { 0x7AC, "ArgumentOutOfRange" },
+ { 0x9AC, "BufferTooSmall" },
+ { 0x67AC, "ServiceNotInitialized" },
+ { 0xCBAC, "NotImplemented" },
+ { 0x7D1AC, "InvalidData" },
+ { 0x7D3AC, "InvalidInitialProcessData" },
+ { 0x7D5AC, "InvalidKip" },
+ { 0x7D7AC, "InvalidKipFileSize" },
+ { 0x7D9AC, "InvalidKipMagic" },
+ { 0x7DBAC, "InvalidKipSegmentSize" },
+ { 0x7DDAC, "KipSegmentDecompressionFailed" },
+ { 0x7E5AC, "InvalidIni" },
+ { 0x7E7AC, "InvalidIniFileSize" },
+ { 0x7E9AC, "InvalidIniMagic" },
+ { 0x7EBAC, "InvalidIniProcessCount" },
+ { 0x7F9AC, "InvalidPackage2" },
+ { 0x7FBAC, "InvalidPackage2HeaderSignature" },
+ { 0x7FDAC, "InvalidPackage2MetaSizeA" },
+ { 0x7FFAC, "InvalidPackage2MetaSizeB" },
+ { 0x801AC, "InvalidPackage2MetaKeyGeneration" },
+ { 0x803AC, "InvalidPackage2MetaMagic" },
+ { 0x805AC, "InvalidPackage2MetaEntryPointAlignment" },
+ { 0x807AC, "InvalidPackage2MetaPayloadAlignment" },
+ { 0x809AC, "InvalidPackage2MetaPayloadSizeAlignment" },
+ { 0x80BAC, "InvalidPackage2MetaTotalSize" },
+ { 0x80DAC, "InvalidPackage2MetaPayloadSize" },
+ { 0x80FAC, "InvalidPackage2MetaPayloadsOverlap" },
+ { 0x811AC, "InvalidPackage2MetaEntryPointNotFound" },
+ { 0x813AC, "InvalidPackage2PayloadCorrupted" },
+ { 0x821AC, "InvalidPackage1" },
+ { 0x823AC, "InvalidPackage1SectionSize" },
+ { 0x825AC, "InvalidPackage1MarikoBodySize" },
+ { 0x827AC, "InvalidPackage1Pk11Size" }
+ };
+
+ public static bool TryGet(int errorCode, out string name)
+ {
+ return _names.TryGetValue(errorCode, out name);
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Horizon.Common/Ryujinx.Horizon.Common.csproj b/Ryujinx.Horizon.Common/Ryujinx.Horizon.Common.csproj
new file mode 100644
index 00000000..d04c5a9b
--- /dev/null
+++ b/Ryujinx.Horizon.Common/Ryujinx.Horizon.Common.csproj
@@ -0,0 +1,11 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+ <PropertyGroup>
+ <TargetFramework>net7.0</TargetFramework>
+ </PropertyGroup>
+
+ <ItemGroup>
+ <ProjectReference Include="..\Ryujinx.Memory\Ryujinx.Memory.csproj" />
+ </ItemGroup>
+
+</Project>
diff --git a/Ryujinx.Horizon.Common/ThreadTerminatedException.cs b/Ryujinx.Horizon.Common/ThreadTerminatedException.cs
new file mode 100644
index 00000000..c86cb05f
--- /dev/null
+++ b/Ryujinx.Horizon.Common/ThreadTerminatedException.cs
@@ -0,0 +1,19 @@
+using System;
+
+namespace Ryujinx.Horizon.Common
+{
+ public class ThreadTerminatedException : Exception
+ {
+ public ThreadTerminatedException() : base("The thread has been terminated.")
+ {
+ }
+
+ public ThreadTerminatedException(string message) : base(message)
+ {
+ }
+
+ public ThreadTerminatedException(string message, Exception innerException) : base(message, innerException)
+ {
+ }
+ }
+}
diff --git a/Ryujinx.Horizon.Generators/CodeGenerator.cs b/Ryujinx.Horizon.Generators/CodeGenerator.cs
index 80a33c66..3a479eb7 100644
--- a/Ryujinx.Horizon.Generators/CodeGenerator.cs
+++ b/Ryujinx.Horizon.Generators/CodeGenerator.cs
@@ -24,10 +24,10 @@ namespace Ryujinx.Horizon.Generators
IncreaseIndentation();
}
- public void LeaveScope()
+ public void LeaveScope(string suffix = "")
{
DecreaseIndentation();
- AppendLine("}");
+ AppendLine($"}}{suffix}");
}
public void IncreaseIndentation()
diff --git a/Ryujinx.Horizon.Generators/Hipc/CommandArgType.cs b/Ryujinx.Horizon.Generators/Hipc/CommandArgType.cs
new file mode 100644
index 00000000..b859f1f3
--- /dev/null
+++ b/Ryujinx.Horizon.Generators/Hipc/CommandArgType.cs
@@ -0,0 +1,18 @@
+namespace Ryujinx.Horizon.Generators.Hipc
+{
+ enum CommandArgType : byte
+ {
+ Invalid,
+
+ Buffer,
+ InArgument,
+ InCopyHandle,
+ InMoveHandle,
+ InObject,
+ OutArgument,
+ OutCopyHandle,
+ OutMoveHandle,
+ OutObject,
+ ProcessId
+ }
+}
diff --git a/Ryujinx.Horizon.Generators/Hipc/CommandInterface.cs b/Ryujinx.Horizon.Generators/Hipc/CommandInterface.cs
new file mode 100644
index 00000000..2ee19282
--- /dev/null
+++ b/Ryujinx.Horizon.Generators/Hipc/CommandInterface.cs
@@ -0,0 +1,17 @@
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using System.Collections.Generic;
+
+namespace Ryujinx.Horizon.Generators.Hipc
+{
+ class CommandInterface
+ {
+ public ClassDeclarationSyntax ClassDeclarationSyntax { get; }
+ public List<MethodDeclarationSyntax> CommandImplementations { get; }
+
+ public CommandInterface(ClassDeclarationSyntax classDeclarationSyntax)
+ {
+ ClassDeclarationSyntax = classDeclarationSyntax;
+ CommandImplementations = new List<MethodDeclarationSyntax>();
+ }
+ }
+}
diff --git a/Ryujinx.Horizon.Generators/Hipc/HipcGenerator.cs b/Ryujinx.Horizon.Generators/Hipc/HipcGenerator.cs
new file mode 100644
index 00000000..a66d57a3
--- /dev/null
+++ b/Ryujinx.Horizon.Generators/Hipc/HipcGenerator.cs
@@ -0,0 +1,749 @@
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Ryujinx.Horizon.Generators.Hipc
+{
+ [Generator]
+ class HipcGenerator : ISourceGenerator
+ {
+ private const string ArgVariablePrefix = "arg";
+ private const string ResultVariableName = "result";
+ private const string IsBufferMapAliasVariableName = "isBufferMapAlias";
+ private const string InObjectsVariableName = "inObjects";
+ private const string OutObjectsVariableName = "outObjects";
+ private const string ResponseVariableName = "response";
+ private const string OutRawDataVariableName = "outRawData";
+
+ private const string TypeSystemReadOnlySpan = "System.ReadOnlySpan";
+ private const string TypeSystemSpan = "System.Span";
+ private const string TypeStructLayoutAttribute = "System.Runtime.InteropServices.StructLayoutAttribute";
+
+ public const string CommandAttributeName = "CmifCommandAttribute";
+
+ private const string TypeResult = "Ryujinx.Horizon.Common.Result";
+ private const string TypeBufferAttribute = "Ryujinx.Horizon.Sdk.Sf.BufferAttribute";
+ private const string TypeCopyHandleAttribute = "Ryujinx.Horizon.Sdk.Sf.CopyHandleAttribute";
+ private const string TypeMoveHandleAttribute = "Ryujinx.Horizon.Sdk.Sf.MoveHandleAttribute";
+ private const string TypeClientProcessIdAttribute = "Ryujinx.Horizon.Sdk.Sf.ClientProcessIdAttribute";
+ private const string TypeCommandAttribute = "Ryujinx.Horizon.Sdk.Sf." + CommandAttributeName;
+ private const string TypeIServiceObject = "Ryujinx.Horizon.Sdk.Sf.IServiceObject";
+
+ private enum Modifier
+ {
+ None,
+ Ref,
+ Out,
+ In
+ }
+
+ private struct OutParameter
+ {
+ public readonly string Name;
+ public readonly string TypeName;
+ public readonly int Index;
+ public readonly CommandArgType Type;
+
+ public OutParameter(string name, string typeName, int index, CommandArgType type)
+ {
+ Name = name;
+ TypeName = typeName;
+ Index = index;
+ Type = type;
+ }
+ }
+
+ public void Execute(GeneratorExecutionContext context)
+ {
+ HipcSyntaxReceiver syntaxReceiver = (HipcSyntaxReceiver)context.SyntaxReceiver;
+
+ foreach (var commandInterface in syntaxReceiver.CommandInterfaces)
+ {
+ if (!NeedsIServiceObjectImplementation(context.Compilation, commandInterface.ClassDeclarationSyntax))
+ {
+ continue;
+ }
+
+ CodeGenerator generator = new CodeGenerator();
+ string className = commandInterface.ClassDeclarationSyntax.Identifier.ToString();
+
+ generator.AppendLine("using Ryujinx.Horizon.Common;");
+ generator.AppendLine("using Ryujinx.Horizon.Sdk.Sf;");
+ generator.AppendLine("using Ryujinx.Horizon.Sdk.Sf.Cmif;");
+ generator.AppendLine("using Ryujinx.Horizon.Sdk.Sf.Hipc;");
+ generator.AppendLine("using System;");
+ generator.AppendLine("using System.Collections.Generic;");
+ generator.AppendLine("using System.Runtime.CompilerServices;");
+ generator.AppendLine("using System.Runtime.InteropServices;");
+ generator.AppendLine();
+ generator.EnterScope($"namespace {GetNamespaceName(commandInterface.ClassDeclarationSyntax)}");
+ generator.EnterScope($"partial class {className}");
+
+ GenerateMethodTable(generator, context.Compilation, commandInterface);
+
+ foreach (var method in commandInterface.CommandImplementations)
+ {
+ generator.AppendLine();
+
+ GenerateMethod(generator, context.Compilation, method);
+ }
+
+ generator.LeaveScope();
+ generator.LeaveScope();
+
+ context.AddSource($"{className}.g.cs", generator.ToString());
+ }
+ }
+
+ private static string GetNamespaceName(SyntaxNode syntaxNode)
+ {
+ while (syntaxNode != null && !(syntaxNode is NamespaceDeclarationSyntax))
+ {
+ syntaxNode = syntaxNode.Parent;
+ }
+
+ if (syntaxNode == null)
+ {
+ return string.Empty;
+ }
+
+ return ((NamespaceDeclarationSyntax)syntaxNode).Name.ToString();
+ }
+
+ private static void GenerateMethodTable(CodeGenerator generator, Compilation compilation, CommandInterface commandInterface)
+ {
+ generator.EnterScope($"public IReadOnlyDictionary<int, CommandHandler> GetCommandHandlers()");
+ generator.EnterScope($"return new Dictionary<int, CommandHandler>()");
+
+ foreach (var method in commandInterface.CommandImplementations)
+ {
+ foreach (var commandId in GetAttributeAguments(compilation, method, TypeCommandAttribute, 0))
+ {
+ string[] args = new string[method.ParameterList.Parameters.Count];
+
+ int index = 0;
+
+ foreach (var parameter in method.ParameterList.Parameters)
+ {
+ string canonicalTypeName = GetCanonicalTypeNameWithGenericArguments(compilation, parameter.Type);
+ CommandArgType argType = GetCommandArgType(compilation, parameter);
+
+ string arg;
+
+ if (argType == CommandArgType.Buffer)
+ {
+ string bufferFlags = GetFirstAttributeAgument(compilation, parameter, TypeBufferAttribute, 0);
+ string bufferFixedSize = GetFirstAttributeAgument(compilation, parameter, TypeBufferAttribute, 1);
+
+ if (bufferFixedSize != null)
+ {
+ arg = $"new CommandArg({bufferFlags}, {bufferFixedSize})";
+ }
+ else
+ {
+ arg = $"new CommandArg({bufferFlags})";
+ }
+ }
+ else if (argType == CommandArgType.InArgument || argType == CommandArgType.OutArgument)
+ {
+ string alignment = GetTypeAlignmentExpression(compilation, parameter.Type);
+
+ arg = $"new CommandArg(CommandArgType.{argType}, Unsafe.SizeOf<{canonicalTypeName}>(), {alignment})";
+ }
+ else
+ {
+ arg = $"new CommandArg(CommandArgType.{argType})";
+ }
+
+ args[index++] = arg;
+ }
+
+ generator.AppendLine($"{{ {commandId}, new CommandHandler({method.Identifier.Text}, {string.Join(", ", args)}) }},");
+ }
+ }
+
+ generator.LeaveScope(";");
+ generator.LeaveScope();
+ }
+
+ private static IEnumerable<string> GetAttributeAguments(Compilation compilation, SyntaxNode syntaxNode, string attributeName, int argIndex)
+ {
+ ISymbol symbol = compilation.GetSemanticModel(syntaxNode.SyntaxTree).GetDeclaredSymbol(syntaxNode);
+
+ foreach (var attribute in symbol.GetAttributes())
+ {
+ if (attribute.AttributeClass.ToDisplayString() == attributeName && (uint)argIndex < (uint)attribute.ConstructorArguments.Length)
+ {
+ yield return attribute.ConstructorArguments[argIndex].ToCSharpString();
+ }
+ }
+ }
+
+ private static string GetFirstAttributeAgument(Compilation compilation, SyntaxNode syntaxNode, string attributeName, int argIndex)
+ {
+ return GetAttributeAguments(compilation, syntaxNode, attributeName, argIndex).FirstOrDefault();
+ }
+
+ private static void GenerateMethod(CodeGenerator generator, Compilation compilation, MethodDeclarationSyntax method)
+ {
+ int inObjectsCount = 0;
+ int outObjectsCount = 0;
+ int buffersCount = 0;
+
+ foreach (var parameter in method.ParameterList.Parameters)
+ {
+ if (IsObject(compilation, parameter))
+ {
+ if (IsIn(parameter))
+ {
+ inObjectsCount++;
+ }
+ else
+ {
+ outObjectsCount++;
+ }
+ }
+ else if (IsBuffer(compilation, parameter))
+ {
+ buffersCount++;
+ }
+ }
+
+ generator.EnterScope($"private Result {method.Identifier.Text}(" +
+ "ref ServiceDispatchContext context, " +
+ "HipcCommandProcessor processor, " +
+ "ServerMessageRuntimeMetadata runtimeMetadata, " +
+ "ReadOnlySpan<byte> inRawData, " +
+ "ref Span<CmifOutHeader> outHeader)");
+
+ bool returnsResult = method.ReturnType != null && GetCanonicalTypeName(compilation, method.ReturnType) == TypeResult;
+
+ if (returnsResult || buffersCount != 0 || inObjectsCount != 0)
+ {
+ generator.AppendLine($"Result {ResultVariableName};");
+
+ if (buffersCount != 0)
+ {
+ generator.AppendLine($"bool[] {IsBufferMapAliasVariableName} = new bool[{method.ParameterList.Parameters.Count}];");
+ generator.AppendLine();
+
+ generator.AppendLine($"{ResultVariableName} = processor.ProcessBuffers(ref context, {IsBufferMapAliasVariableName}, runtimeMetadata);");
+ generator.EnterScope($"if ({ResultVariableName}.IsFailure)");
+ generator.AppendLine($"return {ResultVariableName};");
+ generator.LeaveScope();
+ }
+
+ generator.AppendLine();
+ }
+
+ List<OutParameter> outParameters = new List<OutParameter>();
+
+ string[] args = new string[method.ParameterList.Parameters.Count];
+
+ if (inObjectsCount != 0)
+ {
+ generator.AppendLine($"var {InObjectsVariableName} = new IServiceObject[{inObjectsCount}];");
+ generator.AppendLine();
+
+ generator.AppendLine($"{ResultVariableName} = processor.GetInObjects(context.Processor, {InObjectsVariableName});");
+ generator.EnterScope($"if ({ResultVariableName}.IsFailure)");
+ generator.AppendLine($"return {ResultVariableName};");
+ generator.LeaveScope();
+ generator.AppendLine();
+ }
+
+ if (outObjectsCount != 0)
+ {
+ generator.AppendLine($"var {OutObjectsVariableName} = new IServiceObject[{outObjectsCount}];");
+ }
+
+ int index = 0;
+ int inCopyHandleIndex = 0;
+ int inMoveHandleIndex = 0;
+ int inObjectIndex = 0;
+
+ foreach (var parameter in method.ParameterList.Parameters)
+ {
+ string name = parameter.Identifier.Text;
+ string argName = GetPrefixedArgName(name);
+ string canonicalTypeName = GetCanonicalTypeNameWithGenericArguments(compilation, parameter.Type);
+ CommandArgType argType = GetCommandArgType(compilation, parameter);
+ Modifier modifier = GetModifier(parameter);
+ bool isNonSpanBuffer = false;
+
+ if (modifier == Modifier.Out)
+ {
+ if (IsNonSpanOutBuffer(compilation, parameter))
+ {
+ generator.AppendLine($"using var {argName} = CommandSerialization.GetWritableRegion(processor.GetBufferRange({index}));");
+
+ argName = $"out {GenerateSpanCastElement0(canonicalTypeName, $"{argName}.Memory.Span")}";
+ }
+ else
+ {
+ outParameters.Add(new OutParameter(argName, canonicalTypeName, index, argType));
+
+ argName = $"out {canonicalTypeName} {argName}";
+ }
+ }
+ else
+ {
+ string value = $"default({canonicalTypeName})";
+
+ switch (argType)
+ {
+ case CommandArgType.InArgument:
+ value = $"CommandSerialization.DeserializeArg<{canonicalTypeName}>(inRawData, processor.GetInArgOffset({index}))";
+ break;
+ case CommandArgType.InCopyHandle:
+ value = $"CommandSerialization.DeserializeCopyHandle(ref context, {inCopyHandleIndex++})";
+ break;
+ case CommandArgType.InMoveHandle:
+ value = $"CommandSerialization.DeserializeMoveHandle(ref context, {inMoveHandleIndex++})";
+ break;
+ case CommandArgType.ProcessId:
+ value = "CommandSerialization.DeserializeClientProcessId(ref context)";
+ break;
+ case CommandArgType.InObject:
+ value = $"{InObjectsVariableName}[{inObjectIndex++}]";
+ break;
+ case CommandArgType.Buffer:
+ if (IsReadOnlySpan(compilation, parameter))
+ {
+ string spanGenericTypeName = GetCanonicalTypeNameOfGenericArgument(compilation, parameter.Type, 0);
+ value = GenerateSpanCast(spanGenericTypeName, $"CommandSerialization.GetReadOnlySpan(processor.GetBufferRange({index}))");
+ }
+ else if (IsSpan(compilation, parameter))
+ {
+ value = $"CommandSerialization.GetWritableRegion(processor.GetBufferRange({index}))";
+ }
+ else
+ {
+ value = $"CommandSerialization.GetRef<{canonicalTypeName}>(processor.GetBufferRange({index}))";
+ isNonSpanBuffer = true;
+ }
+ break;
+ }
+
+ if (IsSpan(compilation, parameter))
+ {
+ generator.AppendLine($"using var {argName} = {value};");
+
+ string spanGenericTypeName = GetCanonicalTypeNameOfGenericArgument(compilation, parameter.Type, 0);
+ argName = GenerateSpanCast(spanGenericTypeName, $"{argName}.Memory.Span"); ;
+ }
+ else if (isNonSpanBuffer)
+ {
+ generator.AppendLine($"ref var {argName} = ref {value};");
+ }
+ else if (argType == CommandArgType.InObject)
+ {
+ generator.EnterScope($"if (!({value} is {canonicalTypeName} {argName}))");
+ generator.AppendLine("return SfResult.InvalidInObject;");
+ generator.LeaveScope();
+ }
+ else
+ {
+ generator.AppendLine($"var {argName} = {value};");
+ }
+ }
+
+ if (modifier == Modifier.Ref)
+ {
+ argName = $"ref {argName}";
+ }
+ else if (modifier == Modifier.In)
+ {
+ argName = $"in {argName}";
+ }
+
+ args[index++] = argName;
+ }
+
+ if (args.Length - outParameters.Count > 0)
+ {
+ generator.AppendLine();
+ }
+
+ if (returnsResult)
+ {
+ generator.AppendLine($"{ResultVariableName} = {method.Identifier.Text}({string.Join(", ", args)});");
+ generator.AppendLine();
+
+ generator.AppendLine($"Span<byte> {OutRawDataVariableName};");
+ generator.AppendLine();
+
+ generator.EnterScope($"if ({ResultVariableName}.IsFailure)");
+ generator.AppendLine($"context.Processor.PrepareForErrorReply(ref context, out {OutRawDataVariableName}, runtimeMetadata);");
+ generator.AppendLine($"CommandHandler.GetCmifOutHeaderPointer(ref outHeader, ref {OutRawDataVariableName});");
+ generator.AppendLine($"return {ResultVariableName};");
+ generator.LeaveScope();
+ }
+ else
+ {
+ generator.AppendLine($"{method.Identifier.Text}({string.Join(", ", args)});");
+
+ generator.AppendLine();
+ generator.AppendLine($"Span<byte> {OutRawDataVariableName};");
+ }
+
+ generator.AppendLine();
+
+ generator.AppendLine($"var {ResponseVariableName} = context.Processor.PrepareForReply(ref context, out {OutRawDataVariableName}, runtimeMetadata);");
+ generator.AppendLine($"CommandHandler.GetCmifOutHeaderPointer(ref outHeader, ref {OutRawDataVariableName});");
+ generator.AppendLine();
+
+ generator.EnterScope($"if ({OutRawDataVariableName}.Length < processor.OutRawDataSize)");
+ generator.AppendLine("return SfResult.InvalidOutRawSize;");
+ generator.LeaveScope();
+
+ if (outParameters.Count != 0)
+ {
+ generator.AppendLine();
+
+ int outCopyHandleIndex = 0;
+ int outMoveHandleIndex = outObjectsCount;
+ int outObjectIndex = 0;
+
+ for (int outIndex = 0; outIndex < outParameters.Count; outIndex++)
+ {
+ OutParameter outParameter = outParameters[outIndex];
+
+ switch (outParameter.Type)
+ {
+ case CommandArgType.OutArgument:
+ generator.AppendLine($"CommandSerialization.SerializeArg<{outParameter.TypeName}>({OutRawDataVariableName}, processor.GetOutArgOffset({outParameter.Index}), {outParameter.Name});");
+ break;
+ case CommandArgType.OutCopyHandle:
+ generator.AppendLine($"CommandSerialization.SerializeCopyHandle({ResponseVariableName}, {outCopyHandleIndex++}, {outParameter.Name});");
+ break;
+ case CommandArgType.OutMoveHandle:
+ generator.AppendLine($"CommandSerialization.SerializeMoveHandle({ResponseVariableName}, {outMoveHandleIndex++}, {outParameter.Name});");
+ break;
+ case CommandArgType.OutObject:
+ generator.AppendLine($"{OutObjectsVariableName}[{outObjectIndex++}] = {outParameter.Name};");
+ break;
+ }
+ }
+ }
+
+ generator.AppendLine();
+
+ if (outObjectsCount != 0 || buffersCount != 0)
+ {
+ if (outObjectsCount != 0)
+ {
+ generator.AppendLine($"processor.SetOutObjects(ref context, {ResponseVariableName}, {OutObjectsVariableName});");
+ }
+
+ if (buffersCount != 0)
+ {
+ generator.AppendLine($"processor.SetOutBuffers({ResponseVariableName}, {IsBufferMapAliasVariableName});");
+ }
+
+ generator.AppendLine();
+ }
+
+ generator.AppendLine("return Result.Success;");
+ generator.LeaveScope();
+ }
+
+ private static string GetPrefixedArgName(string name)
+ {
+ return ArgVariablePrefix + name[0].ToString().ToUpperInvariant() + name.Substring(1);
+ }
+
+ private static string GetCanonicalTypeNameOfGenericArgument(Compilation compilation, SyntaxNode syntaxNode, int argIndex)
+ {
+ if (syntaxNode is GenericNameSyntax genericNameSyntax)
+ {
+ if ((uint)argIndex < (uint)genericNameSyntax.TypeArgumentList.Arguments.Count)
+ {
+ return GetCanonicalTypeNameWithGenericArguments(compilation, genericNameSyntax.TypeArgumentList.Arguments[argIndex]);
+ }
+ }
+
+ return GetCanonicalTypeName(compilation, syntaxNode);
+ }
+
+ private static string GetCanonicalTypeNameWithGenericArguments(Compilation compilation, SyntaxNode syntaxNode)
+ {
+ TypeInfo typeInfo = compilation.GetSemanticModel(syntaxNode.SyntaxTree).GetTypeInfo(syntaxNode);
+
+ return typeInfo.Type.ToDisplayString();
+ }
+
+ private static string GetCanonicalTypeName(Compilation compilation, SyntaxNode syntaxNode)
+ {
+ TypeInfo typeInfo = compilation.GetSemanticModel(syntaxNode.SyntaxTree).GetTypeInfo(syntaxNode);
+ string typeName = typeInfo.Type.ToDisplayString();
+
+ int genericArgsStartIndex = typeName.IndexOf('<');
+ if (genericArgsStartIndex >= 0)
+ {
+ return typeName.Substring(0, genericArgsStartIndex);
+ }
+
+ return typeName;
+ }
+
+ private static SpecialType GetSpecialTypeName(Compilation compilation, SyntaxNode syntaxNode)
+ {
+ TypeInfo typeInfo = compilation.GetSemanticModel(syntaxNode.SyntaxTree).GetTypeInfo(syntaxNode);
+
+ return typeInfo.Type.SpecialType;
+ }
+
+ private static string GetTypeAlignmentExpression(Compilation compilation, SyntaxNode syntaxNode)
+ {
+ TypeInfo typeInfo = compilation.GetSemanticModel(syntaxNode.SyntaxTree).GetTypeInfo(syntaxNode);
+
+ // Since there's no way to get the alignment for a arbitrary type here, let's assume that all
+ // "special" types are primitive types aligned to their own length.
+ // Otherwise, assume that the type is a custom struct, that either defines an explicit alignment
+ // or has an alignment of 1 which is the lowest possible value.
+ if (typeInfo.Type.SpecialType == SpecialType.None)
+ {
+ string pack = GetTypeFirstNamedAttributeAgument(compilation, syntaxNode, TypeStructLayoutAttribute, "Pack");
+
+ return pack ?? "1";
+ }
+ else
+ {
+ return $"Unsafe.SizeOf<{typeInfo.Type.ToDisplayString()}>()";
+ }
+ }
+
+ private static string GetTypeFirstNamedAttributeAgument(Compilation compilation, SyntaxNode syntaxNode, string attributeName, string argName)
+ {
+ ISymbol symbol = compilation.GetSemanticModel(syntaxNode.SyntaxTree).GetTypeInfo(syntaxNode).Type;
+
+ foreach (var attribute in symbol.GetAttributes())
+ {
+ if (attribute.AttributeClass.ToDisplayString() == attributeName)
+ {
+ foreach (var kv in attribute.NamedArguments)
+ {
+ if (kv.Key == argName)
+ {
+ return kv.Value.ToCSharpString();
+ }
+ }
+ }
+ }
+
+ return null;
+ }
+
+ private static CommandArgType GetCommandArgType(Compilation compilation, ParameterSyntax parameter)
+ {
+ CommandArgType type = CommandArgType.Invalid;
+
+ if (IsIn(parameter))
+ {
+ if (IsArgument(compilation, parameter))
+ {
+ type = CommandArgType.InArgument;
+ }
+ else if (IsBuffer(compilation, parameter))
+ {
+ type = CommandArgType.Buffer;
+ }
+ else if (IsCopyHandle(compilation, parameter))
+ {
+ type = CommandArgType.InCopyHandle;
+ }
+ else if (IsMoveHandle(compilation, parameter))
+ {
+ type = CommandArgType.InMoveHandle;
+ }
+ else if (IsObject(compilation, parameter))
+ {
+ type = CommandArgType.InObject;
+ }
+ else if (IsProcessId(compilation, parameter))
+ {
+ type = CommandArgType.ProcessId;
+ }
+ }
+ else if (IsOut(parameter))
+ {
+ if (IsArgument(compilation, parameter))
+ {
+ type = CommandArgType.OutArgument;
+ }
+ else if (IsNonSpanOutBuffer(compilation, parameter))
+ {
+ type = CommandArgType.Buffer;
+ }
+ else if (IsCopyHandle(compilation, parameter))
+ {
+ type = CommandArgType.OutCopyHandle;
+ }
+ else if (IsMoveHandle(compilation, parameter))
+ {
+ type = CommandArgType.OutMoveHandle;
+ }
+ else if (IsObject(compilation, parameter))
+ {
+ type = CommandArgType.OutObject;
+ }
+ }
+
+ return type;
+ }
+
+ private static bool IsArgument(Compilation compilation,ParameterSyntax parameter)
+ {
+ return !IsBuffer(compilation, parameter) &&
+ !IsHandle(compilation, parameter) &&
+ !IsObject(compilation, parameter) &&
+ !IsProcessId(compilation, parameter) &&
+ IsUnmanagedType(compilation, parameter.Type);
+ }
+
+ private static bool IsBuffer(Compilation compilation, ParameterSyntax parameter)
+ {
+ return HasAttribute(compilation, parameter, TypeBufferAttribute) &&
+ IsValidTypeForBuffer(compilation, parameter);
+ }
+
+ private static bool IsNonSpanOutBuffer(Compilation compilation, ParameterSyntax parameter)
+ {
+ return HasAttribute(compilation, parameter, TypeBufferAttribute) &&
+ IsUnmanagedType(compilation, parameter.Type);
+ }
+
+ private static bool IsValidTypeForBuffer(Compilation compilation, ParameterSyntax parameter)
+ {
+ return IsReadOnlySpan(compilation, parameter) ||
+ IsSpan(compilation, parameter) ||
+ IsUnmanagedType(compilation, parameter.Type);
+ }
+
+ private static bool IsUnmanagedType(Compilation compilation, SyntaxNode syntaxNode)
+ {
+ TypeInfo typeInfo = compilation.GetSemanticModel(syntaxNode.SyntaxTree).GetTypeInfo(syntaxNode);
+
+ return typeInfo.Type.IsUnmanagedType;
+ }
+
+ private static bool IsReadOnlySpan(Compilation compilation, ParameterSyntax parameter)
+ {
+ return GetCanonicalTypeName(compilation, parameter.Type) == TypeSystemReadOnlySpan;
+ }
+
+ private static bool IsSpan(Compilation compilation, ParameterSyntax parameter)
+ {
+ return GetCanonicalTypeName(compilation, parameter.Type) == TypeSystemSpan;
+ }
+
+ private static bool IsHandle(Compilation compilation, ParameterSyntax parameter)
+ {
+ return IsCopyHandle(compilation, parameter) || IsMoveHandle(compilation, parameter);
+ }
+
+ private static bool IsCopyHandle(Compilation compilation, ParameterSyntax parameter)
+ {
+ return HasAttribute(compilation, parameter, TypeCopyHandleAttribute) &&
+ GetSpecialTypeName(compilation, parameter.Type) == SpecialType.System_Int32;
+ }
+
+ private static bool IsMoveHandle(Compilation compilation, ParameterSyntax parameter)
+ {
+ return HasAttribute(compilation, parameter, TypeMoveHandleAttribute) &&
+ GetSpecialTypeName(compilation, parameter.Type) == SpecialType.System_Int32;
+ }
+
+ private static bool IsObject(Compilation compilation, ParameterSyntax parameter)
+ {
+ SyntaxNode syntaxNode = parameter.Type;
+ TypeInfo typeInfo = compilation.GetSemanticModel(syntaxNode.SyntaxTree).GetTypeInfo(syntaxNode);
+
+ return typeInfo.Type.ToDisplayString() == TypeIServiceObject ||
+ typeInfo.Type.AllInterfaces.Any(x => x.ToDisplayString() == TypeIServiceObject);
+ }
+
+ private static bool IsProcessId(Compilation compilation, ParameterSyntax parameter)
+ {
+ return HasAttribute(compilation, parameter, TypeClientProcessIdAttribute) &&
+ GetSpecialTypeName(compilation, parameter.Type) == SpecialType.System_UInt64;
+ }
+
+ private static bool IsIn(ParameterSyntax parameter)
+ {
+ return !IsOut(parameter);
+ }
+
+ private static bool IsOut(ParameterSyntax parameter)
+ {
+ return parameter.Modifiers.Any(SyntaxKind.OutKeyword);
+ }
+
+ private static Modifier GetModifier(ParameterSyntax parameter)
+ {
+ foreach (SyntaxToken syntaxToken in parameter.Modifiers)
+ {
+ if (syntaxToken.IsKind(SyntaxKind.RefKeyword))
+ {
+ return Modifier.Ref;
+ }
+ else if (syntaxToken.IsKind(SyntaxKind.OutKeyword))
+ {
+ return Modifier.Out;
+ }
+ else if (syntaxToken.IsKind(SyntaxKind.InKeyword))
+ {
+ return Modifier.In;
+ }
+ }
+
+ return Modifier.None;
+ }
+
+ private static string GenerateSpanCastElement0(string targetType, string input)
+ {
+ return $"{GenerateSpanCast(targetType, input)}[0]";
+ }
+
+ private static string GenerateSpanCast(string targetType, string input)
+ {
+ return $"MemoryMarshal.Cast<byte, {targetType}>({input})";
+ }
+
+ private static bool HasAttribute(Compilation compilation, ParameterSyntax parameterSyntax, string fullAttributeName)
+ {
+ foreach (var attributeList in parameterSyntax.AttributeLists)
+ {
+ foreach (var attribute in attributeList.Attributes)
+ {
+ if (GetCanonicalTypeName(compilation, attribute) == fullAttributeName)
+ {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ private static bool NeedsIServiceObjectImplementation(Compilation compilation, ClassDeclarationSyntax classDeclarationSyntax)
+ {
+ ITypeSymbol type = compilation.GetSemanticModel(classDeclarationSyntax.SyntaxTree).GetDeclaredSymbol(classDeclarationSyntax);
+ var serviceObjectInterface = type.AllInterfaces.FirstOrDefault(x => x.ToDisplayString() == TypeIServiceObject);
+ var interfaceMember = serviceObjectInterface?.GetMembers().FirstOrDefault(x => x.Name == "GetCommandHandlers");
+
+ // Return true only if the class implements IServiceObject but does not actually implement the method
+ // that the interface defines, since this is the only case we want to handle, if the method already exists
+ // we have nothing to do.
+ return serviceObjectInterface != null && type.FindImplementationForInterfaceMember(interfaceMember) == null;
+ }
+
+ public void Initialize(GeneratorInitializationContext context)
+ {
+ context.RegisterForSyntaxNotifications(() => new HipcSyntaxReceiver());
+ }
+ }
+}
diff --git a/Ryujinx.Horizon.Generators/Hipc/HipcSyntaxReceiver.cs b/Ryujinx.Horizon.Generators/Hipc/HipcSyntaxReceiver.cs
new file mode 100644
index 00000000..4b998dbe
--- /dev/null
+++ b/Ryujinx.Horizon.Generators/Hipc/HipcSyntaxReceiver.cs
@@ -0,0 +1,58 @@
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Ryujinx.Horizon.Generators.Hipc
+{
+ class HipcSyntaxReceiver : ISyntaxReceiver
+ {
+ public List<CommandInterface> CommandInterfaces { get; }
+
+ public HipcSyntaxReceiver()
+ {
+ CommandInterfaces = new List<CommandInterface>();
+ }
+
+ public void OnVisitSyntaxNode(SyntaxNode syntaxNode)
+ {
+ if (syntaxNode is ClassDeclarationSyntax classDeclaration)
+ {
+ if (!classDeclaration.Modifiers.Any(SyntaxKind.PartialKeyword) || classDeclaration.BaseList == null)
+ {
+ return;
+ }
+
+ CommandInterface commandInterface = new CommandInterface(classDeclaration);
+
+ foreach (var memberDeclaration in classDeclaration.Members)
+ {
+ if (memberDeclaration is MethodDeclarationSyntax methodDeclaration)
+ {
+ VisitMethod(commandInterface, methodDeclaration);
+ }
+ }
+
+ CommandInterfaces.Add(commandInterface);
+ }
+ }
+
+ private void VisitMethod(CommandInterface commandInterface, MethodDeclarationSyntax methodDeclaration)
+ {
+ string attributeName = HipcGenerator.CommandAttributeName.Replace("Attribute", string.Empty);
+
+ if (methodDeclaration.AttributeLists.Count != 0)
+ {
+ foreach (var attributeList in methodDeclaration.AttributeLists)
+ {
+ if (attributeList.Attributes.Any(x => x.Name.ToString().Contains(attributeName)))
+ {
+ commandInterface.CommandImplementations.Add(methodDeclaration);
+ break;
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/Ryujinx.Horizon.Kernel.Generators/CodeGenerator.cs b/Ryujinx.Horizon.Kernel.Generators/CodeGenerator.cs
new file mode 100644
index 00000000..80a33c66
--- /dev/null
+++ b/Ryujinx.Horizon.Kernel.Generators/CodeGenerator.cs
@@ -0,0 +1,58 @@
+using System.Text;
+
+namespace Ryujinx.Horizon.Generators
+{
+ class CodeGenerator
+ {
+ private const string Indent = " ";
+ private readonly StringBuilder _sb;
+ private string _currentIndent;
+
+ public CodeGenerator()
+ {
+ _sb = new StringBuilder();
+ }
+
+ public void EnterScope(string header = null)
+ {
+ if (header != null)
+ {
+ AppendLine(header);
+ }
+
+ AppendLine("{");
+ IncreaseIndentation();
+ }
+
+ public void LeaveScope()
+ {
+ DecreaseIndentation();
+ AppendLine("}");
+ }
+
+ public void IncreaseIndentation()
+ {
+ _currentIndent += Indent;
+ }
+
+ public void DecreaseIndentation()
+ {
+ _currentIndent = _currentIndent.Substring(0, _currentIndent.Length - Indent.Length);
+ }
+
+ public void AppendLine()
+ {
+ _sb.AppendLine();
+ }
+
+ public void AppendLine(string text)
+ {
+ _sb.AppendLine(_currentIndent + text);
+ }
+
+ public override string ToString()
+ {
+ return _sb.ToString();
+ }
+ }
+}
diff --git a/Ryujinx.Horizon.Generators/Kernel/SyscallGenerator.cs b/Ryujinx.Horizon.Kernel.Generators/Kernel/SyscallGenerator.cs
index 2562cd46..f2a87703 100644
--- a/Ryujinx.Horizon.Generators/Kernel/SyscallGenerator.cs
+++ b/Ryujinx.Horizon.Kernel.Generators/Kernel/SyscallGenerator.cs
@@ -25,15 +25,17 @@ namespace Ryujinx.Horizon.Generators.Kernel
private const string TypeSystemUInt64 = "System.UInt64";
private const string NamespaceKernel = "Ryujinx.HLE.HOS.Kernel";
+ private const string NamespaceHorizonCommon = "Ryujinx.Horizon.Common";
private const string TypeSvcAttribute = NamespaceKernel + ".SupervisorCall.SvcAttribute";
private const string TypePointerSizedAttribute = NamespaceKernel + ".SupervisorCall.PointerSizedAttribute";
+ private const string TypeResultName = "Result";
private const string TypeKernelResultName = "KernelResult";
- private const string TypeKernelResult = NamespaceKernel + ".Common." + TypeKernelResultName;
+ private const string TypeResult = NamespaceHorizonCommon + "." + TypeResultName;
private const string TypeExecutionContext = "IExecutionContext";
private static readonly string[] _expectedResults = new string[]
{
- $"{TypeKernelResultName}.Success",
+ $"{TypeResultName}.Success",
$"{TypeKernelResultName}.TimedOut",
$"{TypeKernelResultName}.Cancelled",
$"{TypeKernelResultName}.PortRemoteClosed",
@@ -133,6 +135,7 @@ namespace Ryujinx.Horizon.Generators.Kernel
generator.AppendLine($"using {NamespaceKernel}.Memory;");
generator.AppendLine($"using {NamespaceKernel}.Process;");
generator.AppendLine($"using {NamespaceKernel}.Threading;");
+ generator.AppendLine($"using {NamespaceHorizonCommon};");
generator.AppendLine("using System;");
generator.AppendLine();
generator.EnterScope($"namespace {ClassNamespace}");
@@ -183,7 +186,7 @@ namespace Ryujinx.Horizon.Generators.Kernel
private static void GenerateResultCheckHelper(CodeGenerator generator)
{
- generator.EnterScope($"private static bool {ResultCheckHelperName}({TypeKernelResultName} {ResultVariableName})");
+ generator.EnterScope($"private static bool {ResultCheckHelperName}({TypeResultName} {ResultVariableName})");
string[] expectedChecks = new string[_expectedResults.Length];
@@ -266,19 +269,25 @@ namespace Ryujinx.Horizon.Generators.Kernel
GenerateLogPrintBeforeCall(generator, method.Identifier.Text, logInArgs);
- string returnTypeName = method.ReturnType.ToString();
string argsList = string.Join(", ", args);
int returnRegisterIndex = 0;
string result = null;
string canonicalReturnTypeName = null;
- if (returnTypeName != "void")
+ if (method.ReturnType.ToString() != "void")
{
generator.AppendLine($"var {ResultVariableName} = syscall.{method.Identifier.Text}({argsList});");
- generator.AppendLine($"context.SetX({returnRegisterIndex++}, (uint){ResultVariableName});");
-
canonicalReturnTypeName = GetCanonicalTypeName(compilation, method.ReturnType);
+ if (canonicalReturnTypeName == TypeResult)
+ {
+ generator.AppendLine($"context.SetX({returnRegisterIndex++}, (uint){ResultVariableName}.ErrorCode);");
+ }
+ else
+ {
+ generator.AppendLine($"context.SetX({returnRegisterIndex++}, (uint){ResultVariableName});");
+ }
+
if (Is64BitInteger(canonicalReturnTypeName))
{
generator.AppendLine($"context.SetX({returnRegisterIndex++}, (uint)({ResultVariableName} >> 32));");
@@ -358,8 +367,17 @@ namespace Ryujinx.Horizon.Generators.Kernel
if (method.ReturnType.ToString() != "void")
{
generator.AppendLine($"var {ResultVariableName} = syscall.{method.Identifier.Text}({argsList});");
- generator.AppendLine($"context.SetX({returnRegisterIndex++}, (ulong){ResultVariableName});");
canonicalReturnTypeName = GetCanonicalTypeName(compilation, method.ReturnType);
+
+ if (canonicalReturnTypeName == TypeResult)
+ {
+ generator.AppendLine($"context.SetX({returnRegisterIndex++}, (ulong){ResultVariableName}.ErrorCode);");
+ }
+ else
+ {
+ generator.AppendLine($"context.SetX({returnRegisterIndex++}, (ulong){ResultVariableName});");
+ }
+
result = GetFormattedLogValue(ResultVariableName, canonicalReturnTypeName);
}
else
@@ -433,7 +451,7 @@ namespace Ryujinx.Horizon.Generators.Kernel
log += $" = {result}";
}
- if (canonicalResultTypeName == TypeKernelResult)
+ if (canonicalResultTypeName == TypeResult)
{
generator.EnterScope($"if ({ResultCheckHelperName}({ResultVariableName}))");
GenerateLogPrint(generator, "Trace", "KernelSvc", log);
diff --git a/Ryujinx.Horizon.Generators/Kernel/SyscallSyntaxReceiver.cs b/Ryujinx.Horizon.Kernel.Generators/Kernel/SyscallSyntaxReceiver.cs
index e2e8e1d3..e2e8e1d3 100644
--- a/Ryujinx.Horizon.Generators/Kernel/SyscallSyntaxReceiver.cs
+++ b/Ryujinx.Horizon.Kernel.Generators/Kernel/SyscallSyntaxReceiver.cs
diff --git a/Ryujinx.Horizon.Kernel.Generators/Ryujinx.Horizon.Kernel.Generators.csproj b/Ryujinx.Horizon.Kernel.Generators/Ryujinx.Horizon.Kernel.Generators.csproj
new file mode 100644
index 00000000..67fab2d5
--- /dev/null
+++ b/Ryujinx.Horizon.Kernel.Generators/Ryujinx.Horizon.Kernel.Generators.csproj
@@ -0,0 +1,15 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+ <PropertyGroup>
+ <TargetFramework>netstandard2.0</TargetFramework>
+ </PropertyGroup>
+
+ <ItemGroup>
+ <PackageReference Include="Microsoft.CodeAnalysis.Analyzers">
+ <PrivateAssets>all</PrivateAssets>
+ <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
+ </PackageReference>
+ <PackageReference Include="Microsoft.CodeAnalysis.CSharp" />
+ </ItemGroup>
+
+</Project>
diff --git a/Ryujinx.Horizon/HeapAllocator.cs b/Ryujinx.Horizon/HeapAllocator.cs
new file mode 100644
index 00000000..867c9677
--- /dev/null
+++ b/Ryujinx.Horizon/HeapAllocator.cs
@@ -0,0 +1,143 @@
+using Ryujinx.Common;
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+
+namespace Ryujinx.Horizon
+{
+ class HeapAllocator
+ {
+ private const ulong InvalidAddress = ulong.MaxValue;
+
+ private struct Range : IComparable<Range>
+ {
+ public ulong Offset { get; }
+ public ulong Size { get; }
+
+ public Range(ulong offset, ulong size)
+ {
+ Offset = offset;
+ Size = size;
+ }
+
+ public int CompareTo(Range other)
+ {
+ return Offset.CompareTo(other.Offset);
+ }
+ }
+
+ private readonly List<Range> _freeRanges;
+ private ulong _currentHeapSize;
+
+ public HeapAllocator()
+ {
+ _freeRanges = new List<Range>();
+ _currentHeapSize = 0;
+ }
+
+ public ulong Allocate(ulong size, ulong alignment = 1UL)
+ {
+ ulong address = AllocateImpl(size, alignment);
+
+ if (address == InvalidAddress)
+ {
+ ExpandHeap(size + alignment - 1UL);
+
+ address = AllocateImpl(size, alignment);
+
+ Debug.Assert(address != InvalidAddress);
+ }
+
+ return address;
+ }
+
+ private void ExpandHeap(ulong expansionSize)
+ {
+ ulong oldHeapSize = _currentHeapSize;
+ ulong newHeapSize = BitUtils.AlignUp(oldHeapSize + expansionSize, 0x200000UL);
+
+ _currentHeapSize = newHeapSize;
+
+ HorizonStatic.Syscall.SetHeapSize(out ulong heapAddress, newHeapSize).AbortOnFailure();
+
+ Free(heapAddress + oldHeapSize, newHeapSize - oldHeapSize);
+ }
+
+ private ulong AllocateImpl(ulong size, ulong alignment)
+ {
+ for (int i = 0; i < _freeRanges.Count; i++)
+ {
+ var range = _freeRanges[i];
+
+ ulong alignedOffset = BitUtils.AlignUp(range.Offset, alignment);
+ ulong sizeDelta = alignedOffset - range.Offset;
+ ulong usableSize = range.Size - sizeDelta;
+
+ if (sizeDelta < range.Size && usableSize >= size)
+ {
+ _freeRanges.RemoveAt(i);
+
+ if (sizeDelta != 0)
+ {
+ InsertFreeRange(range.Offset, sizeDelta);
+ }
+
+ ulong endOffset = range.Offset + range.Size;
+ ulong remainingSize = endOffset - (alignedOffset + size);
+ if (remainingSize != 0)
+ {
+ InsertFreeRange(endOffset - remainingSize, remainingSize);
+ }
+
+ return alignedOffset;
+ }
+ }
+
+ return InvalidAddress;
+ }
+
+ public void Free(ulong offset, ulong size)
+ {
+ InsertFreeRangeComingled(offset, size);
+ }
+
+ private void InsertFreeRange(ulong offset, ulong size)
+ {
+ var range = new Range(offset, size);
+ int index = _freeRanges.BinarySearch(range);
+ if (index < 0)
+ {
+ index = ~index;
+ }
+
+ _freeRanges.Insert(index, range);
+ }
+
+ private void InsertFreeRangeComingled(ulong offset, ulong size)
+ {
+ ulong endOffset = offset + size;
+ var range = new Range(offset, size);
+ int index = _freeRanges.BinarySearch(range);
+ if (index < 0)
+ {
+ index = ~index;
+ }
+
+ if (index < _freeRanges.Count && _freeRanges[index].Offset == endOffset)
+ {
+ endOffset = _freeRanges[index].Offset + _freeRanges[index].Size;
+ _freeRanges.RemoveAt(index);
+ }
+
+ if (index > 0 && _freeRanges[index - 1].Offset + _freeRanges[index - 1].Size == offset)
+ {
+ offset = _freeRanges[index - 1].Offset;
+ _freeRanges.RemoveAt(--index);
+ }
+
+ range = new Range(offset, endOffset - offset);
+
+ _freeRanges.Insert(index, range);
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Horizon/HorizonOptions.cs b/Ryujinx.Horizon/HorizonOptions.cs
new file mode 100644
index 00000000..b1567c6a
--- /dev/null
+++ b/Ryujinx.Horizon/HorizonOptions.cs
@@ -0,0 +1,12 @@
+namespace Ryujinx.Horizon
+{
+ public struct HorizonOptions
+ {
+ public bool IgnoreMissingServices { get; }
+
+ public HorizonOptions(bool ignoreMissingServices)
+ {
+ IgnoreMissingServices = ignoreMissingServices;
+ }
+ }
+}
diff --git a/Ryujinx.Horizon/HorizonStatic.cs b/Ryujinx.Horizon/HorizonStatic.cs
new file mode 100644
index 00000000..1e483cd4
--- /dev/null
+++ b/Ryujinx.Horizon/HorizonStatic.cs
@@ -0,0 +1,44 @@
+using Ryujinx.Horizon.Common;
+using Ryujinx.Memory;
+using System;
+
+namespace Ryujinx.Horizon
+{
+ static class HorizonStatic
+ {
+ [ThreadStatic]
+ private static HorizonOptions _options;
+
+ [ThreadStatic]
+ private static ISyscallApi _syscall;
+
+ [ThreadStatic]
+ private static IVirtualMemoryManager _addressSpace;
+
+ [ThreadStatic]
+ private static IThreadContext _threadContext;
+
+ [ThreadStatic]
+ private static int _threadHandle;
+
+ public static HorizonOptions Options => _options;
+ public static ISyscallApi Syscall => _syscall;
+ public static IVirtualMemoryManager AddressSpace => _addressSpace;
+ public static IThreadContext ThreadContext => _threadContext;
+ public static int CurrentThreadHandle => _threadHandle;
+
+ public static void Register(
+ HorizonOptions options,
+ ISyscallApi syscallApi,
+ IVirtualMemoryManager addressSpace,
+ IThreadContext threadContext,
+ int threadHandle)
+ {
+ _options = options;
+ _syscall = syscallApi;
+ _addressSpace = addressSpace;
+ _threadContext = threadContext;
+ _threadHandle = threadHandle;
+ }
+ }
+}
diff --git a/Ryujinx.Horizon/IService.cs b/Ryujinx.Horizon/IService.cs
new file mode 100644
index 00000000..67c12cef
--- /dev/null
+++ b/Ryujinx.Horizon/IService.cs
@@ -0,0 +1,7 @@
+namespace Ryujinx.Horizon
+{
+ interface IService
+ {
+ abstract static void Main();
+ }
+}
diff --git a/Ryujinx.Horizon/LogManager/LmIpcServer.cs b/Ryujinx.Horizon/LogManager/LmIpcServer.cs
new file mode 100644
index 00000000..7b757fe9
--- /dev/null
+++ b/Ryujinx.Horizon/LogManager/LmIpcServer.cs
@@ -0,0 +1,54 @@
+using Ryujinx.Horizon.Sdk.Sf.Hipc;
+using Ryujinx.Horizon.Sdk.Sm;
+using Ryujinx.Horizon.Sm;
+
+namespace Ryujinx.Horizon.LogManager
+{
+ class LmIpcServer
+ {
+ private const int LogMaxSessionsCount = 42;
+
+ private const int PointerBufferSize = 0x400;
+ private const int MaxDomains = 31;
+ private const int MaxDomainObjects = 61;
+
+ private const int MaxPortsCount = 1;
+
+ private static readonly ManagerOptions _logManagerOptions = new ManagerOptions(
+ PointerBufferSize,
+ MaxDomains,
+ MaxDomainObjects,
+ false);
+
+ private static readonly ServiceName _logServiceName = ServiceName.Encode("lm");
+
+ private SmApi _sm;
+ private ServerManager _serverManager;
+
+ private LmLog _logServiceObject;
+
+ public void Initialize()
+ {
+ HeapAllocator allocator = new HeapAllocator();
+
+ _sm = new SmApi();
+ _sm.Initialize().AbortOnFailure();
+
+ _serverManager = new ServerManager(allocator, _sm, MaxPortsCount, _logManagerOptions, LogMaxSessionsCount);
+
+ _logServiceObject = new LmLog();
+
+ _serverManager.RegisterObjectForServer(_logServiceObject, _logServiceName, LogMaxSessionsCount);
+ }
+
+ public void ServiceRequests()
+ {
+ _serverManager.ServiceRequests();
+ }
+
+ public void Shutdown()
+ {
+ _serverManager.Dispose();
+ }
+ }
+}
diff --git a/Ryujinx.Horizon/LogManager/LmLog.cs b/Ryujinx.Horizon/LogManager/LmLog.cs
new file mode 100644
index 00000000..772465c4
--- /dev/null
+++ b/Ryujinx.Horizon/LogManager/LmLog.cs
@@ -0,0 +1,19 @@
+using Ryujinx.Horizon.Common;
+using Ryujinx.Horizon.Sdk.Lm;
+using Ryujinx.Horizon.Sdk.Sf;
+
+namespace Ryujinx.Horizon.LogManager
+{
+ partial class LmLog : IServiceObject
+ {
+ public LogDestination LogDestination { get; set; } = LogDestination.TargetManager;
+
+ [CmifCommand(0)]
+ public Result OpenLogger(out LmLogger logger, [ClientProcessId] ulong clientProcessId)
+ {
+ logger = new LmLogger(this, clientProcessId);
+
+ return Result.Success;
+ }
+ }
+}
diff --git a/Ryujinx.Horizon/LogManager/LmLogger.cs b/Ryujinx.Horizon/LogManager/LmLogger.cs
new file mode 100644
index 00000000..461776cd
--- /dev/null
+++ b/Ryujinx.Horizon/LogManager/LmLogger.cs
@@ -0,0 +1,139 @@
+using Ryujinx.Common.Logging;
+using Ryujinx.Common.Memory;
+using Ryujinx.Horizon.Common;
+using Ryujinx.Horizon.Sdk.Lm;
+using Ryujinx.Horizon.Sdk.Sf;
+using Ryujinx.Horizon.Sdk.Sf.Hipc;
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Text;
+
+namespace Ryujinx.Horizon.LogManager
+{
+ partial class LmLogger : IServiceObject
+ {
+ private readonly LmLog _log;
+ private readonly ulong _clientProcessId;
+
+ public LmLogger(LmLog log, ulong clientProcessId)
+ {
+ _log = log;
+ _clientProcessId = clientProcessId;
+ }
+
+ [CmifCommand(0)]
+ public Result Log([Buffer(HipcBufferFlags.In | HipcBufferFlags.AutoSelect)] Span<byte> message)
+ {
+ if (!SetProcessId(message, _clientProcessId))
+ {
+ return Result.Success;
+ }
+
+ Logger.Guest?.Print(LogClass.ServiceLm, LogImpl(message));
+
+ return Result.Success;
+ }
+
+ [CmifCommand(1)]
+ public Result SetDestination(LogDestination destination)
+ {
+ _log.LogDestination = destination;
+
+ return Result.Success;
+ }
+
+ private static bool SetProcessId(Span<byte> message, ulong processId)
+ {
+ ref LogPacketHeader header = ref MemoryMarshal.Cast<byte, LogPacketHeader>(message)[0];
+
+ uint expectedMessageSize = (uint)Unsafe.SizeOf<LogPacketHeader>() + header.PayloadSize;
+
+ if (expectedMessageSize != (uint)message.Length)
+ {
+ Logger.Warning?.Print(LogClass.ServiceLm, $"Invalid message size (expected 0x{expectedMessageSize:X} but got 0x{message.Length:X}).");
+
+ return false;
+ }
+
+ header.ProcessId = processId;
+
+ return true;
+ }
+
+ private static string LogImpl(ReadOnlySpan<byte> message)
+ {
+ SpanReader reader = new SpanReader(message);
+
+ LogPacketHeader header = reader.Read<LogPacketHeader>();
+
+ StringBuilder sb = new StringBuilder();
+
+ sb.AppendLine($"Guest Log:\n Log level: {header.Severity}");
+
+ while (reader.Length > 0)
+ {
+ int type = ReadUleb128(ref reader);
+ int size = ReadUleb128(ref reader);
+
+ LogDataChunkKey field = (LogDataChunkKey)type;
+
+ string fieldStr = string.Empty;
+
+ if (field == LogDataChunkKey.Start)
+ {
+ reader.Skip(size);
+
+ continue;
+ }
+ else if (field == LogDataChunkKey.Stop)
+ {
+ break;
+ }
+ else if (field == LogDataChunkKey.Line)
+ {
+ fieldStr = $"{field}: {reader.Read<int>()}";
+ }
+ else if (field == LogDataChunkKey.DropCount)
+ {
+ fieldStr = $"{field}: {reader.Read<long>()}";
+ }
+ else if (field == LogDataChunkKey.Time)
+ {
+ fieldStr = $"{field}: {reader.Read<long>()}s";
+ }
+ else if (field < LogDataChunkKey.Count)
+ {
+ fieldStr = $"{field}: '{Encoding.UTF8.GetString(reader.GetSpan(size)).TrimEnd()}'";
+ }
+ else
+ {
+ fieldStr = $"Field{field}: '{Encoding.UTF8.GetString(reader.GetSpan(size)).TrimEnd()}'";
+ }
+
+ sb.AppendLine($" {fieldStr}");
+ }
+
+ return sb.ToString();
+ }
+
+ private static int ReadUleb128(ref SpanReader reader)
+ {
+ int result = 0;
+ int count = 0;
+
+ byte encoded;
+
+ do
+ {
+ encoded = reader.Read<byte>();
+
+ result += (encoded & 0x7F) << (7 * count);
+
+ count++;
+ } while ((encoded & 0x80) != 0);
+
+ return result;
+ }
+ }
+}
diff --git a/Ryujinx.Horizon/LogManager/LmMain.cs b/Ryujinx.Horizon/LogManager/LmMain.cs
new file mode 100644
index 00000000..8c0262ac
--- /dev/null
+++ b/Ryujinx.Horizon/LogManager/LmMain.cs
@@ -0,0 +1,14 @@
+namespace Ryujinx.Horizon.LogManager
+{
+ class LmMain : IService
+ {
+ public static void Main()
+ {
+ LmIpcServer ipcServer = new LmIpcServer();
+
+ ipcServer.Initialize();
+ ipcServer.ServiceRequests();
+ ipcServer.Shutdown();
+ }
+ }
+}
diff --git a/Ryujinx.Horizon/Ryujinx.Horizon.csproj b/Ryujinx.Horizon/Ryujinx.Horizon.csproj
new file mode 100644
index 00000000..e4591c6f
--- /dev/null
+++ b/Ryujinx.Horizon/Ryujinx.Horizon.csproj
@@ -0,0 +1,14 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+ <PropertyGroup>
+ <TargetFramework>net7.0</TargetFramework>
+ </PropertyGroup>
+
+ <ItemGroup>
+ <ProjectReference Include="..\Ryujinx.Common\Ryujinx.Common.csproj" />
+ <ProjectReference Include="..\Ryujinx.Horizon.Common\Ryujinx.Horizon.Common.csproj" />
+ <ProjectReference Include="..\Ryujinx.Horizon.Generators\Ryujinx.Horizon.Generators.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
+ <ProjectReference Include="..\Ryujinx.Memory\Ryujinx.Memory.csproj" />
+ </ItemGroup>
+
+</Project>
diff --git a/Ryujinx.Horizon/Sdk/DebugUtil.cs b/Ryujinx.Horizon/Sdk/DebugUtil.cs
new file mode 100644
index 00000000..f56a50ec
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/DebugUtil.cs
@@ -0,0 +1,12 @@
+using System.Diagnostics;
+
+namespace Ryujinx.Horizon.Sdk
+{
+ static class DebugUtil
+ {
+ public static void Assert(bool condition)
+ {
+ Debug.Assert(condition);
+ }
+ }
+}
diff --git a/Ryujinx.Horizon/Sdk/Diag/LogSeverity.cs b/Ryujinx.Horizon/Sdk/Diag/LogSeverity.cs
new file mode 100644
index 00000000..72acf789
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Diag/LogSeverity.cs
@@ -0,0 +1,11 @@
+namespace Ryujinx.Horizon.Sdk.Diag
+{
+ enum LogSeverity : byte
+ {
+ Trace = 0,
+ Info = 1,
+ Warn = 2,
+ Error = 3,
+ Fatal = 4
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Horizon/Sdk/Lm/LogDataChunkKey.cs b/Ryujinx.Horizon/Sdk/Lm/LogDataChunkKey.cs
new file mode 100644
index 00000000..90756ece
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Lm/LogDataChunkKey.cs
@@ -0,0 +1,19 @@
+namespace Ryujinx.Horizon.Sdk.Lm
+{
+ enum LogDataChunkKey
+ {
+ Start = 0,
+ Stop = 1,
+ Message = 2,
+ Line = 3,
+ Filename = 4,
+ Function = 5,
+ Module = 6,
+ Thread = 7,
+ DropCount = 8,
+ Time = 9,
+ ProgramName = 10,
+
+ Count
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Horizon/Sdk/Lm/LogDestination.cs b/Ryujinx.Horizon/Sdk/Lm/LogDestination.cs
new file mode 100644
index 00000000..8b08548d
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Lm/LogDestination.cs
@@ -0,0 +1,14 @@
+using System;
+
+namespace Ryujinx.Horizon.Sdk.Lm
+{
+ [Flags]
+ enum LogDestination
+ {
+ TargetManager = 1 << 0,
+ Uart = 1 << 1,
+ UartIfSleep = 1 << 2,
+
+ All = 0xffff
+ }
+}
diff --git a/Ryujinx.Horizon/Sdk/Lm/LogPacketFlags.cs b/Ryujinx.Horizon/Sdk/Lm/LogPacketFlags.cs
new file mode 100644
index 00000000..75d9f40b
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Lm/LogPacketFlags.cs
@@ -0,0 +1,12 @@
+using System;
+
+namespace Ryujinx.Horizon.Sdk.Lm
+{
+ [Flags]
+ enum LogPacketFlags : byte
+ {
+ IsHead = 1 << 0,
+ IsTail = 1 << 1,
+ IsLittleEndian = 1 << 2
+ }
+}
diff --git a/Ryujinx.Horizon/Sdk/Lm/LogPacketHeader.cs b/Ryujinx.Horizon/Sdk/Lm/LogPacketHeader.cs
new file mode 100644
index 00000000..022ba8da
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Lm/LogPacketHeader.cs
@@ -0,0 +1,15 @@
+using Ryujinx.Horizon.Sdk.Diag;
+
+namespace Ryujinx.Horizon.Sdk.Lm
+{
+ struct LogPacketHeader
+ {
+ public ulong ProcessId;
+ public ulong ThreadId;
+ public LogPacketFlags Flags;
+ public byte Padding;
+ public LogSeverity Severity;
+ public byte Verbosity;
+ public uint PayloadSize;
+ }
+}
diff --git a/Ryujinx.Horizon/Sdk/OsTypes/Event.cs b/Ryujinx.Horizon/Sdk/OsTypes/Event.cs
new file mode 100644
index 00000000..79d7408e
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/OsTypes/Event.cs
@@ -0,0 +1,61 @@
+using System;
+using System.Collections.Generic;
+
+namespace Ryujinx.Horizon.Sdk.OsTypes
+{
+ class Event : IDisposable
+ {
+ private EventType _event;
+
+ public object EventLock => _event.Lock;
+ public LinkedList<MultiWaitHolderBase> MultiWaitHolders => _event.MultiWaitHolders;
+
+ public Event(EventClearMode clearMode)
+ {
+ Os.InitializeEvent(out _event, signaled: false, clearMode);
+ }
+
+ public TriBool IsSignaledThreadUnsafe()
+ {
+ return _event.Signaled ? TriBool.True : TriBool.False;
+ }
+
+ public void Wait()
+ {
+ Os.WaitEvent(ref _event);
+ }
+
+ public bool TryWait()
+ {
+ return Os.TryWaitEvent(ref _event);
+ }
+
+ public bool TimedWait(TimeSpan timeout)
+ {
+ return Os.TimedWaitEvent(ref _event, timeout);
+ }
+
+ public void Signal()
+ {
+ Os.SignalEvent(ref _event);
+ }
+
+ public void Clear()
+ {
+ Os.ClearEvent(ref _event);
+ }
+
+ protected virtual void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ Os.FinalizeEvent(ref _event);
+ }
+ }
+
+ public void Dispose()
+ {
+ Dispose(true);
+ }
+ }
+}
diff --git a/Ryujinx.Horizon/Sdk/OsTypes/EventClearMode.cs b/Ryujinx.Horizon/Sdk/OsTypes/EventClearMode.cs
new file mode 100644
index 00000000..b500e6b3
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/OsTypes/EventClearMode.cs
@@ -0,0 +1,8 @@
+namespace Ryujinx.Horizon.Sdk.OsTypes
+{
+ enum EventClearMode
+ {
+ ManualClear,
+ AutoClear
+ }
+}
diff --git a/Ryujinx.Horizon/Sdk/OsTypes/EventType.cs b/Ryujinx.Horizon/Sdk/OsTypes/EventType.cs
new file mode 100644
index 00000000..b4b1a275
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/OsTypes/EventType.cs
@@ -0,0 +1,15 @@
+using System.Collections.Generic;
+
+namespace Ryujinx.Horizon.Sdk.OsTypes
+{
+ struct EventType
+ {
+ public LinkedList<MultiWaitHolderBase> MultiWaitHolders;
+ public bool Signaled;
+ public bool InitiallySignaled;
+ public EventClearMode ClearMode;
+ public InitializationState State;
+ public ulong BroadcastCounter;
+ public object Lock;
+ }
+}
diff --git a/Ryujinx.Horizon/Sdk/OsTypes/Impl/InterProcessEvent.cs b/Ryujinx.Horizon/Sdk/OsTypes/Impl/InterProcessEvent.cs
new file mode 100644
index 00000000..62b5bf06
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/OsTypes/Impl/InterProcessEvent.cs
@@ -0,0 +1,89 @@
+using Ryujinx.Horizon.Common;
+
+namespace Ryujinx.Horizon.Sdk.OsTypes.Impl
+{
+ static class InterProcessEvent
+ {
+ public static Result Create(ref InterProcessEventType ipEvent, EventClearMode clearMode)
+ {
+ Result result = InterProcessEventImpl.Create(out int writableHandle, out int readableHandle);
+
+ if (result != Result.Success)
+ {
+ return result;
+ }
+
+ ipEvent = new InterProcessEventType(
+ clearMode == EventClearMode.AutoClear,
+ true,
+ true,
+ readableHandle,
+ writableHandle);
+
+ return Result.Success;
+ }
+
+ public static void Destroy(ref InterProcessEventType ipEvent)
+ {
+ ipEvent.State = InitializationState.NotInitialized;
+
+ if (ipEvent.ReadableHandleManaged)
+ {
+ if (ipEvent.ReadableHandle != 0)
+ {
+ InterProcessEventImpl.Close(ipEvent.ReadableHandle);
+ }
+ ipEvent.ReadableHandleManaged = false;
+ }
+
+ if (ipEvent.WritableHandleManaged)
+ {
+ if (ipEvent.WritableHandle != 0)
+ {
+ InterProcessEventImpl.Close(ipEvent.WritableHandle);
+ }
+ ipEvent.WritableHandleManaged = false;
+ }
+ }
+
+ public static int DetachReadableHandle(ref InterProcessEventType ipEvent)
+ {
+ int handle = ipEvent.ReadableHandle;
+
+ ipEvent.ReadableHandle = 0;
+ ipEvent.ReadableHandleManaged = false;
+
+ return handle;
+ }
+
+ public static int DetachWritableHandle(ref InterProcessEventType ipEvent)
+ {
+ int handle = ipEvent.WritableHandle;
+
+ ipEvent.WritableHandle = 0;
+ ipEvent.WritableHandleManaged = false;
+
+ return handle;
+ }
+
+ public static int GetReadableHandle(ref InterProcessEventType ipEvent)
+ {
+ return ipEvent.ReadableHandle;
+ }
+
+ public static int GetWritableHandle(ref InterProcessEventType ipEvent)
+ {
+ return ipEvent.WritableHandle;
+ }
+
+ public static void Signal(ref InterProcessEventType ipEvent)
+ {
+ InterProcessEventImpl.Signal(ipEvent.WritableHandle);
+ }
+
+ public static void Clear(ref InterProcessEventType ipEvent)
+ {
+ InterProcessEventImpl.Clear(ipEvent.ReadableHandle == 0 ? ipEvent.WritableHandle : ipEvent.ReadableHandle);
+ }
+ }
+}
diff --git a/Ryujinx.Horizon/Sdk/OsTypes/Impl/InterProcessEventImpl.cs b/Ryujinx.Horizon/Sdk/OsTypes/Impl/InterProcessEventImpl.cs
new file mode 100644
index 00000000..a8aeacc9
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/OsTypes/Impl/InterProcessEventImpl.cs
@@ -0,0 +1,136 @@
+using Ryujinx.Horizon.Common;
+using System;
+
+namespace Ryujinx.Horizon.Sdk.OsTypes.Impl
+{
+ static class InterProcessEventImpl
+ {
+ public static Result Create(out int writableHandle, out int readableHandle)
+ {
+ Result result = HorizonStatic.Syscall.CreateEvent(out writableHandle, out readableHandle);
+
+ if (result == KernelResult.OutOfResource)
+ {
+ return OsResult.OutOfResource;
+ }
+
+ result.AbortOnFailure();
+
+ return Result.Success;
+ }
+
+ public static void Close(int handle)
+ {
+ if (handle != 0)
+ {
+ HorizonStatic.Syscall.CloseHandle(handle).AbortOnFailure();
+ }
+ }
+
+ public static void Signal(int handle)
+ {
+ HorizonStatic.Syscall.SignalEvent(handle).AbortOnFailure();
+ }
+
+ public static void Clear(int handle)
+ {
+ HorizonStatic.Syscall.ClearEvent(handle).AbortOnFailure();
+ }
+
+ public static void Wait(int handle, bool autoClear)
+ {
+ Span<int> handles = stackalloc int[1];
+
+ handles[0] = handle;
+
+ while (true)
+ {
+ Result result = HorizonStatic.Syscall.WaitSynchronization(out _, handles, -1L);
+
+ if (result == Result.Success)
+ {
+ if (autoClear)
+ {
+ result = HorizonStatic.Syscall.ResetSignal(handle);
+
+ if (result == KernelResult.InvalidState)
+ {
+ continue;
+ }
+
+ result.AbortOnFailure();
+ }
+
+ return;
+ }
+
+ result.AbortUnless(KernelResult.Cancelled);
+ }
+ }
+
+ public static bool TryWait(int handle, bool autoClear)
+ {
+ if (autoClear)
+ {
+ return HorizonStatic.Syscall.ResetSignal(handle) == Result.Success;
+ }
+
+ Span<int> handles = stackalloc int[1];
+
+ handles[0] = handle;
+
+ while (true)
+ {
+ Result result = HorizonStatic.Syscall.WaitSynchronization(out _, handles, 0);
+
+ if (result == Result.Success)
+ {
+ return true;
+ }
+ else if (result == KernelResult.TimedOut)
+ {
+ return false;
+ }
+
+ result.AbortUnless(KernelResult.Cancelled);
+ }
+ }
+
+ public static bool TimedWait(int handle, bool autoClear, TimeSpan timeout)
+ {
+ Span<int> handles = stackalloc int[1];
+
+ handles[0] = handle;
+
+ long timeoutNs = timeout.Milliseconds * 1000000L;
+
+ while (true)
+ {
+ Result result = HorizonStatic.Syscall.WaitSynchronization(out _, handles, timeoutNs);
+
+ if (result == Result.Success)
+ {
+ if (autoClear)
+ {
+ result = HorizonStatic.Syscall.ResetSignal(handle);
+
+ if (result == KernelResult.InvalidState)
+ {
+ continue;
+ }
+
+ result.AbortOnFailure();
+ }
+
+ return true;
+ }
+ else if (result == KernelResult.TimedOut)
+ {
+ return false;
+ }
+
+ result.AbortUnless(KernelResult.Cancelled);
+ }
+ }
+ }
+}
diff --git a/Ryujinx.Horizon/Sdk/OsTypes/Impl/MultiWaitImpl.cs b/Ryujinx.Horizon/Sdk/OsTypes/Impl/MultiWaitImpl.cs
new file mode 100644
index 00000000..fd45792d
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/OsTypes/Impl/MultiWaitImpl.cs
@@ -0,0 +1,250 @@
+using Ryujinx.Common;
+using Ryujinx.Horizon.Common;
+using System.Collections.Generic;
+using System;
+
+namespace Ryujinx.Horizon.Sdk.OsTypes.Impl
+{
+ class MultiWaitImpl
+ {
+ private const int WaitTimedOut = -1;
+ private const int WaitCancelled = -2;
+ private const int WaitInvalid = -3;
+
+ private readonly List<MultiWaitHolderBase> _multiWaits;
+
+ private object _lock;
+
+ private int _waitingThreadHandle;
+
+ private MultiWaitHolderBase _signaledHolder;
+
+ public long CurrentTime { get; private set; }
+
+ public MultiWaitImpl()
+ {
+ _multiWaits = new List<MultiWaitHolderBase>();
+
+ _lock = new object();
+ }
+
+ public void LinkMultiWaitHolder(MultiWaitHolderBase multiWaitHolder)
+ {
+ _multiWaits.Add(multiWaitHolder);
+ }
+
+ public void UnlinkMultiWaitHolder(MultiWaitHolderBase multiWaitHolder)
+ {
+ _multiWaits.Remove(multiWaitHolder);
+ }
+
+ public void MoveAllFrom(MultiWaitImpl other)
+ {
+ foreach (MultiWaitHolderBase multiWait in other._multiWaits)
+ {
+ multiWait.SetMultiWait(this);
+ }
+
+ _multiWaits.AddRange(other._multiWaits);
+
+ other._multiWaits.Clear();
+ }
+
+ public MultiWaitHolderBase WaitAnyImpl(bool infinite, long timeout)
+ {
+ _signaledHolder = null;
+ _waitingThreadHandle = Os.GetCurrentThreadHandle();
+
+ MultiWaitHolderBase result = LinkHoldersToObjectList();
+
+ lock (_lock)
+ {
+ if (_signaledHolder != null)
+ {
+ result = _signaledHolder;
+ }
+ }
+
+ if (result == null)
+ {
+ result = WaitAnyHandleImpl(infinite, timeout);
+ }
+
+ UnlinkHoldersFromObjectsList();
+ _waitingThreadHandle = 0;
+
+ return result;
+ }
+
+ private MultiWaitHolderBase WaitAnyHandleImpl(bool infinite, long timeout)
+ {
+ Span<int> objectHandles = new int[64];
+
+ Span<MultiWaitHolderBase> objects = new MultiWaitHolderBase[64];
+
+ int count = FillObjectsArray(objectHandles, objects);
+
+ long endTime = infinite ? long.MaxValue : PerformanceCounter.ElapsedMilliseconds * 1000000;
+
+ while (true)
+ {
+ CurrentTime = PerformanceCounter.ElapsedMilliseconds * 1000000;
+
+ MultiWaitHolderBase minTimeoutObject = RecalcMultiWaitTimeout(endTime, out long minTimeout);
+
+ int index;
+
+ if (count == 0 && minTimeout == 0)
+ {
+ index = WaitTimedOut;
+ }
+ else
+ {
+ index = WaitSynchronization(objectHandles.Slice(0, count), minTimeout);
+
+ DebugUtil.Assert(index != WaitInvalid);
+ }
+
+ switch (index)
+ {
+ case WaitTimedOut:
+ if (minTimeoutObject != null)
+ {
+ CurrentTime = PerformanceCounter.ElapsedMilliseconds * 1000000;
+
+ if (minTimeoutObject.Signaled == TriBool.True)
+ {
+ lock (_lock)
+ {
+ _signaledHolder = minTimeoutObject;
+
+ return _signaledHolder;
+ }
+ }
+ }
+ else
+ {
+ return null;
+ }
+ break;
+ case WaitCancelled:
+ lock (_lock)
+ {
+ if (_signaledHolder != null)
+ {
+ return _signaledHolder;
+ }
+ }
+ break;
+ default:
+ lock (_lock)
+ {
+ _signaledHolder = objects[index];
+
+ return _signaledHolder;
+ }
+ }
+ }
+ }
+
+ private int FillObjectsArray(Span<int> handles, Span<MultiWaitHolderBase> objects)
+ {
+ int count = 0;
+
+ foreach (MultiWaitHolderBase holder in _multiWaits)
+ {
+ int handle = holder.Handle;
+
+ if (handle != 0)
+ {
+ handles[count] = handle;
+ objects[count] = holder;
+
+ count++;
+ }
+ }
+
+ return count;
+ }
+
+ private MultiWaitHolderBase RecalcMultiWaitTimeout(long endTime, out long minTimeout)
+ {
+ MultiWaitHolderBase minTimeHolder = null;
+
+ long minTime = endTime;
+
+ foreach (MultiWaitHolder holder in _multiWaits)
+ {
+ long currentTime = holder.GetAbsoluteTimeToWakeup();
+
+ if ((ulong)currentTime < (ulong)minTime)
+ {
+ minTimeHolder = holder;
+
+ minTime = currentTime;
+ }
+ }
+
+ minTimeout = (ulong)minTime < (ulong)CurrentTime ? 0 : minTime - CurrentTime;
+
+ return minTimeHolder;
+ }
+
+ private static int WaitSynchronization(ReadOnlySpan<int> handles, long timeout)
+ {
+ Result result = HorizonStatic.Syscall.WaitSynchronization(out int index, handles, timeout);
+
+ if (result == KernelResult.TimedOut)
+ {
+ return WaitTimedOut;
+ }
+ else if (result == KernelResult.Cancelled)
+ {
+ return WaitCancelled;
+ }
+ else
+ {
+ result.AbortOnFailure();
+ }
+
+ return index;
+ }
+
+ public void NotifyAndWakeUpThread(MultiWaitHolderBase holder)
+ {
+ lock (_lock)
+ {
+ if (_signaledHolder == null)
+ {
+ _signaledHolder = holder;
+ HorizonStatic.Syscall.CancelSynchronization(_waitingThreadHandle).AbortOnFailure();
+ }
+ }
+ }
+
+ private MultiWaitHolderBase LinkHoldersToObjectList()
+ {
+ MultiWaitHolderBase signaledHolder = null;
+
+ foreach (MultiWaitHolderBase holder in _multiWaits)
+ {
+ TriBool isSignaled = holder.LinkToObjectList();
+
+ if (signaledHolder == null && isSignaled == TriBool.True)
+ {
+ signaledHolder = holder;
+ }
+ }
+
+ return signaledHolder;
+ }
+
+ private void UnlinkHoldersFromObjectsList()
+ {
+ foreach (MultiWaitHolderBase holder in _multiWaits)
+ {
+ holder.UnlinkFromObjectList();
+ }
+ }
+ }
+}
diff --git a/Ryujinx.Horizon/Sdk/OsTypes/InitializationState.cs b/Ryujinx.Horizon/Sdk/OsTypes/InitializationState.cs
new file mode 100644
index 00000000..45ffd258
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/OsTypes/InitializationState.cs
@@ -0,0 +1,8 @@
+namespace Ryujinx.Horizon.Sdk.OsTypes
+{
+ enum InitializationState : byte
+ {
+ NotInitialized,
+ Initialized
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Horizon/Sdk/OsTypes/InterProcessEventType.cs b/Ryujinx.Horizon/Sdk/OsTypes/InterProcessEventType.cs
new file mode 100644
index 00000000..5f6824fe
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/OsTypes/InterProcessEventType.cs
@@ -0,0 +1,27 @@
+namespace Ryujinx.Horizon.Sdk.OsTypes
+{
+ struct InterProcessEventType
+ {
+ public readonly bool AutoClear;
+ public InitializationState State;
+ public bool ReadableHandleManaged;
+ public bool WritableHandleManaged;
+ public int ReadableHandle;
+ public int WritableHandle;
+
+ public InterProcessEventType(
+ bool autoClear,
+ bool readableHandleManaged,
+ bool writableHandleManaged,
+ int readableHandle,
+ int writableHandle)
+ {
+ AutoClear = autoClear;
+ State = InitializationState.Initialized;
+ ReadableHandleManaged = readableHandleManaged;
+ WritableHandleManaged = writableHandleManaged;
+ ReadableHandle = readableHandle;
+ WritableHandle = writableHandle;
+ }
+ }
+}
diff --git a/Ryujinx.Horizon/Sdk/OsTypes/MultiWait.cs b/Ryujinx.Horizon/Sdk/OsTypes/MultiWait.cs
new file mode 100644
index 00000000..5a91f6c3
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/OsTypes/MultiWait.cs
@@ -0,0 +1,43 @@
+using Ryujinx.Horizon.Sdk.OsTypes.Impl;
+
+namespace Ryujinx.Horizon.Sdk.OsTypes
+{
+ class MultiWait
+ {
+ private readonly MultiWaitImpl _impl;
+
+ public MultiWait()
+ {
+ _impl = new MultiWaitImpl();
+ }
+
+ public void LinkMultiWaitHolder(MultiWaitHolderBase multiWaitHolder)
+ {
+ DebugUtil.Assert(!multiWaitHolder.IsLinked);
+
+ _impl.LinkMultiWaitHolder(multiWaitHolder);
+
+ multiWaitHolder.SetMultiWait(_impl);
+ }
+
+ public void MoveAllFrom(MultiWait other)
+ {
+ _impl.MoveAllFrom(other._impl);
+ }
+
+ public MultiWaitHolder WaitAny()
+ {
+ return (MultiWaitHolder)_impl.WaitAnyImpl(true, -1L);
+ }
+
+ public MultiWaitHolder TryWaitAny()
+ {
+ return (MultiWaitHolder)_impl.WaitAnyImpl(false, 0);
+ }
+
+ public MultiWaitHolder TimedWaitAny(long timeout)
+ {
+ return (MultiWaitHolder)_impl.WaitAnyImpl(false, timeout);
+ }
+ }
+}
diff --git a/Ryujinx.Horizon/Sdk/OsTypes/MultiWaitHolder.cs b/Ryujinx.Horizon/Sdk/OsTypes/MultiWaitHolder.cs
new file mode 100644
index 00000000..a24b1906
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/OsTypes/MultiWaitHolder.cs
@@ -0,0 +1,16 @@
+namespace Ryujinx.Horizon.Sdk.OsTypes
+{
+ class MultiWaitHolder : MultiWaitHolderBase
+ {
+ public object UserData { get; set; }
+
+ public void UnlinkFromMultiWaitHolder()
+ {
+ DebugUtil.Assert(IsLinked);
+
+ MultiWait.UnlinkMultiWaitHolder(this);
+
+ SetMultiWait(null);
+ }
+ }
+}
diff --git a/Ryujinx.Horizon/Sdk/OsTypes/MultiWaitHolderBase.cs b/Ryujinx.Horizon/Sdk/OsTypes/MultiWaitHolderBase.cs
new file mode 100644
index 00000000..018305ba
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/OsTypes/MultiWaitHolderBase.cs
@@ -0,0 +1,39 @@
+using Ryujinx.Horizon.Sdk.OsTypes.Impl;
+
+namespace Ryujinx.Horizon.Sdk.OsTypes
+{
+ class MultiWaitHolderBase
+ {
+ protected MultiWaitImpl MultiWait;
+
+ public bool IsLinked => MultiWait != null;
+
+ public virtual TriBool Signaled => TriBool.False;
+
+ public virtual int Handle => 0;
+
+ public void SetMultiWait(MultiWaitImpl multiWait)
+ {
+ MultiWait = multiWait;
+ }
+
+ public MultiWaitImpl GetMultiWait()
+ {
+ return MultiWait;
+ }
+
+ public virtual TriBool LinkToObjectList()
+ {
+ return TriBool.Undefined;
+ }
+
+ public virtual void UnlinkFromObjectList()
+ {
+ }
+
+ public virtual long GetAbsoluteTimeToWakeup()
+ {
+ return long.MaxValue;
+ }
+ }
+}
diff --git a/Ryujinx.Horizon/Sdk/OsTypes/MultiWaitHolderOfEvent.cs b/Ryujinx.Horizon/Sdk/OsTypes/MultiWaitHolderOfEvent.cs
new file mode 100644
index 00000000..37ac22f0
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/OsTypes/MultiWaitHolderOfEvent.cs
@@ -0,0 +1,45 @@
+using System.Collections.Generic;
+
+namespace Ryujinx.Horizon.Sdk.OsTypes
+{
+ class MultiWaitHolderOfEvent : MultiWaitHolder
+ {
+ private Event _event;
+ private LinkedListNode<MultiWaitHolderBase> _node;
+
+ public override TriBool Signaled
+ {
+ get
+ {
+ lock (_event.EventLock)
+ {
+ return _event.IsSignaledThreadUnsafe();
+ }
+ }
+ }
+
+ public MultiWaitHolderOfEvent(Event evnt)
+ {
+ _event = evnt;
+ }
+
+ public override TriBool LinkToObjectList()
+ {
+ lock (_event.EventLock)
+ {
+ _node = _event.MultiWaitHolders.AddLast(this);
+
+ return _event.IsSignaledThreadUnsafe();
+ }
+ }
+
+ public override void UnlinkFromObjectList()
+ {
+ lock (_event.EventLock)
+ {
+ _event.MultiWaitHolders.Remove(_node);
+ _node = null;
+ }
+ }
+ }
+}
diff --git a/Ryujinx.Horizon/Sdk/OsTypes/MultiWaitHolderOfHandle.cs b/Ryujinx.Horizon/Sdk/OsTypes/MultiWaitHolderOfHandle.cs
new file mode 100644
index 00000000..6fc5c75b
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/OsTypes/MultiWaitHolderOfHandle.cs
@@ -0,0 +1,14 @@
+namespace Ryujinx.Horizon.Sdk.OsTypes
+{
+ class MultiWaitHolderOfHandle : MultiWaitHolder
+ {
+ private int _handle;
+
+ public override int Handle => _handle;
+
+ public MultiWaitHolderOfHandle(int handle)
+ {
+ _handle = handle;
+ }
+ }
+}
diff --git a/Ryujinx.Horizon/Sdk/OsTypes/OsEvent.cs b/Ryujinx.Horizon/Sdk/OsTypes/OsEvent.cs
new file mode 100644
index 00000000..cc7e8483
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/OsTypes/OsEvent.cs
@@ -0,0 +1,130 @@
+using System;
+using System.Collections.Generic;
+using System.Threading;
+
+namespace Ryujinx.Horizon.Sdk.OsTypes
+{
+ static partial class Os
+ {
+ public static void InitializeEvent(out EventType evnt, bool signaled, EventClearMode clearMode)
+ {
+ evnt = new EventType
+ {
+ MultiWaitHolders = new LinkedList<MultiWaitHolderBase>(),
+ Signaled = signaled,
+ InitiallySignaled = signaled,
+ ClearMode = clearMode,
+ State = InitializationState.Initialized,
+ Lock = new object()
+ };
+ }
+
+ public static void FinalizeEvent(ref EventType evnt)
+ {
+ evnt.State = InitializationState.NotInitialized;
+ }
+
+ public static void WaitEvent(ref EventType evnt)
+ {
+ lock (evnt.Lock)
+ {
+ ulong currentCounter = evnt.BroadcastCounter;
+
+ while (!evnt.Signaled)
+ {
+ if (currentCounter != evnt.BroadcastCounter)
+ {
+ break;
+ }
+
+ Monitor.Wait(evnt.Lock);
+ }
+
+ if (evnt.ClearMode == EventClearMode.AutoClear)
+ {
+ evnt.Signaled = false;
+ }
+ }
+ }
+
+ public static bool TryWaitEvent(ref EventType evnt)
+ {
+ lock (evnt.Lock)
+ {
+ bool signaled = evnt.Signaled;
+
+ if (evnt.ClearMode == EventClearMode.AutoClear)
+ {
+ evnt.Signaled = false;
+ }
+
+ return signaled;
+ }
+ }
+
+ public static bool TimedWaitEvent(ref EventType evnt, TimeSpan timeout)
+ {
+ lock (evnt.Lock)
+ {
+ ulong currentCounter = evnt.BroadcastCounter;
+
+ while (!evnt.Signaled)
+ {
+ if (currentCounter != evnt.BroadcastCounter)
+ {
+ break;
+ }
+
+ bool wasSignaledInTime = Monitor.Wait(evnt.Lock, timeout);
+ if (!wasSignaledInTime)
+ {
+ return false;
+ }
+ }
+
+ if (evnt.ClearMode == EventClearMode.AutoClear)
+ {
+ evnt.Signaled = false;
+ }
+ }
+
+ return true;
+ }
+
+ public static void SignalEvent(ref EventType evnt)
+ {
+ lock (evnt.Lock)
+ {
+ if (evnt.Signaled)
+ {
+ return;
+ }
+
+ evnt.Signaled = true;
+
+ if (evnt.ClearMode == EventClearMode.ManualClear)
+ {
+ evnt.BroadcastCounter++;
+ Monitor.PulseAll(evnt.Lock);
+ }
+ else
+ {
+ Monitor.Pulse(evnt.Lock);
+ }
+
+ foreach (MultiWaitHolderBase holder in evnt.MultiWaitHolders)
+ {
+ holder.GetMultiWait().NotifyAndWakeUpThread(holder);
+ }
+ }
+ }
+
+ public static void ClearEvent(ref EventType evnt)
+ {
+ lock (evnt.Lock)
+ {
+ evnt.Signaled = false;
+ }
+ }
+ }
+}
diff --git a/Ryujinx.Horizon/Sdk/OsTypes/OsMultiWait.cs b/Ryujinx.Horizon/Sdk/OsTypes/OsMultiWait.cs
new file mode 100644
index 00000000..827de231
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/OsTypes/OsMultiWait.cs
@@ -0,0 +1,10 @@
+namespace Ryujinx.Horizon.Sdk.OsTypes
+{
+ static partial class Os
+ {
+ public static void FinalizeMultiWaitHolder(MultiWaitHolderBase holder)
+ {
+ DebugUtil.Assert(!holder.IsLinked);
+ }
+ }
+}
diff --git a/Ryujinx.Horizon/Sdk/OsTypes/OsProcessHandle.cs b/Ryujinx.Horizon/Sdk/OsTypes/OsProcessHandle.cs
new file mode 100644
index 00000000..6a6d9bf2
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/OsTypes/OsProcessHandle.cs
@@ -0,0 +1,33 @@
+using Ryujinx.Horizon.Common;
+
+namespace Ryujinx.Horizon.Sdk.OsTypes
+{
+ static partial class Os
+ {
+ private const int SelfProcessHandle = (0x1ffff << 15) | 1;
+
+ public static int GetCurrentProcessHandle()
+ {
+ return SelfProcessHandle;
+ }
+
+ public static ulong GetCurrentProcessId()
+ {
+ return GetProcessId(GetCurrentProcessHandle());
+ }
+
+ private static ulong GetProcessId(int handle)
+ {
+ Result result = TryGetProcessId(handle, out ulong pid);
+
+ result.AbortOnFailure();
+
+ return pid;
+ }
+
+ private static Result TryGetProcessId(int handle, out ulong pid)
+ {
+ return HorizonStatic.Syscall.GetProcessId(out pid, handle);
+ }
+ }
+}
diff --git a/Ryujinx.Horizon/Sdk/OsTypes/OsResult.cs b/Ryujinx.Horizon/Sdk/OsTypes/OsResult.cs
new file mode 100644
index 00000000..86dcd1fa
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/OsTypes/OsResult.cs
@@ -0,0 +1,11 @@
+using Ryujinx.Horizon.Common;
+
+namespace Ryujinx.Horizon.Sdk.OsTypes
+{
+ static class OsResult
+ {
+ private const int ModuleId = 3;
+
+ public static Result OutOfResource => new Result(ModuleId, 9);
+ }
+}
diff --git a/Ryujinx.Horizon/Sdk/OsTypes/OsSystemEvent.cs b/Ryujinx.Horizon/Sdk/OsTypes/OsSystemEvent.cs
new file mode 100644
index 00000000..061d7a3c
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/OsTypes/OsSystemEvent.cs
@@ -0,0 +1,85 @@
+using Ryujinx.Horizon.Sdk.OsTypes.Impl;
+using Ryujinx.Horizon.Common;
+using System;
+
+namespace Ryujinx.Horizon.Sdk.OsTypes
+{
+ static partial class Os
+ {
+ public static Result CreateSystemEvent(out SystemEventType sysEvent, EventClearMode clearMode, bool interProcess)
+ {
+ sysEvent = new SystemEventType();
+
+ if (interProcess)
+ {
+ Result result = InterProcessEvent.Create(ref sysEvent.InterProcessEvent, clearMode);
+
+ if (result != Result.Success)
+ {
+ return result;
+ }
+
+ sysEvent.State = SystemEventType.InitializationState.InitializedAsInterProcess;
+ }
+ else
+ {
+ throw new NotImplementedException();
+ }
+
+ return Result.Success;
+ }
+
+ public static void DestroySystemEvent(ref SystemEventType sysEvent)
+ {
+ var oldState = sysEvent.State;
+ sysEvent.State = SystemEventType.InitializationState.NotInitialized;
+
+ switch (oldState)
+ {
+ case SystemEventType.InitializationState.InitializedAsInterProcess:
+ InterProcessEvent.Destroy(ref sysEvent.InterProcessEvent);
+ break;
+ }
+ }
+
+ public static int DetachReadableHandleOfSystemEvent(ref SystemEventType sysEvent)
+ {
+ return InterProcessEvent.DetachReadableHandle(ref sysEvent.InterProcessEvent);
+ }
+
+ public static int DetachWritableHandleOfSystemEvent(ref SystemEventType sysEvent)
+ {
+ return InterProcessEvent.DetachWritableHandle(ref sysEvent.InterProcessEvent);
+ }
+
+ public static int GetReadableHandleOfSystemEvent(ref SystemEventType sysEvent)
+ {
+ return InterProcessEvent.GetReadableHandle(ref sysEvent.InterProcessEvent);
+ }
+
+ public static int GetWritableHandleOfSystemEvent(ref SystemEventType sysEvent)
+ {
+ return InterProcessEvent.GetWritableHandle(ref sysEvent.InterProcessEvent);
+ }
+
+ public static void SignalSystemEvent(ref SystemEventType sysEvent)
+ {
+ switch (sysEvent.State)
+ {
+ case SystemEventType.InitializationState.InitializedAsInterProcess:
+ InterProcessEvent.Signal(ref sysEvent.InterProcessEvent);
+ break;
+ }
+ }
+
+ public static void ClearSystemEvent(ref SystemEventType sysEvent)
+ {
+ switch (sysEvent.State)
+ {
+ case SystemEventType.InitializationState.InitializedAsInterProcess:
+ InterProcessEvent.Clear(ref sysEvent.InterProcessEvent);
+ break;
+ }
+ }
+ }
+}
diff --git a/Ryujinx.Horizon/Sdk/OsTypes/OsThreadManager.cs b/Ryujinx.Horizon/Sdk/OsTypes/OsThreadManager.cs
new file mode 100644
index 00000000..2037cd7f
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/OsTypes/OsThreadManager.cs
@@ -0,0 +1,10 @@
+namespace Ryujinx.Horizon.Sdk.OsTypes
+{
+ static partial class Os
+ {
+ public static int GetCurrentThreadHandle()
+ {
+ return HorizonStatic.CurrentThreadHandle;
+ }
+ }
+}
diff --git a/Ryujinx.Horizon/Sdk/OsTypes/SystemEventType.cs b/Ryujinx.Horizon/Sdk/OsTypes/SystemEventType.cs
new file mode 100644
index 00000000..338493d2
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/OsTypes/SystemEventType.cs
@@ -0,0 +1,17 @@
+namespace Ryujinx.Horizon.Sdk.OsTypes
+{
+ struct SystemEventType
+ {
+ public enum InitializationState : byte
+ {
+ NotInitialized,
+ InitializedAsEvent,
+ InitializedAsInterProcess
+ }
+
+ public InterProcessEventType InterProcessEvent;
+ public InitializationState State;
+
+ public bool NotInitialized => State == InitializationState.NotInitialized;
+ }
+}
diff --git a/Ryujinx.Horizon/Sdk/OsTypes/TriBool.cs b/Ryujinx.Horizon/Sdk/OsTypes/TriBool.cs
new file mode 100644
index 00000000..7debd9e2
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/OsTypes/TriBool.cs
@@ -0,0 +1,9 @@
+namespace Ryujinx.Horizon.Sdk.OsTypes
+{
+ enum TriBool
+ {
+ False,
+ True,
+ Undefined
+ }
+}
diff --git a/Ryujinx.Horizon/Sdk/ServiceUtil.cs b/Ryujinx.Horizon/Sdk/ServiceUtil.cs
new file mode 100644
index 00000000..413ac1f6
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/ServiceUtil.cs
@@ -0,0 +1,38 @@
+using Ryujinx.Horizon.Common;
+using Ryujinx.Horizon.Sdk.Sf.Cmif;
+using Ryujinx.Horizon.Sdk.Sf.Hipc;
+using System;
+
+namespace Ryujinx.Horizon.Sdk
+{
+ static class ServiceUtil
+ {
+ public static Result SendRequest(out CmifResponse response, int sessionHandle, uint requestId, bool sendPid, scoped ReadOnlySpan<byte> data)
+ {
+ ulong tlsAddress = HorizonStatic.ThreadContext.TlsAddress;
+ int tlsSize = Api.TlsMessageBufferSize;
+
+ using (var tlsRegion = HorizonStatic.AddressSpace.GetWritableRegion(tlsAddress, tlsSize))
+ {
+ CmifRequest request = CmifMessage.CreateRequest(tlsRegion.Memory.Span, new CmifRequestFormat()
+ {
+ DataSize = data.Length,
+ RequestId = requestId,
+ SendPid = sendPid
+ });
+
+ data.CopyTo(request.Data);
+ }
+
+ Result result = HorizonStatic.Syscall.SendSyncRequest(sessionHandle);
+
+ if (result.IsFailure)
+ {
+ response = default;
+ return result;
+ }
+
+ return CmifMessage.ParseResponse(out response, HorizonStatic.AddressSpace.GetWritableRegion(tlsAddress, tlsSize).Memory.Span, false, 0);
+ }
+ }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Cmif/CmifDomainInHeader.cs b/Ryujinx.Horizon/Sdk/Sf/Cmif/CmifDomainInHeader.cs
new file mode 100644
index 00000000..88211501
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Cmif/CmifDomainInHeader.cs
@@ -0,0 +1,12 @@
+namespace Ryujinx.Horizon.Sdk.Sf.Cmif
+{
+ struct CmifDomainInHeader
+ {
+ public CmifDomainRequestType Type;
+ public byte ObjectsCount;
+ public ushort DataSize;
+ public int ObjectId;
+ public uint Padding;
+ public uint Token;
+ }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Cmif/CmifDomainOutHeader.cs b/Ryujinx.Horizon/Sdk/Sf/Cmif/CmifDomainOutHeader.cs
new file mode 100644
index 00000000..2086d24c
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Cmif/CmifDomainOutHeader.cs
@@ -0,0 +1,12 @@
+namespace Ryujinx.Horizon.Sdk.Sf.Cmif
+{
+ struct CmifDomainOutHeader
+ {
+#pragma warning disable CS0649
+ public uint ObjectsCount;
+ public uint Padding;
+ public uint Padding2;
+ public uint Padding3;
+#pragma warning restore CS0649
+ }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Cmif/CmifDomainRequestType.cs b/Ryujinx.Horizon/Sdk/Sf/Cmif/CmifDomainRequestType.cs
new file mode 100644
index 00000000..b913db94
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Cmif/CmifDomainRequestType.cs
@@ -0,0 +1,9 @@
+namespace Ryujinx.Horizon.Sdk.Sf.Cmif
+{
+ enum CmifDomainRequestType : byte
+ {
+ Invalid = 0,
+ SendMessage = 1,
+ Close = 2
+ }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Cmif/CmifInHeader.cs b/Ryujinx.Horizon/Sdk/Sf/Cmif/CmifInHeader.cs
new file mode 100644
index 00000000..55b859fc
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Cmif/CmifInHeader.cs
@@ -0,0 +1,10 @@
+namespace Ryujinx.Horizon.Sdk.Sf.Cmif
+{
+ struct CmifInHeader
+ {
+ public uint Magic;
+ public uint Version;
+ public uint CommandId;
+ public uint Token;
+ }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Cmif/CmifMessage.cs b/Ryujinx.Horizon/Sdk/Sf/Cmif/CmifMessage.cs
new file mode 100644
index 00000000..781452e3
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Cmif/CmifMessage.cs
@@ -0,0 +1,128 @@
+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;
+ }
+ }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Cmif/CmifOutHeader.cs b/Ryujinx.Horizon/Sdk/Sf/Cmif/CmifOutHeader.cs
new file mode 100644
index 00000000..2828cde5
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Cmif/CmifOutHeader.cs
@@ -0,0 +1,14 @@
+using Ryujinx.Horizon.Common;
+
+namespace Ryujinx.Horizon.Sdk.Sf.Cmif
+{
+ struct CmifOutHeader
+ {
+#pragma warning disable CS0649
+ public uint Magic;
+ public uint Version;
+ public Result Result;
+ public uint Token;
+#pragma warning restore CS0649
+ }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Cmif/CmifRequest.cs b/Ryujinx.Horizon/Sdk/Sf/Cmif/CmifRequest.cs
new file mode 100644
index 00000000..80772ad3
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Cmif/CmifRequest.cs
@@ -0,0 +1,14 @@
+using Ryujinx.Horizon.Sdk.Sf.Hipc;
+using System;
+
+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;
+ }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Cmif/CmifRequestFormat.cs b/Ryujinx.Horizon/Sdk/Sf/Cmif/CmifRequestFormat.cs
new file mode 100644
index 00000000..d1154578
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Cmif/CmifRequestFormat.cs
@@ -0,0 +1,24 @@
+namespace Ryujinx.Horizon.Sdk.Sf.Cmif
+{
+ struct CmifRequestFormat
+ {
+#pragma warning disable CS0649
+ 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 bool SendPid;
+#pragma warning restore CS0649
+ }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Cmif/CmifResponse.cs b/Ryujinx.Horizon/Sdk/Sf/Cmif/CmifResponse.cs
new file mode 100644
index 00000000..d1d8dc9c
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Cmif/CmifResponse.cs
@@ -0,0 +1,12 @@
+using System;
+
+namespace Ryujinx.Horizon.Sdk.Sf.Cmif
+{
+ ref struct CmifResponse
+ {
+ public ReadOnlySpan<byte> Data;
+ public ReadOnlySpan<uint> Objects;
+ public ReadOnlySpan<int> CopyHandles;
+ public ReadOnlySpan<int> MoveHandles;
+ }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Cmif/CommandType.cs b/Ryujinx.Horizon/Sdk/Sf/Cmif/CommandType.cs
new file mode 100644
index 00000000..b3b05864
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Cmif/CommandType.cs
@@ -0,0 +1,14 @@
+namespace Ryujinx.Horizon.Sdk.Sf.Cmif
+{
+ enum CommandType
+ {
+ Invalid = 0,
+ LegacyRequest = 1,
+ Close = 2,
+ LegacyControl = 3,
+ Request = 4,
+ Control = 5,
+ RequestWithContext = 6,
+ ControlWithContext = 7
+ }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Cmif/DomainServiceObject.cs b/Ryujinx.Horizon/Sdk/Sf/Cmif/DomainServiceObject.cs
new file mode 100644
index 00000000..14839687
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Cmif/DomainServiceObject.cs
@@ -0,0 +1,7 @@
+namespace Ryujinx.Horizon.Sdk.Sf.Cmif
+{
+ abstract partial class DomainServiceObject : ServerDomainBase, IServiceObject
+ {
+ public abstract ServerDomainBase GetServerDomain();
+ }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Cmif/DomainServiceObjectDispatchTable.cs b/Ryujinx.Horizon/Sdk/Sf/Cmif/DomainServiceObjectDispatchTable.cs
new file mode 100644
index 00000000..bcf311b2
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Cmif/DomainServiceObjectDispatchTable.cs
@@ -0,0 +1,75 @@
+using Ryujinx.Horizon.Common;
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.Horizon.Sdk.Sf.Cmif
+{
+ class DomainServiceObjectDispatchTable : ServiceDispatchTableBase
+ {
+ public override Result ProcessMessage(ref ServiceDispatchContext context, ReadOnlySpan<byte> inRawData)
+ {
+ return ProcessMessageImpl(ref context, ((DomainServiceObject)context.ServiceObject).GetServerDomain(), inRawData);
+ }
+
+ private Result ProcessMessageImpl(ref ServiceDispatchContext context, ServerDomainBase domain, ReadOnlySpan<byte> inRawData)
+ {
+ if (inRawData.Length < Unsafe.SizeOf<CmifDomainInHeader>())
+ {
+ return SfResult.InvalidHeaderSize;
+ }
+
+ var inHeader = MemoryMarshal.Cast<byte, CmifDomainInHeader>(inRawData)[0];
+
+ ReadOnlySpan<byte> inDomainRawData = inRawData.Slice(Unsafe.SizeOf<CmifDomainInHeader>());
+
+ int targetObjectId = inHeader.ObjectId;
+
+ switch (inHeader.Type)
+ {
+ case CmifDomainRequestType.SendMessage:
+ var targetObject = domain.GetObject(targetObjectId);
+ if (targetObject == null)
+ {
+ return SfResult.TargetNotFound;
+ }
+
+ if (inHeader.DataSize + inHeader.ObjectsCount * sizeof(int) > inDomainRawData.Length)
+ {
+ return SfResult.InvalidHeaderSize;
+ }
+
+ ReadOnlySpan<byte> inMessageRawData = inDomainRawData.Slice(0, inHeader.DataSize);
+
+ if (inHeader.ObjectsCount > DomainServiceObjectProcessor.MaximumObjects)
+ {
+ return SfResult.InvalidInObjectsCount;
+ }
+
+ int[] inObjectIds = new int[inHeader.ObjectsCount];
+
+ var domainProcessor = new DomainServiceObjectProcessor(domain, inObjectIds);
+
+ if (context.Processor == null)
+ {
+ context.Processor = domainProcessor;
+ }
+ else
+ {
+ context.Processor.SetImplementationProcessor(domainProcessor);
+ }
+
+ context.ServiceObject = targetObject.ServiceObject;
+
+ return targetObject.ProcessMessage(ref context, inMessageRawData);
+
+ case CmifDomainRequestType.Close:
+ domain.UnregisterObject(targetObjectId);
+ return Result.Success;
+
+ default:
+ return SfResult.InvalidInHeader;
+ }
+ }
+ }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Cmif/DomainServiceObjectProcessor.cs b/Ryujinx.Horizon/Sdk/Sf/Cmif/DomainServiceObjectProcessor.cs
new file mode 100644
index 00000000..92d86196
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Cmif/DomainServiceObjectProcessor.cs
@@ -0,0 +1,140 @@
+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
+{
+ class DomainServiceObjectProcessor : ServerMessageProcessor
+ {
+ public const int MaximumObjects = 8;
+
+ private ServerMessageProcessor _implProcessor;
+ private readonly ServerDomainBase _domain;
+ private int _outObjectIdsOffset;
+ private readonly int[] _inObjectIds;
+ private readonly int[] _reservedObjectIds;
+ private ServerMessageRuntimeMetadata _implMetadata;
+
+ private int InObjectsCount => _inObjectIds.Length;
+ private int OutObjectsCount => _implMetadata.OutObjectsCount;
+ private int ImplOutHeadersSize => _implMetadata.OutHeadersSize;
+ private int ImplOutDataTotalSize => _implMetadata.OutDataSize + _implMetadata.OutHeadersSize;
+
+ public DomainServiceObjectProcessor(ServerDomainBase domain, int[] inObjectIds)
+ {
+ _domain = domain;
+ _inObjectIds = inObjectIds;
+ _reservedObjectIds = new int[MaximumObjects];
+ }
+
+ public override void SetImplementationProcessor(ServerMessageProcessor impl)
+ {
+ if (_implProcessor == null)
+ {
+ _implProcessor = impl;
+ }
+ else
+ {
+ _implProcessor.SetImplementationProcessor(impl);
+ }
+
+ _implMetadata = _implProcessor.GetRuntimeMetadata();
+ }
+
+ public override ServerMessageRuntimeMetadata GetRuntimeMetadata()
+ {
+ var runtimeMetadata = _implProcessor.GetRuntimeMetadata();
+
+ return new ServerMessageRuntimeMetadata(
+ (ushort)(runtimeMetadata.InDataSize + runtimeMetadata.InObjectsCount * sizeof(int)),
+ (ushort)(runtimeMetadata.OutDataSize + runtimeMetadata.OutObjectsCount * sizeof(int)),
+ (byte)(runtimeMetadata.InHeadersSize + Unsafe.SizeOf<CmifDomainInHeader>()),
+ (byte)(runtimeMetadata.OutHeadersSize + Unsafe.SizeOf<CmifDomainOutHeader>()),
+ 0,
+ 0);
+ }
+
+ public override Result PrepareForProcess(ref ServiceDispatchContext context, ServerMessageRuntimeMetadata runtimeMetadata)
+ {
+ if (_implMetadata.InObjectsCount != InObjectsCount)
+ {
+ return SfResult.InvalidInObjectsCount;
+ }
+
+ Result result = _domain.ReserveIds(new Span<int>(_reservedObjectIds).Slice(0, OutObjectsCount));
+
+ if (result.IsFailure)
+ {
+ return result;
+ }
+
+ return _implProcessor.PrepareForProcess(ref context, runtimeMetadata);
+ }
+
+ public override Result GetInObjects(Span<ServiceObjectHolder> inObjects)
+ {
+ for (int i = 0; i < InObjectsCount; i++)
+ {
+ inObjects[i] = _domain.GetObject(_inObjectIds[i]);
+ }
+
+ return Result.Success;
+ }
+
+ public override HipcMessageData PrepareForReply(scoped ref ServiceDispatchContext context, out Span<byte> outRawData, ServerMessageRuntimeMetadata runtimeMetadata)
+ {
+ var response = _implProcessor.PrepareForReply(ref context, out outRawData, runtimeMetadata);
+
+ int outHeaderSize = Unsafe.SizeOf<CmifDomainOutHeader>();
+ int implOutDataTotalSize = ImplOutDataTotalSize;
+
+ DebugUtil.Assert(outHeaderSize + implOutDataTotalSize + OutObjectsCount * sizeof(int) <= outRawData.Length);
+
+ outRawData = outRawData.Slice(outHeaderSize);
+ _outObjectIdsOffset = (response.DataWords.Length * sizeof(uint) - outRawData.Length) + implOutDataTotalSize;
+
+ return response;
+ }
+
+ public override void PrepareForErrorReply(scoped ref ServiceDispatchContext context, out Span<byte> outRawData, ServerMessageRuntimeMetadata runtimeMetadata)
+ {
+ _implProcessor.PrepareForErrorReply(ref context, out outRawData, runtimeMetadata);
+
+ int outHeaderSize = Unsafe.SizeOf<CmifDomainOutHeader>();
+ int implOutDataTotalSize = ImplOutDataTotalSize;
+
+ DebugUtil.Assert(outHeaderSize + implOutDataTotalSize <= outRawData.Length);
+
+ outRawData = outRawData.Slice(outHeaderSize);
+
+ _domain.UnreserveIds(new Span<int>(_reservedObjectIds).Slice(0, OutObjectsCount));
+ }
+
+ public override void SetOutObjects(scoped ref ServiceDispatchContext context, HipcMessageData response, Span<ServiceObjectHolder> outObjects)
+ {
+ int outObjectsCount = OutObjectsCount;
+ Span<int> objectIds = _reservedObjectIds;
+
+ for (int i = 0; i < outObjectsCount; i++)
+ {
+ if (outObjects[i] == null)
+ {
+ _domain.UnreserveIds(objectIds.Slice(i, 1));
+ objectIds[i] = 0;
+ continue;
+ }
+
+ _domain.RegisterObject(objectIds[i], outObjects[i]);
+ }
+
+ Span<int> outObjectIds = MemoryMarshal.Cast<byte, int>(MemoryMarshal.Cast<uint, byte>(response.DataWords).Slice(_outObjectIdsOffset));
+
+ for (int i = 0; i < outObjectsCount; i++)
+ {
+ outObjectIds[i] = objectIds[i];
+ }
+ }
+ }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Cmif/HandlesToClose.cs b/Ryujinx.Horizon/Sdk/Sf/Cmif/HandlesToClose.cs
new file mode 100644
index 00000000..0f3b259a
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Cmif/HandlesToClose.cs
@@ -0,0 +1,52 @@
+using System;
+
+namespace Ryujinx.Horizon.Sdk.Sf.Cmif
+{
+ struct HandlesToClose
+ {
+ private int _handle0;
+ private int _handle1;
+ private int _handle2;
+ private int _handle3;
+ private int _handle4;
+ private int _handle5;
+ private int _handle6;
+ private int _handle7;
+
+ public int Count;
+
+ public int this[int index]
+ {
+ get
+ {
+ return index switch
+ {
+ 0 => _handle0,
+ 1 => _handle1,
+ 2 => _handle2,
+ 3 => _handle3,
+ 4 => _handle4,
+ 5 => _handle5,
+ 6 => _handle6,
+ 7 => _handle7,
+ _ => throw new IndexOutOfRangeException()
+ };
+ }
+ set
+ {
+ switch (index)
+ {
+ case 0: _handle0 = value; break;
+ case 1: _handle1 = value; break;
+ case 2: _handle2 = value; break;
+ case 3: _handle3 = value; break;
+ case 4: _handle4 = value; break;
+ case 5: _handle5 = value; break;
+ case 6: _handle6 = value; break;
+ case 7: _handle7 = value; break;
+ default: throw new IndexOutOfRangeException();
+ }
+ }
+ }
+ }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Cmif/InlineContext.cs b/Ryujinx.Horizon/Sdk/Sf/Cmif/InlineContext.cs
new file mode 100644
index 00000000..ddb6943f
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Cmif/InlineContext.cs
@@ -0,0 +1,11 @@
+namespace Ryujinx.Horizon.Sdk.Sf.Cmif
+{
+ class InlineContext
+ {
+ public static int Set(int newContext)
+ {
+ // TODO: Implement (will require FS changes???)
+ return newContext;
+ }
+ }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Cmif/PointerAndSize.cs b/Ryujinx.Horizon/Sdk/Sf/Cmif/PointerAndSize.cs
new file mode 100644
index 00000000..5af00077
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Cmif/PointerAndSize.cs
@@ -0,0 +1,17 @@
+namespace Ryujinx.Horizon.Sdk.Sf.Cmif
+{
+ struct PointerAndSize
+ {
+ public static PointerAndSize Empty => new PointerAndSize(0UL, 0UL);
+
+ public ulong Address { get; }
+ public ulong Size { get; }
+ public bool IsEmpty => Size == 0UL;
+
+ public PointerAndSize(ulong address, ulong size)
+ {
+ Address = address;
+ Size = size;
+ }
+ }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Cmif/ScopedInlineContextChange.cs b/Ryujinx.Horizon/Sdk/Sf/Cmif/ScopedInlineContextChange.cs
new file mode 100644
index 00000000..eabe544f
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Cmif/ScopedInlineContextChange.cs
@@ -0,0 +1,19 @@
+using System;
+
+namespace Ryujinx.Horizon.Sdk.Sf.Cmif
+{
+ struct ScopedInlineContextChange : IDisposable
+ {
+ private readonly int _previousContext;
+
+ public ScopedInlineContextChange(int newContext)
+ {
+ _previousContext = InlineContext.Set(newContext);
+ }
+
+ public void Dispose()
+ {
+ InlineContext.Set(_previousContext);
+ }
+ }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Cmif/ServerDomainBase.cs b/Ryujinx.Horizon/Sdk/Sf/Cmif/ServerDomainBase.cs
new file mode 100644
index 00000000..f38fa030
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Cmif/ServerDomainBase.cs
@@ -0,0 +1,15 @@
+using Ryujinx.Horizon.Common;
+using System;
+
+namespace Ryujinx.Horizon.Sdk.Sf.Cmif
+{
+ abstract class ServerDomainBase
+ {
+ public abstract Result ReserveIds(Span<int> outIds);
+ public abstract void UnreserveIds(ReadOnlySpan<int> ids);
+ public abstract void RegisterObject(int id, ServiceObjectHolder obj);
+
+ public abstract ServiceObjectHolder UnregisterObject(int id);
+ public abstract ServiceObjectHolder GetObject(int id);
+ }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Cmif/ServerDomainManager.cs b/Ryujinx.Horizon/Sdk/Sf/Cmif/ServerDomainManager.cs
new file mode 100644
index 00000000..62ee2738
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Cmif/ServerDomainManager.cs
@@ -0,0 +1,246 @@
+using Ryujinx.Horizon.Common;
+using System;
+using System.Collections.Generic;
+
+namespace Ryujinx.Horizon.Sdk.Sf.Cmif
+{
+ class ServerDomainManager
+ {
+ private class EntryManager
+ {
+ public class Entry
+ {
+ public int Id { get; }
+ public Domain Owner { get; set; }
+ public ServiceObjectHolder Obj { get; set; }
+ public LinkedListNode<Entry> Node { get; set; }
+
+ public Entry(int id)
+ {
+ Id = id;
+ }
+ }
+
+ private readonly LinkedList<Entry> _freeList;
+ private readonly Entry[] _entries;
+
+ public EntryManager(int count)
+ {
+ _freeList = new LinkedList<Entry>();
+ _entries = new Entry[count];
+
+ for (int i = 0; i < count; i++)
+ {
+ _freeList.AddLast(_entries[i] = new Entry(i + 1));
+ }
+ }
+
+ public Entry AllocateEntry()
+ {
+ lock (_freeList)
+ {
+ if (_freeList.Count == 0)
+ {
+ return null;
+ }
+
+ var entry = _freeList.First.Value;
+ _freeList.RemoveFirst();
+ return entry;
+ }
+ }
+
+ public void FreeEntry(Entry entry)
+ {
+ lock (_freeList)
+ {
+ DebugUtil.Assert(entry.Owner == null);
+ DebugUtil.Assert(entry.Obj == null);
+ _freeList.AddFirst(entry);
+ }
+ }
+
+ public Entry GetEntry(int id)
+ {
+ if (id == 0)
+ {
+ return null;
+ }
+
+ int index = id - 1;
+
+ if ((uint)index >= (uint)_entries.Length)
+ {
+ return null;
+ }
+
+ return _entries[index];
+ }
+ }
+
+ private class Domain : DomainServiceObject, IDisposable
+ {
+ private readonly ServerDomainManager _manager;
+ private readonly LinkedList<EntryManager.Entry> _entries;
+
+ public Domain(ServerDomainManager manager)
+ {
+ _manager = manager;
+ _entries = new LinkedList<EntryManager.Entry>();
+ }
+
+ public override ServiceObjectHolder GetObject(int id)
+ {
+ var entry = _manager._entryManager.GetEntry(id);
+ if (entry == null)
+ {
+ return null;
+ }
+
+ lock (_manager._entryOwnerLock)
+ {
+ if (entry.Owner != this)
+ {
+ return null;
+ }
+ }
+
+ return entry.Obj.Clone();
+ }
+
+ public override ServerDomainBase GetServerDomain()
+ {
+ return this;
+ }
+
+ public override void RegisterObject(int id, ServiceObjectHolder obj)
+ {
+ var entry = _manager._entryManager.GetEntry(id);
+ DebugUtil.Assert(entry != null);
+
+ lock (_manager._entryOwnerLock)
+ {
+ DebugUtil.Assert(entry.Owner == null);
+ entry.Owner = this;
+ entry.Node = _entries.AddLast(entry);
+ }
+
+ entry.Obj = obj;
+ }
+
+ public override Result ReserveIds(Span<int> outIds)
+ {
+ for (int i = 0; i < outIds.Length; i++)
+ {
+ var entry = _manager._entryManager.AllocateEntry();
+ if (entry == null)
+ {
+ return SfResult.OutOfDomainEntries;
+ }
+
+ DebugUtil.Assert(entry.Owner == null);
+
+ outIds[i] = entry.Id;
+ }
+
+ return Result.Success;
+ }
+
+ public override ServiceObjectHolder UnregisterObject(int id)
+ {
+ var entry = _manager._entryManager.GetEntry(id);
+ if (entry == null)
+ {
+ return null;
+ }
+
+ ServiceObjectHolder obj;
+
+ lock (_manager._entryOwnerLock)
+ {
+ if (entry.Owner != this)
+ {
+ return null;
+ }
+
+ entry.Owner = null;
+ obj = entry.Obj;
+ entry.Obj = null;
+ _entries.Remove(entry.Node);
+ entry.Node = null;
+ }
+
+ _manager._entryManager.FreeEntry(entry);
+
+ return obj;
+ }
+
+ public override void UnreserveIds(ReadOnlySpan<int> ids)
+ {
+ for (int i = 0; i < ids.Length; i++)
+ {
+ var entry = _manager._entryManager.GetEntry(ids[i]);
+
+ DebugUtil.Assert(entry != null);
+ DebugUtil.Assert(entry.Owner == null);
+
+ _manager._entryManager.FreeEntry(entry);
+ }
+ }
+
+ public void Dispose()
+ {
+ foreach (var entry in _entries)
+ {
+ if (entry.Obj.ServiceObject is IDisposable disposableObj)
+ {
+ disposableObj.Dispose();
+ }
+ }
+
+ _manager.FreeDomain(this);
+ }
+ }
+
+ private readonly EntryManager _entryManager;
+ private readonly object _entryOwnerLock;
+ private readonly HashSet<Domain> _domains;
+ private int _maxDomains;
+
+ public ServerDomainManager(int entryCount, int maxDomains)
+ {
+ _entryManager = new EntryManager(entryCount);
+ _entryOwnerLock = new object();
+ _domains = new HashSet<Domain>();
+ _maxDomains = maxDomains;
+ }
+
+ public DomainServiceObject AllocateDomainServiceObject()
+ {
+ lock (_domains)
+ {
+ if (_domains.Count == _maxDomains)
+ {
+ return null;
+ }
+
+ var domain = new Domain(this);
+ _domains.Add(domain);
+ return domain;
+ }
+ }
+
+ public static void DestroyDomainServiceObject(DomainServiceObject obj)
+ {
+ ((Domain)obj).Dispose();
+ }
+
+ private void FreeDomain(Domain domain)
+ {
+ lock (_domains)
+ {
+ _domains.Remove(domain);
+ }
+ }
+ }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Cmif/ServerMessageProcessor.cs b/Ryujinx.Horizon/Sdk/Sf/Cmif/ServerMessageProcessor.cs
new file mode 100644
index 00000000..e7650238
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Cmif/ServerMessageProcessor.cs
@@ -0,0 +1,18 @@
+using Ryujinx.Horizon.Common;
+using Ryujinx.Horizon.Sdk.Sf.Hipc;
+using System;
+
+namespace Ryujinx.Horizon.Sdk.Sf.Cmif
+{
+ abstract class ServerMessageProcessor
+ {
+ public abstract void SetImplementationProcessor(ServerMessageProcessor impl);
+ public abstract ServerMessageRuntimeMetadata GetRuntimeMetadata();
+
+ public abstract Result PrepareForProcess(scoped ref ServiceDispatchContext context, ServerMessageRuntimeMetadata runtimeMetadata);
+ public abstract Result GetInObjects(Span<ServiceObjectHolder> inObjects);
+ public abstract HipcMessageData PrepareForReply(scoped ref ServiceDispatchContext context, out Span<byte> outRawData, ServerMessageRuntimeMetadata runtimeMetadata);
+ public abstract void PrepareForErrorReply(scoped ref ServiceDispatchContext context, out Span<byte> outRawData, ServerMessageRuntimeMetadata runtimeMetadata);
+ public abstract void SetOutObjects(scoped ref ServiceDispatchContext context, HipcMessageData response, Span<ServiceObjectHolder> outObjects);
+ }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Cmif/ServerMessageRuntimeMetadata.cs b/Ryujinx.Horizon/Sdk/Sf/Cmif/ServerMessageRuntimeMetadata.cs
new file mode 100644
index 00000000..18a40430
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Cmif/ServerMessageRuntimeMetadata.cs
@@ -0,0 +1,29 @@
+namespace Ryujinx.Horizon.Sdk.Sf.Cmif
+{
+ 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 int UnfixedOutPointerSizeOffset => InDataSize + InHeadersSize + 0x10;
+
+ public ServerMessageRuntimeMetadata(
+ ushort inDataSize,
+ ushort outDataSize,
+ byte inHeadersSize,
+ byte outHeadersSize,
+ byte inObjectsCount,
+ byte outObjectsCount)
+ {
+ InDataSize = inDataSize;
+ OutDataSize = outDataSize;
+ InHeadersSize = inHeadersSize;
+ OutHeadersSize = outHeadersSize;
+ InObjectsCount = inObjectsCount;
+ OutObjectsCount = outObjectsCount;
+ }
+ }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Cmif/ServiceDispatchContext.cs b/Ryujinx.Horizon/Sdk/Sf/Cmif/ServiceDispatchContext.cs
new file mode 100644
index 00000000..3339a1a6
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Cmif/ServiceDispatchContext.cs
@@ -0,0 +1,18 @@
+using Ryujinx.Horizon.Sdk.Sf.Hipc;
+using System;
+
+namespace Ryujinx.Horizon.Sdk.Sf.Cmif
+{
+ ref struct ServiceDispatchContext
+ {
+ 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;
+ }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Cmif/ServiceDispatchMeta.cs b/Ryujinx.Horizon/Sdk/Sf/Cmif/ServiceDispatchMeta.cs
new file mode 100644
index 00000000..7fbd8eb8
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Cmif/ServiceDispatchMeta.cs
@@ -0,0 +1,12 @@
+namespace Ryujinx.Horizon.Sdk.Sf.Cmif
+{
+ struct ServiceDispatchMeta
+ {
+ public ServiceDispatchTableBase DispatchTable { get; }
+
+ public ServiceDispatchMeta(ServiceDispatchTableBase dispatchTable)
+ {
+ DispatchTable = dispatchTable;
+ }
+ }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Cmif/ServiceDispatchTable.cs b/Ryujinx.Horizon/Sdk/Sf/Cmif/ServiceDispatchTable.cs
new file mode 100644
index 00000000..145c1783
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Cmif/ServiceDispatchTable.cs
@@ -0,0 +1,33 @@
+using Ryujinx.Horizon.Common;
+using System;
+using System.Collections.Generic;
+
+namespace Ryujinx.Horizon.Sdk.Sf.Cmif
+{
+ class ServiceDispatchTable : ServiceDispatchTableBase
+ {
+ private readonly string _objectName;
+ private readonly IReadOnlyDictionary<int, CommandHandler> _entries;
+
+ public ServiceDispatchTable(string objectName, IReadOnlyDictionary<int, CommandHandler> entries)
+ {
+ _objectName = objectName;
+ _entries = entries;
+ }
+
+ public override Result ProcessMessage(ref ServiceDispatchContext context, ReadOnlySpan<byte> inRawData)
+ {
+ return ProcessMessageImpl(ref context, inRawData, _entries, _objectName);
+ }
+
+ public static ServiceDispatchTableBase Create(IServiceObject instance)
+ {
+ if (instance is DomainServiceObject)
+ {
+ return new DomainServiceObjectDispatchTable();
+ }
+
+ return new ServiceDispatchTable(instance.GetType().Name, instance.GetCommandHandlers());
+ }
+ }
+}
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;
+ }
+ }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Cmif/ServiceObjectHolder.cs b/Ryujinx.Horizon/Sdk/Sf/Cmif/ServiceObjectHolder.cs
new file mode 100644
index 00000000..6e87e340
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Cmif/ServiceObjectHolder.cs
@@ -0,0 +1,34 @@
+using Ryujinx.Horizon.Common;
+using System;
+
+namespace Ryujinx.Horizon.Sdk.Sf.Cmif
+{
+ class ServiceObjectHolder
+ {
+ public IServiceObject ServiceObject { get; }
+
+ private readonly ServiceDispatchMeta _dispatchMeta;
+
+ public ServiceObjectHolder(ServiceObjectHolder objectHolder)
+ {
+ ServiceObject = objectHolder.ServiceObject;
+ _dispatchMeta = objectHolder._dispatchMeta;
+ }
+
+ public ServiceObjectHolder(IServiceObject serviceImpl)
+ {
+ ServiceObject = serviceImpl;
+ _dispatchMeta = new ServiceDispatchMeta(ServiceDispatchTable.Create(serviceImpl));
+ }
+
+ public ServiceObjectHolder Clone()
+ {
+ return new ServiceObjectHolder(this);
+ }
+
+ public Result ProcessMessage(ref ServiceDispatchContext context, ReadOnlySpan<byte> inRawData)
+ {
+ return _dispatchMeta.DispatchTable.ProcessMessage(ref context, inRawData);
+ }
+ }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/CmifCommandAttribute.cs b/Ryujinx.Horizon/Sdk/Sf/CmifCommandAttribute.cs
new file mode 100644
index 00000000..51a7b597
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/CmifCommandAttribute.cs
@@ -0,0 +1,15 @@
+using System;
+
+namespace Ryujinx.Horizon.Sdk.Sf
+{
+ [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
+ class CmifCommandAttribute : Attribute
+ {
+ public uint CommandId { get; }
+
+ public CmifCommandAttribute(uint commandId)
+ {
+ CommandId = commandId;
+ }
+ }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/CommandArg.cs b/Ryujinx.Horizon/Sdk/Sf/CommandArg.cs
new file mode 100644
index 00000000..8f367b4e
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/CommandArg.cs
@@ -0,0 +1,56 @@
+using Ryujinx.Horizon.Sdk.Sf.Hipc;
+
+namespace Ryujinx.Horizon.Sdk.Sf
+{
+ enum CommandArgType : byte
+ {
+ Invalid,
+
+ Buffer,
+ InArgument,
+ InCopyHandle,
+ InMoveHandle,
+ InObject,
+ OutArgument,
+ OutCopyHandle,
+ OutMoveHandle,
+ OutObject,
+ ProcessId
+ }
+
+ struct CommandArg
+ {
+ public CommandArgType Type { get; }
+ public HipcBufferFlags BufferFlags { get; }
+ public ushort BufferFixedSize { get; }
+ public int ArgSize { get; }
+ public int ArgAlignment { get; }
+
+ public CommandArg(CommandArgType type)
+ {
+ Type = type;
+ BufferFlags = default;
+ BufferFixedSize = 0;
+ ArgSize = 0;
+ ArgAlignment = 0;
+ }
+
+ public CommandArg(CommandArgType type, int argSize, int argAlignment)
+ {
+ Type = type;
+ BufferFlags = default;
+ BufferFixedSize = 0;
+ ArgSize = argSize;
+ ArgAlignment = argAlignment;
+ }
+
+ public CommandArg(HipcBufferFlags flags, ushort fixedSize = 0)
+ {
+ Type = CommandArgType.Buffer;
+ BufferFlags = flags;
+ BufferFixedSize = fixedSize;
+ ArgSize = 0;
+ ArgAlignment = 0;
+ }
+ }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/CommandArgAttributes.cs b/Ryujinx.Horizon/Sdk/Sf/CommandArgAttributes.cs
new file mode 100644
index 00000000..5b7c302f
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/CommandArgAttributes.cs
@@ -0,0 +1,38 @@
+using Ryujinx.Horizon.Sdk.Sf.Hipc;
+using System;
+
+namespace Ryujinx.Horizon.Sdk.Sf
+{
+ [AttributeUsage(AttributeTargets.Parameter)]
+ class BufferAttribute : Attribute
+ {
+ public HipcBufferFlags Flags { get; }
+ public ushort FixedSize { get; }
+
+ public BufferAttribute(HipcBufferFlags flags)
+ {
+ Flags = flags;
+ }
+
+ public BufferAttribute(HipcBufferFlags flags, ushort fixedSize)
+ {
+ Flags = flags | HipcBufferFlags.FixedSize;
+ FixedSize = fixedSize;
+ }
+ }
+
+ [AttributeUsage(AttributeTargets.Parameter)]
+ class ClientProcessIdAttribute : Attribute
+ {
+ }
+
+ [AttributeUsage(AttributeTargets.Parameter)]
+ class CopyHandleAttribute : Attribute
+ {
+ }
+
+ [AttributeUsage(AttributeTargets.Parameter)]
+ class MoveHandleAttribute : Attribute
+ {
+ }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/CommandHandler.cs b/Ryujinx.Horizon/Sdk/Sf/CommandHandler.cs
new file mode 100644
index 00000000..ae42a8ef
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/CommandHandler.cs
@@ -0,0 +1,57 @@
+using Ryujinx.Horizon.Common;
+using Ryujinx.Horizon.Sdk.Sf.Cmif;
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.Horizon.Sdk.Sf
+{
+ class CommandHandler
+ {
+ public delegate Result MethodInvoke(
+ ref ServiceDispatchContext context,
+ HipcCommandProcessor processor,
+ ServerMessageRuntimeMetadata runtimeMetadata,
+ ReadOnlySpan<byte> inRawData,
+ ref Span<CmifOutHeader> outHeader);
+
+ private readonly MethodInvoke _invoke;
+ private readonly HipcCommandProcessor _processor;
+
+ public string MethodName => _invoke.Method.Name;
+
+ public CommandHandler(MethodInvoke invoke, params CommandArg[] args)
+ {
+ _invoke = invoke;
+ _processor = new HipcCommandProcessor(args);
+ }
+
+ public Result Invoke(ref Span<CmifOutHeader> outHeader, ref ServiceDispatchContext context, ReadOnlySpan<byte> inRawData)
+ {
+ if (context.Processor == null)
+ {
+ context.Processor = _processor;
+ }
+ else
+ {
+ context.Processor.SetImplementationProcessor(_processor);
+ }
+
+ var runtimeMetadata = context.Processor.GetRuntimeMetadata();
+ Result result = context.Processor.PrepareForProcess(ref context, runtimeMetadata);
+
+ if (result.IsFailure)
+ {
+ return result;
+ }
+
+ return _invoke(ref context, _processor, runtimeMetadata, inRawData, ref outHeader);
+ }
+
+ public static void GetCmifOutHeaderPointer(ref Span<CmifOutHeader> outHeader, ref Span<byte> outRawData)
+ {
+ outHeader = MemoryMarshal.Cast<byte, CmifOutHeader>(outRawData).Slice(0, 1);
+ outRawData = outRawData.Slice(Unsafe.SizeOf<CmifOutHeader>());
+ }
+ }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/CommandSerialization.cs b/Ryujinx.Horizon/Sdk/Sf/CommandSerialization.cs
new file mode 100644
index 00000000..9a3a511a
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/CommandSerialization.cs
@@ -0,0 +1,68 @@
+using Ryujinx.Horizon.Sdk.Sf.Cmif;
+using Ryujinx.Horizon.Sdk.Sf.Hipc;
+using Ryujinx.Memory;
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.Horizon.Sdk.Sf
+{
+ static class CommandSerialization
+ {
+ public static ReadOnlySpan<byte> GetReadOnlySpan(PointerAndSize bufferRange)
+ {
+ return HorizonStatic.AddressSpace.GetSpan(bufferRange.Address, checked((int)bufferRange.Size));
+ }
+
+ public static WritableRegion GetWritableRegion(PointerAndSize bufferRange)
+ {
+ return HorizonStatic.AddressSpace.GetWritableRegion(bufferRange.Address, checked((int)bufferRange.Size));
+ }
+
+ public static ref T GetRef<T>(PointerAndSize bufferRange) where T : unmanaged
+ {
+ var writableRegion = GetWritableRegion(bufferRange);
+ return ref MemoryMarshal.Cast<byte, T>(writableRegion.Memory.Span)[0];
+ }
+
+ public static object DeserializeArg<T>(ref ServiceDispatchContext context, ReadOnlySpan<byte> inRawData, int offset) where T : unmanaged
+ {
+ return MemoryMarshal.Cast<byte, T>(inRawData.Slice(offset, Unsafe.SizeOf<T>()))[0];
+ }
+
+ public static T DeserializeArg<T>(ReadOnlySpan<byte> inRawData, int offset) where T : unmanaged
+ {
+ return MemoryMarshal.Cast<byte, T>(inRawData.Slice(offset, Unsafe.SizeOf<T>()))[0];
+ }
+
+ public static ulong DeserializeClientProcessId(ref ServiceDispatchContext context)
+ {
+ return context.Request.Pid;
+ }
+
+ public static int DeserializeCopyHandle(ref ServiceDispatchContext context, int index)
+ {
+ return context.Request.Data.CopyHandles[index];
+ }
+
+ public static int DeserializeMoveHandle(ref ServiceDispatchContext context, int index)
+ {
+ return context.Request.Data.MoveHandles[index];
+ }
+
+ public static void SerializeArg<T>(Span<byte> outRawData, int offset, T value) where T : unmanaged
+ {
+ MemoryMarshal.Cast<byte, T>(outRawData.Slice(offset, Unsafe.SizeOf<T>()))[0] = (T)value;
+ }
+
+ public static void SerializeCopyHandle(HipcMessageData response, int index, int value)
+ {
+ response.CopyHandles[index] = value;
+ }
+
+ public static void SerializeMoveHandle(HipcMessageData response, int index, int value)
+ {
+ response.MoveHandles[index] = value;
+ }
+ }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Hipc/Api.cs b/Ryujinx.Horizon/Sdk/Sf/Hipc/Api.cs
new file mode 100644
index 00000000..deac524c
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Hipc/Api.cs
@@ -0,0 +1,89 @@
+using Ryujinx.Horizon.Common;
+using System;
+
+namespace Ryujinx.Horizon.Sdk.Sf.Hipc
+{
+ static class Api
+ {
+ public const int TlsMessageBufferSize = 0x100;
+
+ public static Result Receive(out ReceiveResult recvResult, int sessionHandle, Span<byte> messageBuffer)
+ {
+ Result result = ReceiveImpl(sessionHandle, messageBuffer);
+
+ if (result == KernelResult.PortRemoteClosed)
+ {
+ recvResult = ReceiveResult.Closed;
+
+ return Result.Success;
+ }
+ else if (result == KernelResult.ReceiveListBroken)
+ {
+ recvResult = ReceiveResult.NeedsRetry;
+
+ return Result.Success;
+ }
+
+ recvResult = ReceiveResult.Success;
+
+ return result;
+ }
+
+ private static Result ReceiveImpl(int sessionHandle, Span<byte> messageBuffer)
+ {
+ Span<int> handles = stackalloc int[1];
+
+ handles[0] = sessionHandle;
+
+ var tlsSpan = HorizonStatic.AddressSpace.GetSpan(HorizonStatic.ThreadContext.TlsAddress, TlsMessageBufferSize);
+
+ if (messageBuffer == tlsSpan)
+ {
+ return HorizonStatic.Syscall.ReplyAndReceive(out _, handles, 0, -1L);
+ }
+ else
+ {
+ throw new NotImplementedException();
+ }
+ }
+
+ public static Result Reply(int sessionHandle, ReadOnlySpan<byte> messageBuffer)
+ {
+ Result result = ReplyImpl(sessionHandle, messageBuffer);
+
+ result.AbortUnless(KernelResult.TimedOut, KernelResult.PortRemoteClosed);
+
+ return Result.Success;
+ }
+
+ private static Result ReplyImpl(int sessionHandle, ReadOnlySpan<byte> messageBuffer)
+ {
+ Span<int> handles = stackalloc int[1];
+
+ handles[0] = sessionHandle;
+
+ var tlsSpan = HorizonStatic.AddressSpace.GetSpan(HorizonStatic.ThreadContext.TlsAddress, TlsMessageBufferSize);
+
+ if (messageBuffer == tlsSpan)
+ {
+ return HorizonStatic.Syscall.ReplyAndReceive(out _, handles, sessionHandle, 0);
+ }
+ else
+ {
+ throw new NotImplementedException();
+ }
+ }
+
+ public static Result CreateSession(out int serverHandle, out int clientHandle)
+ {
+ Result result = HorizonStatic.Syscall.CreateSession(out serverHandle, out clientHandle, false, null);
+
+ if (result == KernelResult.OutOfResource)
+ {
+ return HipcResult.OutOfSessions;
+ }
+
+ return result;
+ }
+ }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Hipc/Header.cs b/Ryujinx.Horizon/Sdk/Sf/Hipc/Header.cs
new file mode 100644
index 00000000..cdb50b57
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Hipc/Header.cs
@@ -0,0 +1,65 @@
+using Ryujinx.Common.Utilities;
+using Ryujinx.Horizon.Sdk.Sf.Cmif;
+
+namespace Ryujinx.Horizon.Sdk.Sf.Hipc
+{
+ struct Header
+ {
+ private uint _word0;
+ private uint _word1;
+
+ public CommandType Type
+ {
+ get => (CommandType)_word0.Extract(0, 16);
+ set => _word0 = _word0.Insert(0, 16, (uint)value);
+ }
+
+ public int SendStaticsCount
+ {
+ get => (int)_word0.Extract(16, 4);
+ set => _word0 = _word0.Insert(16, 4, (uint)value);
+ }
+
+ public int SendBuffersCount
+ {
+ get => (int)_word0.Extract(20, 4);
+ set => _word0 = _word0.Insert(20, 4, (uint)value);
+ }
+
+ public int ReceiveBuffersCount
+ {
+ get => (int)_word0.Extract(24, 4);
+ set => _word0 = _word0.Insert(24, 4, (uint)value);
+ }
+
+ public int ExchangeBuffersCount
+ {
+ get => (int)_word0.Extract(28, 4);
+ set => _word0 = _word0.Insert(28, 4, (uint)value);
+ }
+
+ public int DataWordsCount
+ {
+ get => (int)_word1.Extract(0, 10);
+ set => _word1 = _word1.Insert(0, 10, (uint)value);
+ }
+
+ public int ReceiveStaticMode
+ {
+ get => (int)_word1.Extract(10, 4);
+ set => _word1 = _word1.Insert(10, 4, (uint)value);
+ }
+
+ public int ReceiveListOffset
+ {
+ get => (int)_word1.Extract(20, 11);
+ set => _word1 = _word1.Insert(20, 11, (uint)value);
+ }
+
+ public bool HasSpecialHeader
+ {
+ get => _word1.Extract(31);
+ set => _word1 = _word1.Insert(31, value);
+ }
+ }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcBufferDescriptor.cs b/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcBufferDescriptor.cs
new file mode 100644
index 00000000..7778d5bc
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcBufferDescriptor.cs
@@ -0,0 +1,15 @@
+namespace Ryujinx.Horizon.Sdk.Sf.Hipc
+{
+ struct HipcBufferDescriptor
+ {
+#pragma warning disable CS0649
+ private uint _sizeLow;
+ private uint _addressLow;
+ private uint _word2;
+#pragma warning restore CS0649
+
+ public ulong Address => _addressLow | (((ulong)_word2 << 4) & 0xf00000000UL) | (((ulong)_word2 << 34) & 0x7000000000UL);
+ public ulong Size => _sizeLow | ((ulong)_word2 << 8) & 0xf00000000UL;
+ public HipcBufferMode Mode => (HipcBufferMode)(_word2 & 3);
+ }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcBufferFlags.cs b/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcBufferFlags.cs
new file mode 100644
index 00000000..594af2c8
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcBufferFlags.cs
@@ -0,0 +1,17 @@
+using System;
+
+namespace Ryujinx.Horizon.Sdk.Sf.Hipc
+{
+ [Flags]
+ enum HipcBufferFlags : byte
+ {
+ In = 1 << 0,
+ Out = 1 << 1,
+ MapAlias = 1 << 2,
+ Pointer = 1 << 3,
+ FixedSize = 1 << 4,
+ AutoSelect = 1 << 5,
+ MapTransferAllowsNonSecure = 1 << 6,
+ MapTransferAllowsNonDevice = 1 << 7
+ }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcBufferMode.cs b/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcBufferMode.cs
new file mode 100644
index 00000000..4ef6374b
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcBufferMode.cs
@@ -0,0 +1,10 @@
+namespace Ryujinx.Horizon.Sdk.Sf.Hipc
+{
+ enum HipcBufferMode
+ {
+ Normal = 0,
+ NonSecure = 1,
+ Invalid = 2,
+ NonDevice = 3
+ }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcManager.cs b/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcManager.cs
new file mode 100644
index 00000000..ea2ec650
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcManager.cs
@@ -0,0 +1,115 @@
+using Ryujinx.Horizon.Common;
+using Ryujinx.Horizon.Sdk.Sf.Cmif;
+using System;
+
+namespace Ryujinx.Horizon.Sdk.Sf.Hipc
+{
+ partial class HipcManager : IServiceObject
+ {
+ private readonly ServerDomainSessionManager _manager;
+ private readonly ServerSession _session;
+
+ public HipcManager(ServerDomainSessionManager manager, ServerSession session)
+ {
+ _manager = manager;
+ _session = session;
+ }
+
+ [CmifCommand(0)]
+ public Result ConvertCurrentObjectToDomain(out int objectId)
+ {
+ objectId = 0;
+
+ var domain = _manager.Domain.AllocateDomainServiceObject();
+ if (domain == null)
+ {
+ return HipcResult.OutOfDomains;
+ }
+
+ bool succeeded = false;
+
+ try
+ {
+ Span<int> objectIds = stackalloc int[1];
+
+ Result result = domain.ReserveIds(objectIds);
+
+ if (result.IsFailure)
+ {
+ return result;
+ }
+
+ objectId = objectIds[0];
+ succeeded = true;
+ }
+ finally
+ {
+ if (!succeeded)
+ {
+ ServerDomainManager.DestroyDomainServiceObject(domain);
+ }
+ }
+
+ domain.RegisterObject(objectId, _session.ServiceObjectHolder);
+ _session.ServiceObjectHolder = new ServiceObjectHolder(domain);
+
+ return Result.Success;
+ }
+
+ [CmifCommand(1)]
+ public Result CopyFromCurrentDomain([MoveHandle] out int clientHandle, int objectId)
+ {
+ clientHandle = 0;
+
+ if (!(_session.ServiceObjectHolder.ServiceObject is DomainServiceObject domain))
+ {
+ return HipcResult.TargetNotDomain;
+ }
+
+ var obj = domain.GetObject(objectId);
+ if (obj == null)
+ {
+ return HipcResult.DomainObjectNotFound;
+ }
+
+ Api.CreateSession(out int serverHandle, out clientHandle).AbortOnFailure();
+ _manager.RegisterSession(serverHandle, obj).AbortOnFailure();
+
+ return Result.Success;
+ }
+
+ [CmifCommand(2)]
+ public Result CloneCurrentObject([MoveHandle] out int clientHandle)
+ {
+ return CloneCurrentObjectImpl(out clientHandle, _manager);
+ }
+
+ [CmifCommand(3)]
+ public void QueryPointerBufferSize(out ushort size)
+ {
+ size = (ushort)_session.PointerBuffer.Size;
+ }
+
+ [CmifCommand(4)]
+ public Result CloneCurrentObjectEx([MoveHandle] out int clientHandle, uint tag)
+ {
+ return CloneCurrentObjectImpl(out clientHandle, _manager.GetSessionManagerByTag(tag));
+ }
+
+ private Result CloneCurrentObjectImpl(out int clientHandle, ServerSessionManager manager)
+ {
+ clientHandle = 0;
+
+ var clone = _session.ServiceObjectHolder.Clone();
+ if (clone == null)
+ {
+ return HipcResult.DomainObjectNotFound;
+ }
+
+ Api.CreateSession(out int serverHandle, out clientHandle).AbortOnFailure();
+ manager.RegisterSession(serverHandle, clone).AbortOnFailure();
+
+ return Result.Success;
+ }
+ }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcMessage.cs b/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcMessage.cs
new file mode 100644
index 00000000..3017f404
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcMessage.cs
@@ -0,0 +1,222 @@
+using Ryujinx.Common;
+using Ryujinx.Horizon.Sdk.Sf.Cmif;
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.Horizon.Sdk.Sf.Hipc
+{
+ ref struct HipcMessage
+ {
+ public const int AutoReceiveStatic = byte.MaxValue;
+
+ public HipcMetadata Meta;
+ public HipcMessageData Data;
+ public ulong Pid;
+
+ public HipcMessage(Span<byte> data)
+ {
+ int initialLength = data.Length;
+
+ Header header = MemoryMarshal.Cast<byte, Header>(data)[0];
+
+ data = data.Slice(Unsafe.SizeOf<Header>());
+
+ int receiveStaticsCount = 0;
+ ulong pid = 0;
+
+ if (header.ReceiveStaticMode != 0)
+ {
+ if (header.ReceiveStaticMode == 2)
+ {
+ receiveStaticsCount = AutoReceiveStatic;
+ }
+ else if (header.ReceiveStaticMode > 2)
+ {
+ receiveStaticsCount = header.ReceiveStaticMode - 2;
+ }
+ }
+
+ SpecialHeader specialHeader = default;
+
+ if (header.HasSpecialHeader)
+ {
+ specialHeader = MemoryMarshal.Cast<byte, SpecialHeader>(data)[0];
+
+ data = data.Slice(Unsafe.SizeOf<SpecialHeader>());
+
+ if (specialHeader.SendPid)
+ {
+ pid = MemoryMarshal.Cast<byte, ulong>(data)[0];
+
+ data = data.Slice(sizeof(ulong));
+ }
+ }
+
+ Meta = new HipcMetadata()
+ {
+ Type = (int)header.Type,
+ SendStaticsCount = header.SendStaticsCount,
+ SendBuffersCount = header.SendBuffersCount,
+ ReceiveBuffersCount = header.ReceiveBuffersCount,
+ ExchangeBuffersCount = header.ExchangeBuffersCount,
+ DataWordsCount = header.DataWordsCount,
+ ReceiveStaticsCount = receiveStaticsCount,
+ SendPid = specialHeader.SendPid,
+ CopyHandlesCount = specialHeader.CopyHandlesCount,
+ MoveHandlesCount = specialHeader.MoveHandlesCount
+ };
+
+ Data = CreateMessageData(Meta, data, initialLength);
+ Pid = pid;
+ }
+
+ public static HipcMessageData WriteResponse(
+ Span<byte> destination,
+ int sendStaticCount,
+ int dataWordsCount,
+ int copyHandlesCount,
+ int moveHandlesCount)
+ {
+ return WriteMessage(destination, new HipcMetadata()
+ {
+ SendStaticsCount = sendStaticCount,
+ DataWordsCount = dataWordsCount,
+ CopyHandlesCount = copyHandlesCount,
+ MoveHandlesCount = moveHandlesCount
+ });
+ }
+
+ public static HipcMessageData WriteMessage(Span<byte> destination, HipcMetadata meta)
+ {
+ int initialLength = destination.Length;
+
+ bool hasSpecialHeader = meta.SendPid || meta.CopyHandlesCount != 0 || meta.MoveHandlesCount != 0;
+
+ MemoryMarshal.Cast<byte, Header>(destination)[0] = new Header()
+ {
+ Type = (CommandType)meta.Type,
+ SendStaticsCount = meta.SendStaticsCount,
+ SendBuffersCount = meta.SendBuffersCount,
+ ReceiveBuffersCount = meta.ReceiveBuffersCount,
+ ExchangeBuffersCount = meta.ExchangeBuffersCount,
+ DataWordsCount = meta.DataWordsCount,
+ ReceiveStaticMode = meta.ReceiveStaticsCount != 0 ? (meta.ReceiveStaticsCount != AutoReceiveStatic ? meta.ReceiveStaticsCount + 2 : 2) : 0,
+ HasSpecialHeader = hasSpecialHeader
+ };
+
+ destination = destination.Slice(Unsafe.SizeOf<Header>());
+
+ if (hasSpecialHeader)
+ {
+ MemoryMarshal.Cast<byte, SpecialHeader>(destination)[0] = new SpecialHeader()
+ {
+ SendPid = meta.SendPid,
+ CopyHandlesCount = meta.CopyHandlesCount,
+ MoveHandlesCount = meta.MoveHandlesCount
+ };
+
+ destination = destination.Slice(Unsafe.SizeOf<SpecialHeader>());
+
+ if (meta.SendPid)
+ {
+ destination = destination.Slice(sizeof(ulong));
+ }
+ }
+
+ return CreateMessageData(meta, destination, initialLength);
+ }
+
+ private static HipcMessageData CreateMessageData(HipcMetadata meta, Span<byte> data, int initialLength)
+ {
+ Span<int> copyHandles = Span<int>.Empty;
+
+ if (meta.CopyHandlesCount != 0)
+ {
+ copyHandles = MemoryMarshal.Cast<byte, int>(data).Slice(0, meta.CopyHandlesCount);
+
+ data = data.Slice(meta.CopyHandlesCount * sizeof(int));
+ }
+
+ Span<int> moveHandles = Span<int>.Empty;
+
+ if (meta.MoveHandlesCount != 0)
+ {
+ moveHandles = MemoryMarshal.Cast<byte, int>(data).Slice(0, meta.MoveHandlesCount);
+
+ data = data.Slice(meta.MoveHandlesCount * sizeof(int));
+ }
+
+ Span<HipcStaticDescriptor> sendStatics = Span<HipcStaticDescriptor>.Empty;
+
+ if (meta.SendStaticsCount != 0)
+ {
+ sendStatics = MemoryMarshal.Cast<byte, HipcStaticDescriptor>(data).Slice(0, meta.SendStaticsCount);
+
+ data = data.Slice(meta.SendStaticsCount * Unsafe.SizeOf<HipcStaticDescriptor>());
+ }
+
+ Span<HipcBufferDescriptor> sendBuffers = Span<HipcBufferDescriptor>.Empty;
+
+ if (meta.SendBuffersCount != 0)
+ {
+ sendBuffers = MemoryMarshal.Cast<byte, HipcBufferDescriptor>(data).Slice(0, meta.SendBuffersCount);
+
+ data = data.Slice(meta.SendBuffersCount * Unsafe.SizeOf<HipcBufferDescriptor>());
+ }
+
+ Span<HipcBufferDescriptor> receiveBuffers = Span<HipcBufferDescriptor>.Empty;
+
+ if (meta.ReceiveBuffersCount != 0)
+ {
+ receiveBuffers = MemoryMarshal.Cast<byte, HipcBufferDescriptor>(data).Slice(0, meta.ReceiveBuffersCount);
+
+ data = data.Slice(meta.ReceiveBuffersCount * Unsafe.SizeOf<HipcBufferDescriptor>());
+ }
+
+ Span<HipcBufferDescriptor> exchangeBuffers = Span<HipcBufferDescriptor>.Empty;
+
+ if (meta.ExchangeBuffersCount != 0)
+ {
+ exchangeBuffers = MemoryMarshal.Cast<byte, HipcBufferDescriptor>(data).Slice(0, meta.ExchangeBuffersCount);
+
+ data = data.Slice(meta.ExchangeBuffersCount * Unsafe.SizeOf<HipcBufferDescriptor>());
+ }
+
+ Span<uint> dataWords = Span<uint>.Empty;
+
+ if (meta.DataWordsCount != 0)
+ {
+ int dataOffset = initialLength - data.Length;
+ int dataOffsetAligned = BitUtils.AlignUp(dataOffset, 0x10);
+
+ int padding = (dataOffsetAligned - dataOffset) / sizeof(uint);
+
+ dataWords = MemoryMarshal.Cast<byte, uint>(data).Slice(padding, meta.DataWordsCount - padding);
+
+ data = data.Slice(meta.DataWordsCount * sizeof(uint));
+ }
+
+ Span<HipcReceiveListEntry> receiveList = Span<HipcReceiveListEntry>.Empty;
+
+ if (meta.ReceiveStaticsCount != 0)
+ {
+ int receiveListSize = meta.ReceiveStaticsCount == AutoReceiveStatic ? 1 : meta.ReceiveStaticsCount;
+
+ receiveList = MemoryMarshal.Cast<byte, HipcReceiveListEntry>(data).Slice(0, receiveListSize);
+ }
+
+ return new HipcMessageData()
+ {
+ SendStatics = sendStatics,
+ SendBuffers = sendBuffers,
+ ReceiveBuffers = receiveBuffers,
+ ExchangeBuffers = exchangeBuffers,
+ DataWords = dataWords,
+ ReceiveList = receiveList,
+ CopyHandles = copyHandles,
+ MoveHandles = moveHandles
+ };
+ }
+ }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcMessageData.cs b/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcMessageData.cs
new file mode 100644
index 00000000..c83c422c
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcMessageData.cs
@@ -0,0 +1,16 @@
+using System;
+
+namespace Ryujinx.Horizon.Sdk.Sf.Hipc
+{
+ ref struct HipcMessageData
+ {
+ public Span<HipcStaticDescriptor> SendStatics;
+ public Span<HipcBufferDescriptor> SendBuffers;
+ public Span<HipcBufferDescriptor> ReceiveBuffers;
+ public Span<HipcBufferDescriptor> ExchangeBuffers;
+ public Span<uint> DataWords;
+ public Span<HipcReceiveListEntry> ReceiveList;
+ public Span<int> CopyHandles;
+ public Span<int> MoveHandles;
+ }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcMetadata.cs b/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcMetadata.cs
new file mode 100644
index 00000000..fe13137a
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcMetadata.cs
@@ -0,0 +1,16 @@
+namespace Ryujinx.Horizon.Sdk.Sf.Hipc
+{
+ struct HipcMetadata
+ {
+ public int Type;
+ public int SendStaticsCount;
+ public int SendBuffersCount;
+ public int ReceiveBuffersCount;
+ public int ExchangeBuffersCount;
+ public int DataWordsCount;
+ public int ReceiveStaticsCount;
+ public bool SendPid;
+ public int CopyHandlesCount;
+ public int MoveHandlesCount;
+ }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcReceiveListEntry.cs b/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcReceiveListEntry.cs
new file mode 100644
index 00000000..94bf0968
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcReceiveListEntry.cs
@@ -0,0 +1,14 @@
+namespace Ryujinx.Horizon.Sdk.Sf.Hipc
+{
+ struct HipcReceiveListEntry
+ {
+ private uint _addressLow;
+ private uint _word1;
+
+ public HipcReceiveListEntry(ulong address, ulong size)
+ {
+ _addressLow = (uint)address;
+ _word1 = (ushort)(address >> 32) | (uint)(size << 16);
+ }
+ }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcResult.cs b/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcResult.cs
new file mode 100644
index 00000000..ef989a98
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcResult.cs
@@ -0,0 +1,22 @@
+using Ryujinx.Horizon.Common;
+
+namespace Ryujinx.Horizon.Sdk.Sf.Hipc
+{
+ static class HipcResult
+ {
+ public const int ModuleId = 11;
+
+ public static Result OutOfSessionMemory => new Result(ModuleId, 102);
+ public static Result OutOfSessions => new Result(ModuleId, 131);
+ public static Result PointerBufferTooSmall => new Result(ModuleId, 141);
+ public static Result OutOfDomains => new Result(ModuleId, 200);
+
+ public static Result InvalidRequestSize => new Result(ModuleId, 402);
+ public static Result UnknownCommandType => new Result(ModuleId, 403);
+
+ public static Result InvalidCmifRequest => new Result(ModuleId, 420);
+
+ public static Result TargetNotDomain => new Result(ModuleId, 491);
+ public static Result DomainObjectNotFound => new Result(ModuleId, 492);
+ }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcStaticDescriptor.cs b/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcStaticDescriptor.cs
new file mode 100644
index 00000000..5cebf47c
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcStaticDescriptor.cs
@@ -0,0 +1,22 @@
+namespace Ryujinx.Horizon.Sdk.Sf.Hipc
+{
+ struct HipcStaticDescriptor
+ {
+ private readonly ulong _data;
+
+ public ulong Address => ((((_data >> 2) & 0x70) | ((_data >> 12) & 0xf)) << 32) | (_data >> 32);
+ public ushort Size => (ushort)(_data >> 16);
+ public int ReceiveIndex => (int)(_data & 0xf);
+
+ public HipcStaticDescriptor(ulong address, ushort size, int receiveIndex)
+ {
+ ulong data = (uint)(receiveIndex & 0xf) | ((uint)size << 16);
+
+ data |= address << 32;
+ data |= (address >> 20) & 0xf000;
+ data |= (address >> 30) & 0xffc0;
+
+ _data = data;
+ }
+ }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Hipc/ManagerOptions.cs b/Ryujinx.Horizon/Sdk/Sf/Hipc/ManagerOptions.cs
new file mode 100644
index 00000000..e087cb22
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Hipc/ManagerOptions.cs
@@ -0,0 +1,20 @@
+namespace Ryujinx.Horizon.Sdk.Sf.Hipc
+{
+ struct ManagerOptions
+ {
+ public static ManagerOptions Default => new ManagerOptions(0, 0, 0, false);
+
+ public int PointerBufferSize { get; }
+ public int MaxDomains { get; }
+ public int MaxDomainObjects { get; }
+ public bool CanDeferInvokeRequest { get; }
+
+ public ManagerOptions(int pointerBufferSize, int maxDomains, int maxDomainObjects, bool canDeferInvokeRequest)
+ {
+ PointerBufferSize = pointerBufferSize;
+ MaxDomains = maxDomains;
+ MaxDomainObjects = maxDomainObjects;
+ CanDeferInvokeRequest = canDeferInvokeRequest;
+ }
+ }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Hipc/ReceiveResult.cs b/Ryujinx.Horizon/Sdk/Sf/Hipc/ReceiveResult.cs
new file mode 100644
index 00000000..7c380a01
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Hipc/ReceiveResult.cs
@@ -0,0 +1,9 @@
+namespace Ryujinx.Horizon.Sdk.Sf.Hipc
+{
+ enum ReceiveResult
+ {
+ Success,
+ Closed,
+ NeedsRetry
+ }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Hipc/Server.cs b/Ryujinx.Horizon/Sdk/Sf/Hipc/Server.cs
new file mode 100644
index 00000000..923f2d52
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Hipc/Server.cs
@@ -0,0 +1,36 @@
+using Ryujinx.Horizon.Sdk.OsTypes;
+using Ryujinx.Horizon.Sdk.Sf.Cmif;
+using Ryujinx.Horizon.Sdk.Sm;
+
+namespace Ryujinx.Horizon.Sdk.Sf.Hipc
+{
+ class Server : MultiWaitHolderOfHandle
+ {
+ public int PortIndex { get; }
+ public int PortHandle { get; }
+ public ServiceName Name { get; }
+ public bool Managed { get; }
+ public ServiceObjectHolder StaticObject { get; }
+
+ public Server(
+ int portIndex,
+ int portHandle,
+ ServiceName name,
+ bool managed,
+ ServiceObjectHolder staticHoder) : base(portHandle)
+ {
+ PortHandle = portHandle;
+ Name = name;
+ Managed = managed;
+
+ if (staticHoder != null)
+ {
+ StaticObject = staticHoder;
+ }
+ else
+ {
+ PortIndex = portIndex;
+ }
+ }
+ }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Hipc/ServerDomainSessionManager.cs b/Ryujinx.Horizon/Sdk/Sf/Hipc/ServerDomainSessionManager.cs
new file mode 100644
index 00000000..d920a659
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Hipc/ServerDomainSessionManager.cs
@@ -0,0 +1,23 @@
+using Ryujinx.Horizon.Common;
+using Ryujinx.Horizon.Sdk.Sf.Cmif;
+using System;
+
+namespace Ryujinx.Horizon.Sdk.Sf.Hipc
+{
+ class ServerDomainSessionManager : ServerSessionManager
+ {
+ public ServerDomainManager Domain { get; }
+
+ public ServerDomainSessionManager(int entryCount, int maxDomains)
+ {
+ Domain = new ServerDomainManager(entryCount, maxDomains);
+ }
+
+ protected override Result DispatchManagerRequest(ServerSession session, Span<byte> inMessage, Span<byte> outMessage)
+ {
+ HipcManager hipcManager = new HipcManager(this, session);
+
+ return DispatchRequest(new ServiceObjectHolder(hipcManager), session, inMessage, outMessage);
+ }
+ }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Hipc/ServerManager.cs b/Ryujinx.Horizon/Sdk/Sf/Hipc/ServerManager.cs
new file mode 100644
index 00000000..5bb2de25
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Hipc/ServerManager.cs
@@ -0,0 +1,198 @@
+using Ryujinx.Horizon.Sdk.OsTypes;
+using Ryujinx.Horizon.Sdk.Sf.Cmif;
+using Ryujinx.Horizon.Sdk.Sm;
+using System;
+using System.Collections.Generic;
+using System.Numerics;
+
+namespace Ryujinx.Horizon.Sdk.Sf.Hipc
+{
+ class ServerManager : ServerManagerBase, IDisposable
+ {
+ private readonly SmApi _sm;
+ private readonly int _pointerBufferSize;
+ private readonly bool _canDeferInvokeRequest;
+ private readonly int _maxSessions;
+
+ private ulong _pointerBuffersBaseAddress;
+ private ulong _savedMessagesBaseAddress;
+
+ private readonly object _resourceLock;
+ private readonly ulong[] _sessionAllocationBitmap;
+ private readonly HashSet<ServerSession> _sessions;
+ private readonly HashSet<Server> _servers;
+
+ public ServerManager(HeapAllocator allocator, SmApi sm, int maxPorts, ManagerOptions options, int maxSessions) : base(sm, options)
+ {
+ _sm = sm;
+ _pointerBufferSize = options.PointerBufferSize;
+ _canDeferInvokeRequest = options.CanDeferInvokeRequest;
+ _maxSessions = maxSessions;
+
+ if (allocator != null)
+ {
+ _pointerBuffersBaseAddress = allocator.Allocate((ulong)maxSessions * (ulong)options.PointerBufferSize);
+
+ if (options.CanDeferInvokeRequest)
+ {
+ _savedMessagesBaseAddress = allocator.Allocate((ulong)maxSessions * (ulong)Api.TlsMessageBufferSize);
+ }
+ }
+
+ _resourceLock = new object();
+ _sessionAllocationBitmap = new ulong[(maxSessions + 63) / 64];
+ _sessions = new HashSet<ServerSession>();
+ _servers = new HashSet<Server>();
+ }
+
+ private PointerAndSize GetObjectBySessionIndex(ServerSession session, ulong baseAddress, ulong size)
+ {
+ return new PointerAndSize(baseAddress + (ulong)session.SessionIndex * size, size);
+ }
+
+ protected override ServerSession AllocateSession(int sessionHandle, ServiceObjectHolder obj)
+ {
+ int sessionIndex = -1;
+
+ lock (_resourceLock)
+ {
+ if (_sessions.Count >= _maxSessions)
+ {
+ return null;
+ }
+
+ for (int i = 0; i <_sessionAllocationBitmap.Length; i++)
+ {
+ ref ulong mask = ref _sessionAllocationBitmap[i];
+
+ if (mask != ulong.MaxValue)
+ {
+ int bit = BitOperations.TrailingZeroCount(~mask);
+ sessionIndex = i * 64 + bit;
+ mask |= 1UL << bit;
+
+ break;
+ }
+ }
+
+ if (sessionIndex == -1)
+ {
+ return null;
+ }
+
+ ServerSession session = new ServerSession(sessionIndex, sessionHandle, obj);
+
+ _sessions.Add(session);
+
+ return session;
+ }
+ }
+
+ protected override void FreeSession(ServerSession session)
+ {
+ if (session.ServiceObjectHolder.ServiceObject is IDisposable disposableObj)
+ {
+ disposableObj.Dispose();
+ }
+
+ lock (_resourceLock)
+ {
+ _sessionAllocationBitmap[session.SessionIndex / 64] &= ~(1UL << (session.SessionIndex & 63));
+ _sessions.Remove(session);
+ }
+ }
+
+ protected override Server AllocateServer(
+ int portIndex,
+ int portHandle,
+ ServiceName name,
+ bool managed,
+ ServiceObjectHolder staticHoder)
+ {
+ lock (_resourceLock)
+ {
+ Server server = new Server(portIndex, portHandle, name, managed, staticHoder);
+
+ _servers.Add(server);
+
+ return server;
+ }
+ }
+
+ protected override void DestroyServer(Server server)
+ {
+ lock (_resourceLock)
+ {
+ server.UnlinkFromMultiWaitHolder();
+ Os.FinalizeMultiWaitHolder(server);
+
+ if (server.Managed)
+ {
+ // We should AbortOnFailure, but sometimes SM is already gone when this is called,
+ // so let's just ignore potential errors.
+ _sm.UnregisterService(server.Name);
+
+ HorizonStatic.Syscall.CloseHandle(server.PortHandle);
+ }
+
+ _servers.Remove(server);
+ }
+ }
+
+ protected override PointerAndSize GetSessionPointerBuffer(ServerSession session)
+ {
+ if (_pointerBufferSize > 0)
+ {
+ return GetObjectBySessionIndex(session, _pointerBuffersBaseAddress, (ulong)_pointerBufferSize);
+ }
+ else
+ {
+ return PointerAndSize.Empty;
+ }
+ }
+
+ protected override PointerAndSize GetSessionSavedMessageBuffer(ServerSession session)
+ {
+ if (_canDeferInvokeRequest)
+ {
+ return GetObjectBySessionIndex(session, _savedMessagesBaseAddress, Api.TlsMessageBufferSize);
+ }
+ else
+ {
+ return PointerAndSize.Empty;
+ }
+ }
+
+ protected virtual void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ lock (_resourceLock)
+ {
+ ServerSession[] sessionsToClose = new ServerSession[_sessions.Count];
+
+ _sessions.CopyTo(sessionsToClose);
+
+ foreach (ServerSession session in sessionsToClose)
+ {
+ CloseSessionImpl(session);
+ }
+
+ Server[] serversToClose = new Server[_servers.Count];
+
+ _servers.CopyTo(serversToClose);
+
+ foreach (Server server in serversToClose)
+ {
+ DestroyServer(server);
+ }
+ }
+ }
+ }
+
+ public void Dispose()
+ {
+ Dispose(true);
+ }
+ }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Hipc/ServerManagerBase.cs b/Ryujinx.Horizon/Sdk/Sf/Hipc/ServerManagerBase.cs
new file mode 100644
index 00000000..68cae6bc
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Hipc/ServerManagerBase.cs
@@ -0,0 +1,307 @@
+using Ryujinx.Horizon.Sdk.OsTypes;
+using Ryujinx.Horizon.Common;
+using Ryujinx.Horizon.Sdk.Sf.Cmif;
+using Ryujinx.Horizon.Sdk.Sm;
+using System;
+
+namespace Ryujinx.Horizon.Sdk.Sf.Hipc
+{
+ class ServerManagerBase : ServerDomainSessionManager
+ {
+ private readonly SmApi _sm;
+
+ private bool _canDeferInvokeRequest;
+
+ private readonly MultiWait _multiWait;
+ private readonly MultiWait _waitList;
+
+ private readonly object _multiWaitSelectionLock;
+ private readonly object _waitListLock;
+
+ private readonly Event _requestStopEvent;
+ private readonly Event _notifyEvent;
+
+ private readonly MultiWaitHolderBase _requestStopEventHolder;
+ private readonly MultiWaitHolderBase _notifyEventHolder;
+
+ private enum UserDataTag
+ {
+ Server = 1,
+ Session = 2
+ }
+
+ public ServerManagerBase(SmApi sm, ManagerOptions options) : base(options.MaxDomainObjects, options.MaxDomains)
+ {
+ _sm = sm;
+ _canDeferInvokeRequest = options.CanDeferInvokeRequest;
+
+ _multiWait = new MultiWait();
+ _waitList = new MultiWait();
+
+ _multiWaitSelectionLock = new object();
+ _waitListLock = new object();
+
+ _requestStopEvent = new Event(EventClearMode.ManualClear);
+ _notifyEvent = new Event(EventClearMode.ManualClear);
+
+ _requestStopEventHolder = new MultiWaitHolderOfEvent(_requestStopEvent);
+ _multiWait.LinkMultiWaitHolder(_requestStopEventHolder);
+ _notifyEventHolder = new MultiWaitHolderOfEvent(_notifyEvent);
+ _multiWait.LinkMultiWaitHolder(_notifyEventHolder);
+ }
+
+ public void RegisterObjectForServer(IServiceObject staticObject, int portHandle)
+ {
+ RegisterServerImpl(0, new ServiceObjectHolder(staticObject), portHandle);
+ }
+
+ public Result RegisterObjectForServer(IServiceObject staticObject, ServiceName name, int maxSessions)
+ {
+ return RegisterServerImpl(0, new ServiceObjectHolder(staticObject), name, maxSessions);
+ }
+
+ public void RegisterServer(int portIndex, int portHandle)
+ {
+ RegisterServerImpl(portIndex, null, portHandle);
+ }
+
+ public Result RegisterServer(int portIndex, ServiceName name, int maxSessions)
+ {
+ return RegisterServerImpl(portIndex, null, name, maxSessions);
+ }
+
+ private void RegisterServerImpl(int portIndex, ServiceObjectHolder staticHolder, int portHandle)
+ {
+ Server server = AllocateServer(portIndex, portHandle, ServiceName.Invalid, managed: false, staticHolder);
+ RegisterServerImpl(server);
+ }
+
+ private Result RegisterServerImpl(int portIndex, ServiceObjectHolder staticHolder, ServiceName name, int maxSessions)
+ {
+ Result result = _sm.RegisterService(out int portHandle, name, maxSessions, isLight: false);
+
+ if (result.IsFailure)
+ {
+ return result;
+ }
+
+ Server server = AllocateServer(portIndex, portHandle, name, managed: true, staticHolder);
+ RegisterServerImpl(server);
+
+ return Result.Success;
+ }
+
+ private void RegisterServerImpl(Server server)
+ {
+ server.UserData = UserDataTag.Server;
+
+ _multiWait.LinkMultiWaitHolder(server);
+ }
+
+ protected virtual Result OnNeedsToAccept(int portIndex, Server server)
+ {
+ throw new NotSupportedException();
+ }
+
+ public void ServiceRequests()
+ {
+ while (WaitAndProcessRequestsImpl());
+ }
+
+ public void WaitAndProcessRequests()
+ {
+ WaitAndProcessRequestsImpl();
+ }
+
+ private bool WaitAndProcessRequestsImpl()
+ {
+ try
+ {
+ MultiWaitHolder multiWait = WaitSignaled();
+
+ if (multiWait == null)
+ {
+ return false;
+ }
+
+ DebugUtil.Assert(Process(multiWait).IsSuccess);
+
+ return HorizonStatic.ThreadContext.Running;
+ }
+ catch (ThreadTerminatedException)
+ {
+ return false;
+ }
+ }
+
+ private MultiWaitHolder WaitSignaled()
+ {
+ lock (_multiWaitSelectionLock)
+ {
+ while (true)
+ {
+ ProcessWaitList();
+
+ MultiWaitHolder selected = _multiWait.WaitAny();
+
+ if (selected == _requestStopEventHolder)
+ {
+ return null;
+ }
+ else if (selected == _notifyEventHolder)
+ {
+ _notifyEvent.Clear();
+ }
+ else
+ {
+ selected.UnlinkFromMultiWaitHolder();
+
+ return selected;
+ }
+ }
+ }
+ }
+
+ public void ResumeProcessing()
+ {
+ _requestStopEvent.Clear();
+ }
+
+ public void RequestStopProcessing()
+ {
+ _requestStopEvent.Signal();
+ }
+
+ protected override void RegisterSessionToWaitList(ServerSession session)
+ {
+ session.HasReceived = false;
+ session.UserData = UserDataTag.Session;
+ RegisterToWaitList(session);
+ }
+
+ private void RegisterToWaitList(MultiWaitHolder holder)
+ {
+ lock (_waitListLock)
+ {
+ _waitList.LinkMultiWaitHolder(holder);
+ _notifyEvent.Signal();
+ }
+ }
+
+ private void ProcessWaitList()
+ {
+ lock (_waitListLock)
+ {
+ _multiWait.MoveAllFrom(_waitList);
+ }
+ }
+
+ private Result Process(MultiWaitHolder holder)
+ {
+ switch ((UserDataTag)holder.UserData)
+ {
+ case UserDataTag.Server:
+ return ProcessForServer(holder);
+ case UserDataTag.Session:
+ return ProcessForSession(holder);
+ default:
+ throw new NotImplementedException(((UserDataTag)holder.UserData).ToString());
+ }
+ }
+
+ private Result ProcessForServer(MultiWaitHolder holder)
+ {
+ DebugUtil.Assert((UserDataTag)holder.UserData == UserDataTag.Server);
+
+ Server server = (Server)holder;
+
+ try
+ {
+ if (server.StaticObject != null)
+ {
+ return AcceptSession(server.PortHandle, server.StaticObject.Clone());
+ }
+ else
+ {
+ return OnNeedsToAccept(server.PortIndex, server);
+ }
+ }
+ finally
+ {
+ RegisterToWaitList(server);
+ }
+ }
+
+ private Result ProcessForSession(MultiWaitHolder holder)
+ {
+ DebugUtil.Assert((UserDataTag)holder.UserData == UserDataTag.Session);
+
+ ServerSession session = (ServerSession)holder;
+
+ using var tlsMessage = HorizonStatic.AddressSpace.GetWritableRegion(HorizonStatic.ThreadContext.TlsAddress, Api.TlsMessageBufferSize);
+
+ Result result;
+
+ if (_canDeferInvokeRequest)
+ {
+ // If the request is deferred, we save the message on a temporary buffer to process it later.
+ using var savedMessage = HorizonStatic.AddressSpace.GetWritableRegion(session.SavedMessage.Address, (int)session.SavedMessage.Size);
+
+ DebugUtil.Assert(tlsMessage.Memory.Length == savedMessage.Memory.Length);
+
+ if (!session.HasReceived)
+ {
+ result = ReceiveRequest(session, tlsMessage.Memory.Span);
+
+ if (result.IsFailure)
+ {
+ return result;
+ }
+
+ session.HasReceived = true;
+ tlsMessage.Memory.Span.CopyTo(savedMessage.Memory.Span);
+ }
+ else
+ {
+ savedMessage.Memory.Span.CopyTo(tlsMessage.Memory.Span);
+ }
+
+ result = ProcessRequest(session, tlsMessage.Memory.Span);
+
+ if (result.IsFailure && !SfResult.Invalidated(result))
+ {
+ return result;
+ }
+ }
+ else
+ {
+ if (!session.HasReceived)
+ {
+ result = ReceiveRequest(session, tlsMessage.Memory.Span);
+
+ if (result.IsFailure)
+ {
+ return result;
+ }
+
+ session.HasReceived = true;
+ }
+
+ result = ProcessRequest(session, tlsMessage.Memory.Span);
+
+ if (result.IsFailure)
+ {
+ // Those results are not valid because the service does not support deferral.
+ if (SfResult.RequestDeferred(result) || SfResult.Invalidated(result))
+ {
+ result.AbortOnFailure();
+ }
+
+ return result;
+ }
+ }
+
+ return Result.Success;
+ }
+ }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Hipc/ServerSession.cs b/Ryujinx.Horizon/Sdk/Sf/Hipc/ServerSession.cs
new file mode 100644
index 00000000..eb98fefd
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Hipc/ServerSession.cs
@@ -0,0 +1,23 @@
+using Ryujinx.Horizon.Sdk.OsTypes;
+using Ryujinx.Horizon.Sdk.Sf.Cmif;
+
+namespace Ryujinx.Horizon.Sdk.Sf.Hipc
+{
+ class ServerSession : MultiWaitHolderOfHandle
+ {
+ public ServiceObjectHolder ServiceObjectHolder { get; set; }
+ public PointerAndSize PointerBuffer { get; set; }
+ public PointerAndSize SavedMessage { get; set; }
+ public int SessionIndex { get; }
+ public int SessionHandle { get; }
+ public bool IsClosed { get; set; }
+ public bool HasReceived { get; set; }
+
+ public ServerSession(int index, int handle, ServiceObjectHolder obj) : base(handle)
+ {
+ ServiceObjectHolder = obj;
+ SessionIndex = index;
+ SessionHandle = handle;
+ }
+ }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Hipc/ServerSessionManager.cs b/Ryujinx.Horizon/Sdk/Sf/Hipc/ServerSessionManager.cs
new file mode 100644
index 00000000..e85892f2
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Hipc/ServerSessionManager.cs
@@ -0,0 +1,335 @@
+using Ryujinx.Common.Logging;
+using Ryujinx.Horizon.Common;
+using Ryujinx.Horizon.Sdk.OsTypes;
+using Ryujinx.Horizon.Sdk.Sf.Cmif;
+using Ryujinx.Horizon.Sdk.Sm;
+using System;
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.Horizon.Sdk.Sf.Hipc
+{
+ class ServerSessionManager
+ {
+ public Result AcceptSession(int portHandle, ServiceObjectHolder obj)
+ {
+ return AcceptSession(out _, portHandle, obj);
+ }
+
+ private Result AcceptSession(out ServerSession session, int portHandle, ServiceObjectHolder obj)
+ {
+ return AcceptSessionImpl(out session, portHandle, obj);
+ }
+
+ private Result AcceptSessionImpl(out ServerSession session, int portHandle, ServiceObjectHolder obj)
+ {
+ session = null;
+
+ Result result = HorizonStatic.Syscall.AcceptSession(out int sessionHandle, portHandle);
+
+ if (result.IsFailure)
+ {
+ return result;
+ }
+
+ bool succeeded = false;
+
+ try
+ {
+ result = RegisterSessionImpl(out session, sessionHandle, obj);
+
+ if (result.IsFailure)
+ {
+ return result;
+ }
+
+ succeeded = true;
+ }
+ finally
+ {
+ if (!succeeded)
+ {
+ HorizonStatic.Syscall.CloseHandle(sessionHandle);
+ }
+ }
+
+ return Result.Success;
+ }
+
+ public Result RegisterSession(int sessionHandle, ServiceObjectHolder obj)
+ {
+ return RegisterSession(out _, sessionHandle, obj);
+ }
+
+ public Result RegisterSession(out ServerSession session, int sessionHandle, ServiceObjectHolder obj)
+ {
+ return RegisterSessionImpl(out session, sessionHandle, obj);
+ }
+
+ private Result RegisterSessionImpl(out ServerSession session, int sessionHandle, ServiceObjectHolder obj)
+ {
+ Result result = CreateSessionImpl(out session, sessionHandle, obj);
+
+ if (result.IsFailure)
+ {
+ return result;
+ }
+
+ session.PointerBuffer = GetSessionPointerBuffer(session);
+ session.SavedMessage = GetSessionSavedMessageBuffer(session);
+
+ RegisterSessionToWaitList(session);
+ return Result.Success;
+ }
+
+ protected virtual void RegisterSessionToWaitList(ServerSession session)
+ {
+ throw new NotSupportedException();
+ }
+
+ private Result CreateSessionImpl(out ServerSession session, int sessionHandle, ServiceObjectHolder obj)
+ {
+ session = AllocateSession(sessionHandle, obj);
+
+ if (session == null)
+ {
+ return HipcResult.OutOfSessionMemory;
+ }
+
+ return Result.Success;
+ }
+
+ protected virtual ServerSession AllocateSession(int sessionHandle, ServiceObjectHolder obj)
+ {
+ throw new NotSupportedException();
+ }
+
+ protected virtual void FreeSession(ServerSession session)
+ {
+ throw new NotSupportedException();
+ }
+
+ protected virtual Server AllocateServer(
+ int portIndex,
+ int portHandle,
+ ServiceName name,
+ bool managed,
+ ServiceObjectHolder staticHoder)
+ {
+ throw new NotSupportedException();
+ }
+
+ protected virtual void DestroyServer(Server server)
+ {
+ throw new NotSupportedException();
+ }
+
+ protected virtual PointerAndSize GetSessionPointerBuffer(ServerSession session)
+ {
+ throw new NotSupportedException();
+ }
+
+ protected virtual PointerAndSize GetSessionSavedMessageBuffer(ServerSession session)
+ {
+ throw new NotSupportedException();
+ }
+
+ private void DestroySession(ServerSession session)
+ {
+ FreeSession(session);
+ }
+
+ protected void CloseSessionImpl(ServerSession session)
+ {
+ int sessionHandle = session.Handle;
+ Os.FinalizeMultiWaitHolder(session);
+ DestroySession(session);
+ HorizonStatic.Syscall.CloseHandle(sessionHandle).AbortOnFailure();
+ }
+
+ private static CommandType GetCmifCommandType(ReadOnlySpan<byte> message)
+ {
+ return MemoryMarshal.Cast<byte, Header>(message)[0].Type;
+ }
+
+ public Result ProcessRequest(ServerSession session, Span<byte> message)
+ {
+ if (session.IsClosed || GetCmifCommandType(message) == CommandType.Close)
+ {
+ CloseSessionImpl(session);
+ return Result.Success;
+ }
+ else
+ {
+ Result result = ProcessRequestImpl(session, message, message);
+
+ if (result.IsSuccess)
+ {
+ RegisterSessionToWaitList(session);
+ return Result.Success;
+ }
+ else if (SfResult.RequestContextChanged(result))
+ {
+ return result;
+ }
+ else
+ {
+ Logger.Warning?.Print(LogClass.KernelIpc, $"Request processing returned error {result}");
+
+ CloseSessionImpl(session);
+ return Result.Success;
+ }
+ }
+ }
+
+ private Result ProcessRequestImpl(ServerSession session, Span<byte> inMessage, Span<byte> outMessage)
+ {
+ CommandType commandType = GetCmifCommandType(inMessage);
+
+ using var _ = new ScopedInlineContextChange(GetInlineContext(commandType, inMessage));
+
+ switch (commandType)
+ {
+ case CommandType.Request:
+ case CommandType.RequestWithContext:
+ return DispatchRequest(session.ServiceObjectHolder, session, inMessage, outMessage);
+ case CommandType.Control:
+ case CommandType.ControlWithContext:
+ return DispatchManagerRequest(session, inMessage, outMessage);
+ default:
+ return HipcResult.UnknownCommandType;
+ }
+ }
+
+ private static int GetInlineContext(CommandType commandType, ReadOnlySpan<byte> inMessage)
+ {
+ switch (commandType)
+ {
+ case CommandType.RequestWithContext:
+ case CommandType.ControlWithContext:
+ if (inMessage.Length >= 0x10)
+ {
+ return MemoryMarshal.Cast<byte, int>(inMessage)[3];
+ }
+ break;
+ }
+
+ return 0;
+ }
+
+ protected Result ReceiveRequest(ServerSession session, Span<byte> message)
+ {
+ return ReceiveRequestImpl(session, message);
+ }
+
+ private Result ReceiveRequestImpl(ServerSession session, Span<byte> message)
+ {
+ PointerAndSize pointerBuffer = session.PointerBuffer;
+
+ while (true)
+ {
+ if (pointerBuffer.Address != 0)
+ {
+ HipcMessageData messageData = HipcMessage.WriteMessage(message, new HipcMetadata()
+ {
+ Type = (int)CommandType.Invalid,
+ ReceiveStaticsCount = HipcMessage.AutoReceiveStatic
+ });
+
+ messageData.ReceiveList[0] = new HipcReceiveListEntry(pointerBuffer.Address, pointerBuffer.Size);
+ }
+ else
+ {
+ MemoryMarshal.Cast<byte, Header>(message)[0] = new Header()
+ {
+ Type = CommandType.Invalid
+ };
+ }
+
+ Result result = Api.Receive(out ReceiveResult recvResult, session.Handle, message);
+
+ if (result.IsFailure)
+ {
+ return result;
+ }
+
+ switch (recvResult)
+ {
+ case ReceiveResult.Success:
+ session.IsClosed = false;
+ return Result.Success;
+ case ReceiveResult.Closed:
+ session.IsClosed = true;
+ return Result.Success;
+ }
+ }
+ }
+
+ protected virtual Result DispatchManagerRequest(ServerSession session, Span<byte> inMessage, Span<byte> outMessage)
+ {
+ return SfResult.NotSupported;
+ }
+
+ protected virtual Result DispatchRequest(
+ ServiceObjectHolder objectHolder,
+ ServerSession session,
+ Span<byte> inMessage,
+ Span<byte> outMessage)
+ {
+ HipcMessage request;
+
+ try
+ {
+ request = new HipcMessage(inMessage);
+ }
+ catch (ArgumentOutOfRangeException)
+ {
+ return HipcResult.InvalidRequestSize;
+ }
+
+ var dispatchCtx = new ServiceDispatchContext()
+ {
+ ServiceObject = objectHolder.ServiceObject,
+ Manager = this,
+ Session = session,
+ HandlesToClose = new HandlesToClose(),
+ PointerBuffer = session.PointerBuffer,
+ InMessageBuffer = inMessage,
+ OutMessageBuffer = outMessage,
+ Request = request
+ };
+
+ ReadOnlySpan<byte> inRawData = MemoryMarshal.Cast<uint, byte>(dispatchCtx.Request.Data.DataWords);
+
+ int inRawSize = dispatchCtx.Request.Meta.DataWordsCount * sizeof(uint);
+
+ if (inRawSize < 0x10)
+ {
+ return HipcResult.InvalidRequestSize;
+ }
+
+ Result result = objectHolder.ProcessMessage(ref dispatchCtx, inRawData);
+
+ if (result.IsFailure)
+ {
+ return result;
+ }
+
+ result = Api.Reply(session.SessionHandle, outMessage);
+
+ ref var handlesToClose = ref dispatchCtx.HandlesToClose;
+
+ for (int i = 0; i < handlesToClose.Count; i++)
+ {
+ HorizonStatic.Syscall.CloseHandle(handlesToClose[i]).AbortOnFailure();
+ }
+
+ return result;
+ }
+
+ public ServerSessionManager GetSessionManagerByTag(uint tag)
+ {
+ // Official FW does not do anything with the tag currently.
+ return this;
+ }
+ }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/Hipc/SpecialHeader.cs b/Ryujinx.Horizon/Sdk/Sf/Hipc/SpecialHeader.cs
new file mode 100644
index 00000000..8b747626
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/Hipc/SpecialHeader.cs
@@ -0,0 +1,27 @@
+using Ryujinx.Common.Utilities;
+
+namespace Ryujinx.Horizon.Sdk.Sf.Hipc
+{
+ struct SpecialHeader
+ {
+ private uint _word;
+
+ public bool SendPid
+ {
+ get => _word.Extract(0);
+ set => _word = _word.Insert(0, value);
+ }
+
+ public int CopyHandlesCount
+ {
+ get => (int)_word.Extract(1, 4);
+ set => _word = _word.Insert(1, 4, (uint)value);
+ }
+
+ public int MoveHandlesCount
+ {
+ get => (int)_word.Extract(5, 4);
+ set => _word = _word.Insert(5, 4, (uint)value);
+ }
+ }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/HipcCommandProcessor.cs b/Ryujinx.Horizon/Sdk/Sf/HipcCommandProcessor.cs
new file mode 100644
index 00000000..53202ede
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/HipcCommandProcessor.cs
@@ -0,0 +1,421 @@
+using Ryujinx.Common;
+using Ryujinx.Horizon.Common;
+using Ryujinx.Horizon.Sdk.Sf.Cmif;
+using Ryujinx.Horizon.Sdk.Sf.Hipc;
+using System;
+using System.Linq;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.Horizon.Sdk.Sf
+{
+ class HipcCommandProcessor : ServerMessageProcessor
+ {
+ private readonly CommandArg[] _args;
+
+ private readonly int[] _inOffsets;
+ private readonly int[] _outOffsets;
+ private readonly PointerAndSize[] _bufferRanges;
+
+ private readonly bool _hasInProcessIdHolder;
+ private readonly int _inObjectsCount;
+ private readonly int _outObjectsCount;
+ private readonly int _inMapAliasBuffersCount;
+ private readonly int _outMapAliasBuffersCount;
+ private readonly int _inPointerBuffersCount;
+ private readonly int _outPointerBuffersCount;
+ private readonly int _outFixedSizePointerBuffersCount;
+ private readonly int _inMoveHandlesCount;
+ private readonly int _inCopyHandlesCount;
+ private readonly int _outMoveHandlesCount;
+ private readonly int _outCopyHandlesCount;
+
+ public int FunctionArgumentsCount => _args.Length;
+
+ public int InRawDataSize => BitUtils.AlignUp(_inOffsets[^1], sizeof(ushort));
+ public int OutRawDataSize => BitUtils.AlignUp(_outOffsets[^1], sizeof(uint));
+
+ private int OutUnfixedSizePointerBuffersCount => _outPointerBuffersCount - _outFixedSizePointerBuffersCount;
+
+ public HipcCommandProcessor(CommandArg[] args)
+ {
+ _args = args;
+
+ for (int i = 0; i < args.Length; i++)
+ {
+ var argInfo = args[i];
+
+ switch (argInfo.Type)
+ {
+ case CommandArgType.Buffer:
+ var flags = argInfo.BufferFlags;
+
+ if (flags.HasFlag(HipcBufferFlags.In))
+ {
+ if (flags.HasFlag(HipcBufferFlags.AutoSelect))
+ {
+ _inMapAliasBuffersCount++;
+ _inPointerBuffersCount++;
+ }
+ else if (flags.HasFlag(HipcBufferFlags.MapAlias))
+ {
+ _inMapAliasBuffersCount++;
+ }
+ else if (flags.HasFlag(HipcBufferFlags.Pointer))
+ {
+ _inPointerBuffersCount++;
+ }
+ }
+ else
+ {
+ bool autoSelect = flags.HasFlag(HipcBufferFlags.AutoSelect);
+ if (autoSelect || flags.HasFlag(HipcBufferFlags.Pointer))
+ {
+ _outPointerBuffersCount++;
+
+ if (flags.HasFlag(HipcBufferFlags.FixedSize))
+ {
+ _outFixedSizePointerBuffersCount++;
+ }
+ }
+
+ if (autoSelect || flags.HasFlag(HipcBufferFlags.MapAlias))
+ {
+ _outMapAliasBuffersCount++;
+ }
+ }
+ break;
+ case CommandArgType.InCopyHandle:
+ _inCopyHandlesCount++;
+ break;
+ case CommandArgType.InMoveHandle:
+ _inMoveHandlesCount++;
+ break;
+ case CommandArgType.InObject:
+ _inObjectsCount++;
+ break;
+ case CommandArgType.ProcessId:
+ _hasInProcessIdHolder = true;
+ break;
+ case CommandArgType.OutCopyHandle:
+ _outCopyHandlesCount++;
+ break;
+ case CommandArgType.OutMoveHandle:
+ _outMoveHandlesCount++;
+ break;
+ case CommandArgType.OutObject:
+ _outObjectsCount++;
+ break;
+ }
+ }
+
+ _inOffsets = RawDataOffsetCalculator.Calculate(args.Where(x => x.Type == CommandArgType.InArgument).ToArray());
+ _outOffsets = RawDataOffsetCalculator.Calculate(args.Where(x => x.Type == CommandArgType.OutArgument).ToArray());
+ _bufferRanges = new PointerAndSize[args.Length];
+ }
+
+ public int GetInArgOffset(int argIndex)
+ {
+ return _inOffsets[argIndex];
+ }
+
+ public int GetOutArgOffset(int argIndex)
+ {
+ return _outOffsets[argIndex];
+ }
+
+ public PointerAndSize GetBufferRange(int argIndex)
+ {
+ return _bufferRanges[argIndex];
+ }
+
+ public Result ProcessBuffers(ref ServiceDispatchContext context, bool[] isBufferMapAlias, ServerMessageRuntimeMetadata runtimeMetadata)
+ {
+ bool mapAliasBuffersValid = true;
+
+ ulong pointerBufferTail = context.PointerBuffer.Address;
+ ulong pointerBufferHead = pointerBufferTail + context.PointerBuffer.Size;
+
+ int sendMapAliasIndex = 0;
+ int recvMapAliasIndex = 0;
+ int sendPointerIndex = 0;
+ int unfixedRecvPointerIndex = 0;
+
+ for (int i = 0; i < _args.Length; i++)
+ {
+ if (_args[i].Type != CommandArgType.Buffer)
+ {
+ continue;
+ }
+
+ var flags = _args[i].BufferFlags;
+ bool isMapAlias;
+
+ if (flags.HasFlag(HipcBufferFlags.MapAlias))
+ {
+ isMapAlias = true;
+ }
+ else if (flags.HasFlag(HipcBufferFlags.Pointer))
+ {
+ isMapAlias = false;
+ }
+ else /* if (flags.HasFlag(HipcBufferFlags.HipcAutoSelect)) */
+ {
+ var descriptor = flags.HasFlag(HipcBufferFlags.In)
+ ? context.Request.Data.SendBuffers[sendMapAliasIndex]
+ : context.Request.Data.ReceiveBuffers[recvMapAliasIndex];
+
+ isMapAlias = descriptor.Address != 0UL;
+ }
+
+ isBufferMapAlias[i] = isMapAlias;
+
+ if (isMapAlias)
+ {
+ var descriptor = flags.HasFlag(HipcBufferFlags.In)
+ ? context.Request.Data.SendBuffers[sendMapAliasIndex++]
+ : context.Request.Data.ReceiveBuffers[recvMapAliasIndex++];
+
+ _bufferRanges[i] = new PointerAndSize(descriptor.Address, descriptor.Size);
+
+ if (!IsMapTransferModeValid(flags, descriptor.Mode))
+ {
+ mapAliasBuffersValid = false;
+ }
+ }
+ else
+ {
+ if (flags.HasFlag(HipcBufferFlags.In))
+ {
+ var descriptor = context.Request.Data.SendStatics[sendPointerIndex++];
+ ulong address = descriptor.Address;
+ ulong size = descriptor.Size;
+ _bufferRanges[i] = new PointerAndSize(address, size);
+
+ if (size != 0)
+ {
+ pointerBufferTail = Math.Max(pointerBufferTail, address + size);
+ }
+ }
+ else /* if (flags.HasFlag(HipcBufferFlags.Out)) */
+ {
+ ulong size;
+
+ if (flags.HasFlag(HipcBufferFlags.FixedSize))
+ {
+ size = _args[i].BufferFixedSize;
+ }
+ else
+ {
+ var data = MemoryMarshal.Cast<uint, byte>(context.Request.Data.DataWords);
+ var recvPointerSizes = MemoryMarshal.Cast<byte, ushort>(data.Slice(runtimeMetadata.UnfixedOutPointerSizeOffset));
+ size = recvPointerSizes[unfixedRecvPointerIndex++];
+ }
+
+ pointerBufferHead = BitUtils.AlignDown(pointerBufferHead - size, 0x10UL);
+ _bufferRanges[i] = new PointerAndSize(pointerBufferHead, size);
+ }
+ }
+ }
+
+ if (!mapAliasBuffersValid)
+ {
+ return HipcResult.InvalidCmifRequest;
+ }
+
+ if (_outPointerBuffersCount != 0 && pointerBufferTail > pointerBufferHead)
+ {
+ return HipcResult.PointerBufferTooSmall;
+ }
+
+ return Result.Success;
+ }
+
+ private static bool IsMapTransferModeValid(HipcBufferFlags flags, HipcBufferMode mode)
+ {
+ if (flags.HasFlag(HipcBufferFlags.MapTransferAllowsNonSecure))
+ {
+ return mode == HipcBufferMode.NonSecure;
+ }
+ else if (flags.HasFlag(HipcBufferFlags.MapTransferAllowsNonDevice))
+ {
+ return mode == HipcBufferMode.NonDevice;
+ }
+ else
+ {
+ return mode == HipcBufferMode.Normal;
+ }
+ }
+
+ public void SetOutBuffers(HipcMessageData response, bool[] isBufferMapAlias)
+ {
+ int recvPointerIndex = 0;
+
+ for (int i = 0; i < _args.Length; i++)
+ {
+ if (_args[i].Type != CommandArgType.Buffer)
+ {
+ continue;
+ }
+
+ var flags = _args[i].BufferFlags;
+ if (flags.HasFlag(HipcBufferFlags.Out))
+ {
+ var buffer = _bufferRanges[i];
+
+ if (flags.HasFlag(HipcBufferFlags.Pointer))
+ {
+ response.SendStatics[recvPointerIndex] = new HipcStaticDescriptor(buffer.Address, (ushort)buffer.Size, recvPointerIndex);
+ }
+ else if (flags.HasFlag(HipcBufferFlags.AutoSelect))
+ {
+ if (!isBufferMapAlias[i])
+ {
+ response.SendStatics[recvPointerIndex] = new HipcStaticDescriptor(buffer.Address, (ushort)buffer.Size, recvPointerIndex);
+ }
+ else
+ {
+ response.SendStatics[recvPointerIndex] = new HipcStaticDescriptor(0UL, 0, recvPointerIndex);
+ }
+ }
+
+ recvPointerIndex++;
+ }
+ }
+ }
+
+ public override void SetImplementationProcessor(ServerMessageProcessor impl)
+ {
+ // We don't need to do anything here as this should be always the last processor to be called.
+ }
+
+ public override ServerMessageRuntimeMetadata GetRuntimeMetadata()
+ {
+ return new ServerMessageRuntimeMetadata(
+ (ushort)InRawDataSize,
+ (ushort)OutRawDataSize,
+ (byte)Unsafe.SizeOf<CmifInHeader>(),
+ (byte)Unsafe.SizeOf<CmifOutHeader>(),
+ (byte)_inObjectsCount,
+ (byte)_outObjectsCount);
+ }
+
+ public override Result PrepareForProcess(ref ServiceDispatchContext context, ServerMessageRuntimeMetadata runtimeMetadata)
+ {
+ ref var meta = ref context.Request.Meta;
+ bool requestValid = true;
+ requestValid &= meta.SendPid == _hasInProcessIdHolder;
+ requestValid &= meta.SendStaticsCount == _inPointerBuffersCount;
+ requestValid &= meta.SendBuffersCount == _inMapAliasBuffersCount;
+ requestValid &= meta.ReceiveBuffersCount == _outMapAliasBuffersCount;
+ requestValid &= meta.ExchangeBuffersCount == 0;
+ requestValid &= meta.CopyHandlesCount == _inCopyHandlesCount;
+ requestValid &= meta.MoveHandlesCount == _inMoveHandlesCount;
+
+ int rawSizeInBytes = meta.DataWordsCount * sizeof(uint);
+ int commandRawSize = BitUtils.AlignUp(runtimeMetadata.UnfixedOutPointerSizeOffset + (OutUnfixedSizePointerBuffersCount * sizeof(ushort)), sizeof(uint));
+ requestValid &= rawSizeInBytes >= commandRawSize;
+
+ return requestValid ? Result.Success : HipcResult.InvalidCmifRequest;
+ }
+
+ public Result GetInObjects(ServerMessageProcessor processor, Span<IServiceObject> objects)
+ {
+ if (objects.Length == 0)
+ {
+ return Result.Success;
+ }
+
+ ServiceObjectHolder[] inObjects = new ServiceObjectHolder[objects.Length];
+ Result result = processor.GetInObjects(inObjects);
+
+ if (result.IsFailure)
+ {
+ return result;
+ }
+
+ int inObjectIndex = 0;
+
+ for (int i = 0; i < _args.Length; i++)
+ {
+ if (_args[i].Type == CommandArgType.InObject)
+ {
+ int index = inObjectIndex++;
+ var inObject = inObjects[index];
+
+ objects[index] = inObject?.ServiceObject;
+ }
+ }
+
+ return Result.Success;
+ }
+
+ public override Result GetInObjects(Span<ServiceObjectHolder> inObjects)
+ {
+ return SfResult.NotSupported;
+ }
+
+ public override HipcMessageData PrepareForReply(scoped ref ServiceDispatchContext context, out Span<byte> outRawData, ServerMessageRuntimeMetadata runtimeMetadata)
+ {
+ int rawDataSize = OutRawDataSize + runtimeMetadata.OutHeadersSize;
+ var response = HipcMessage.WriteResponse(
+ context.OutMessageBuffer,
+ _outPointerBuffersCount,
+ (BitUtils.AlignUp(rawDataSize, 4) + 0x10) / sizeof(uint),
+ _outCopyHandlesCount,
+ _outMoveHandlesCount + runtimeMetadata.OutObjectsCount);
+ outRawData = MemoryMarshal.Cast<uint, byte>(response.DataWords);
+ return response;
+ }
+
+ public override void PrepareForErrorReply(scoped ref ServiceDispatchContext context, out Span<byte> outRawData, ServerMessageRuntimeMetadata runtimeMetadata)
+ {
+ int rawDataSize = runtimeMetadata.OutHeadersSize;
+ var response = HipcMessage.WriteResponse(
+ context.OutMessageBuffer,
+ 0,
+ (BitUtils.AlignUp(rawDataSize, 4) + 0x10) / sizeof(uint),
+ 0,
+ 0);
+ outRawData = MemoryMarshal.Cast<uint, byte>(response.DataWords);
+ }
+
+ public void SetOutObjects(ref ServiceDispatchContext context, HipcMessageData response, Span<IServiceObject> objects)
+ {
+ if (objects.Length == 0)
+ {
+ return;
+ }
+
+ ServiceObjectHolder[] outObjects = new ServiceObjectHolder[objects.Length];
+
+ for (int i = 0; i < objects.Length; i++)
+ {
+ outObjects[i] = objects[i] != null ? new ServiceObjectHolder(objects[i]) : null;
+ }
+
+ context.Processor.SetOutObjects(ref context, response, outObjects);
+ }
+
+ public override void SetOutObjects(scoped ref ServiceDispatchContext context, HipcMessageData response, Span<ServiceObjectHolder> outObjects)
+ {
+ for (int index = 0; index < _outObjectsCount; index++)
+ {
+ SetOutObjectImpl(index, response, context.Manager, outObjects[index]);
+ }
+ }
+
+ private void SetOutObjectImpl(int index, HipcMessageData response, ServerSessionManager manager, ServiceObjectHolder obj)
+ {
+ if (obj == null)
+ {
+ response.MoveHandles[index] = 0;
+ return;
+ }
+
+ Api.CreateSession(out int serverHandle, out int clientHandle).AbortOnFailure();
+ manager.RegisterSession(serverHandle, obj).AbortOnFailure();
+ response.MoveHandles[index] = clientHandle;
+ }
+ }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/IServiceObject.cs b/Ryujinx.Horizon/Sdk/Sf/IServiceObject.cs
new file mode 100644
index 00000000..afa57fef
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/IServiceObject.cs
@@ -0,0 +1,9 @@
+using System.Collections.Generic;
+
+namespace Ryujinx.Horizon.Sdk.Sf
+{
+ interface IServiceObject
+ {
+ IReadOnlyDictionary<int, CommandHandler> GetCommandHandlers();
+ }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/RawDataOffsetCalculator.cs b/Ryujinx.Horizon/Sdk/Sf/RawDataOffsetCalculator.cs
new file mode 100644
index 00000000..982f454f
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/RawDataOffsetCalculator.cs
@@ -0,0 +1,51 @@
+using Ryujinx.Common;
+
+namespace Ryujinx.Horizon.Sdk.Sf
+{
+ static class RawDataOffsetCalculator
+ {
+ public static int[] Calculate(CommandArg[] args)
+ {
+ int[] offsets = new int[args.Length + 1];
+
+ if (args.Length != 0)
+ {
+ int argsCount = args.Length;
+
+ int[] sizes = new int[argsCount];
+ int[] aligns = new int[argsCount];
+ int[] map = new int[argsCount];
+
+ for (int i = 0; i < argsCount; i++)
+ {
+ sizes[i] = args[i].ArgSize;
+ aligns[i] = args[i].ArgAlignment;
+ map[i] = i;
+ }
+
+ for (int i = 1; i < argsCount; i++)
+ {
+ for (int j = i; j > 0 && aligns[map[j - 1]] > aligns[map[j]]; j--)
+ {
+ var temp = map[j - 1];
+ map[j - 1] = map[j];
+ map[j] = temp;
+ }
+ }
+
+ int offset = 0;
+
+ foreach (int i in map)
+ {
+ offset = BitUtils.AlignUp(offset, aligns[i]);
+ offsets[i] = offset;
+ offset += sizes[i];
+ }
+
+ offsets[argsCount] = offset;
+ }
+
+ return offsets;
+ }
+ }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sf/SfResult.cs b/Ryujinx.Horizon/Sdk/Sf/SfResult.cs
new file mode 100644
index 00000000..6aa11ba5
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sf/SfResult.cs
@@ -0,0 +1,31 @@
+using Ryujinx.Horizon.Common;
+
+namespace Ryujinx.Horizon.Sdk.Sf
+{
+ static class SfResult
+ {
+ public const int ModuleId = 10;
+
+ public static Result NotSupported => new Result(ModuleId, 1);
+ public static Result InvalidHeaderSize => new Result(ModuleId, 202);
+ public static Result InvalidInHeader => new Result(ModuleId, 211);
+ public static Result InvalidOutHeader => new Result(ModuleId, 212);
+ public static Result UnknownCommandId => new Result(ModuleId, 221);
+ public static Result InvalidOutRawSize => new Result(ModuleId, 232);
+ public static Result InvalidInObjectsCount => new Result(ModuleId, 235);
+ public static Result InvalidOutObjectsCount => new Result(ModuleId, 236);
+ public static Result InvalidInObject => new Result(ModuleId, 239);
+
+ public static Result TargetNotFound => new Result(ModuleId, 261);
+
+ public static Result OutOfDomainEntries => new Result(ModuleId, 301);
+
+ public static Result InvalidatedByUser => new Result(ModuleId, 802);
+ public static Result RequestDeferredByUser => new Result(ModuleId, 812);
+
+ public static bool RequestContextChanged(Result result) => result.InRange(800, 899);
+ public static bool Invalidated(Result result) => result.InRange(801, 809);
+
+ public static bool RequestDeferred(Result result) => result.InRange(811, 819);
+ }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sm/ServiceName.cs b/Ryujinx.Horizon/Sdk/Sm/ServiceName.cs
new file mode 100644
index 00000000..dbb30078
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sm/ServiceName.cs
@@ -0,0 +1,98 @@
+using System;
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.Horizon.Sdk.Sm
+{
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ struct ServiceName
+ {
+ public static ServiceName Invalid { get; } = new ServiceName(0);
+
+ public bool IsInvalid => Packed == 0;
+
+ public int Length => sizeof(ulong);
+
+ public ulong Packed { get; }
+
+ public byte this[int index]
+ {
+ get
+ {
+ if ((uint)index >= sizeof(ulong))
+ {
+ throw new IndexOutOfRangeException();
+ }
+
+ return (byte)(Packed >> (index * 8));
+ }
+ }
+
+ private ServiceName(ulong packed)
+ {
+ Packed = packed;
+ }
+
+ public static ServiceName Encode(string name)
+ {
+ ulong packed = 0;
+
+ for (int index = 0; index < sizeof(ulong); index++)
+ {
+ if (index < name.Length)
+ {
+ packed |= (ulong)(byte)name[index] << (index * 8);
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ return new ServiceName(packed);
+ }
+
+ public override bool Equals(object obj)
+ {
+ return obj is ServiceName serviceName && serviceName.Equals(this);
+ }
+
+ public bool Equals(ServiceName other)
+ {
+ return other.Packed == Packed;
+ }
+
+ public override int GetHashCode()
+ {
+ return Packed.GetHashCode();
+ }
+
+ public static bool operator ==(ServiceName lhs, ServiceName rhs)
+ {
+ return lhs.Equals(rhs);
+ }
+
+ public static bool operator !=(ServiceName lhs, ServiceName rhs)
+ {
+ return !lhs.Equals(rhs);
+ }
+
+ public override string ToString()
+ {
+ string name = string.Empty;
+
+ for (int index = 0; index < sizeof(ulong); index++)
+ {
+ byte character = (byte)(Packed >> (index * 8));
+
+ if (character == 0)
+ {
+ break;
+ }
+
+ name += (char)character;
+ }
+
+ return name;
+ }
+ }
+}
diff --git a/Ryujinx.Horizon/Sdk/Sm/SmApi.cs b/Ryujinx.Horizon/Sdk/Sm/SmApi.cs
new file mode 100644
index 00000000..e4b0eea1
--- /dev/null
+++ b/Ryujinx.Horizon/Sdk/Sm/SmApi.cs
@@ -0,0 +1,107 @@
+using Ryujinx.Common.Memory;
+using Ryujinx.Horizon.Common;
+using Ryujinx.Horizon.Sdk.Sf.Cmif;
+using System;
+
+namespace Ryujinx.Horizon.Sdk.Sm
+{
+ class SmApi
+ {
+ private int _portHandle;
+
+ public Result Initialize()
+ {
+ Result result = HorizonStatic.Syscall.ConnectToNamedPort(out int portHandle, "sm:");
+
+ while (result == KernelResult.NotFound)
+ {
+ HorizonStatic.Syscall.SleepThread(50000000L);
+ result = HorizonStatic.Syscall.ConnectToNamedPort(out portHandle, "sm:");
+ }
+
+ if (result.IsFailure)
+ {
+ return result;
+ }
+
+ _portHandle = portHandle;
+
+ return RegisterClient();
+ }
+
+ private Result RegisterClient()
+ {
+ Span<byte> data = stackalloc byte[8];
+
+ SpanWriter writer = new SpanWriter(data);
+
+ writer.Write(0UL);
+
+ return ServiceUtil.SendRequest(out _, _portHandle, 0, sendPid: true, data);
+ }
+
+ public Result GetServiceHandle(out int handle, ServiceName name)
+ {
+ Span<byte> data = stackalloc byte[8];
+
+ SpanWriter writer = new SpanWriter(data);
+
+ writer.Write(name);
+
+ Result result = ServiceUtil.SendRequest(out CmifResponse response, _portHandle, 1, sendPid: false, data);
+
+ if (result.IsFailure)
+ {
+ handle = 0;
+ return result;
+ }
+
+ handle = response.MoveHandles[0];
+ return Result.Success;
+ }
+
+ public Result RegisterService(out int handle, ServiceName name, int maxSessions, bool isLight)
+ {
+ Span<byte> data = stackalloc byte[16];
+
+ SpanWriter writer = new SpanWriter(data);
+
+ writer.Write(name);
+ writer.Write(isLight ? 1 : 0);
+ writer.Write(maxSessions);
+
+ Result result = ServiceUtil.SendRequest(out CmifResponse response, _portHandle, 2, sendPid: false, data);
+
+ if (result.IsFailure)
+ {
+ handle = 0;
+ return result;
+ }
+
+ handle = response.MoveHandles[0];
+ return Result.Success;
+ }
+
+ public Result UnregisterService(ServiceName name)
+ {
+ Span<byte> data = stackalloc byte[8];
+
+ SpanWriter writer = new SpanWriter(data);
+
+ writer.Write(name);
+
+ return ServiceUtil.SendRequest(out _, _portHandle, 3, sendPid: false, data);
+ }
+
+ public Result DetachClient()
+ {
+ Span<byte> data = stackalloc byte[8];
+
+ SpanWriter writer = new SpanWriter(data);
+
+ writer.Write(0UL);
+
+ return ServiceUtil.SendRequest(out _, _portHandle, 4, sendPid: true, data);
+ }
+ }
+}
diff --git a/Ryujinx.Horizon/ServiceEntry.cs b/Ryujinx.Horizon/ServiceEntry.cs
new file mode 100644
index 00000000..3fea46c1
--- /dev/null
+++ b/Ryujinx.Horizon/ServiceEntry.cs
@@ -0,0 +1,25 @@
+using Ryujinx.Horizon.Common;
+using Ryujinx.Memory;
+using System;
+
+namespace Ryujinx.Horizon
+{
+ public struct ServiceEntry
+ {
+ private readonly Action _entrypoint;
+ private readonly HorizonOptions _options;
+
+ internal ServiceEntry(Action entrypoint, HorizonOptions options)
+ {
+ _entrypoint = entrypoint;
+ _options = options;
+ }
+
+ public void Start(ISyscallApi syscallApi, IVirtualMemoryManager addressSpace, IThreadContext threadContext)
+ {
+ HorizonStatic.Register(_options, syscallApi, addressSpace, threadContext, (int)threadContext.GetX(1));
+
+ _entrypoint();
+ }
+ }
+}
diff --git a/Ryujinx.Horizon/ServiceTable.cs b/Ryujinx.Horizon/ServiceTable.cs
new file mode 100644
index 00000000..933b6a59
--- /dev/null
+++ b/Ryujinx.Horizon/ServiceTable.cs
@@ -0,0 +1,22 @@
+using Ryujinx.Horizon.LogManager;
+using System.Collections.Generic;
+
+namespace Ryujinx.Horizon
+{
+ public static class ServiceTable
+ {
+ public static IEnumerable<ServiceEntry> GetServices(HorizonOptions options)
+ {
+ List<ServiceEntry> entries = new List<ServiceEntry>();
+
+ void RegisterService<T>() where T : IService
+ {
+ entries.Add(new ServiceEntry(T.Main, options));
+ }
+
+ RegisterService<LmMain>();
+
+ return entries;
+ }
+ }
+}
diff --git a/Ryujinx.Horizon/Sm/Impl/ServiceInfo.cs b/Ryujinx.Horizon/Sm/Impl/ServiceInfo.cs
new file mode 100644
index 00000000..fed420aa
--- /dev/null
+++ b/Ryujinx.Horizon/Sm/Impl/ServiceInfo.cs
@@ -0,0 +1,20 @@
+using Ryujinx.Horizon.Sdk.Sm;
+
+namespace Ryujinx.Horizon.Sm.Impl
+{
+ struct ServiceInfo
+ {
+ public ServiceName Name;
+ public ulong OwnerProcessId;
+ public int PortHandle;
+
+ public void Free()
+ {
+ HorizonStatic.Syscall.CloseHandle(PortHandle);
+
+ Name = ServiceName.Invalid;
+ OwnerProcessId = 0L;
+ PortHandle = 0;
+ }
+ }
+}
diff --git a/Ryujinx.Horizon/Sm/Impl/ServiceManager.cs b/Ryujinx.Horizon/Sm/Impl/ServiceManager.cs
new file mode 100644
index 00000000..cdf2d17f
--- /dev/null
+++ b/Ryujinx.Horizon/Sm/Impl/ServiceManager.cs
@@ -0,0 +1,197 @@
+using Ryujinx.Horizon.Common;
+using Ryujinx.Horizon.Sdk.OsTypes;
+using Ryujinx.Horizon.Sdk.Sf;
+using Ryujinx.Horizon.Sdk.Sm;
+
+namespace Ryujinx.Horizon.Sm.Impl
+{
+ class ServiceManager
+ {
+ private const int MaxServicesCount = 256;
+
+ private readonly ServiceInfo[] _services;
+
+ public ServiceManager()
+ {
+ _services = new ServiceInfo[MaxServicesCount];
+ }
+
+ public Result GetService(out int handle, ulong processId, ServiceName name)
+ {
+ handle = 0;
+ Result result = ValidateServiceName(name);
+
+ if (result.IsFailure)
+ {
+ return result;
+ }
+
+ // TODO: Validation with GetProcessInfo etc.
+
+ int serviceIndex = GetServiceInfo(name);
+
+ if (serviceIndex < 0)
+ {
+ return SfResult.RequestDeferredByUser;
+ }
+
+ result = GetServiceImpl(out handle, ref _services[serviceIndex]);
+
+ if (result == KernelResult.SessionCountExceeded)
+ {
+ return SmResult.OutOfSessions;
+ }
+
+ return result;
+ }
+
+ private Result GetServiceImpl(out int handle, ref ServiceInfo serviceInfo)
+ {
+ return HorizonStatic.Syscall.ConnectToPort(out handle, serviceInfo.PortHandle);
+ }
+
+ public Result RegisterService(out int handle, ulong processId, ServiceName name, int maxSessions, bool isLight)
+ {
+ handle = 0;
+ Result result = ValidateServiceName(name);
+
+ if (result.IsFailure)
+ {
+ return result;
+ }
+
+ // TODO: Validation with GetProcessInfo etc.
+
+ if (HasServiceInfo(name))
+ {
+ return SmResult.AlreadyRegistered;
+ }
+
+ return RegisterServiceImpl(out handle, processId, name, maxSessions, isLight);
+ }
+
+ public Result RegisterServiceForSelf(out int handle, ServiceName name, int maxSessions)
+ {
+ return RegisterServiceImpl(out handle, Os.GetCurrentProcessId(), name, maxSessions, false);
+ }
+
+ private Result RegisterServiceImpl(out int handle, ulong processId, ServiceName name, int maxSessions, bool isLight)
+ {
+ handle = 0;
+
+ Result result = ValidateServiceName(name);
+
+ if (!result.IsSuccess)
+ {
+ return result;
+ }
+
+ if (HasServiceInfo(name))
+ {
+ return SmResult.AlreadyRegistered;
+ }
+
+ int freeServiceIndex = GetFreeService();
+
+ if (freeServiceIndex < 0)
+ {
+ return SmResult.OutOfServices;
+ }
+
+ ref ServiceInfo freeService = ref _services[freeServiceIndex];
+
+ result = HorizonStatic.Syscall.CreatePort(out handle, out int clientPort, maxSessions, isLight, null);
+
+ if (!result.IsSuccess)
+ {
+ return result;
+ }
+
+ freeService.PortHandle = clientPort;
+ freeService.Name = name;
+ freeService.OwnerProcessId = processId;
+
+ return Result.Success;
+ }
+
+ public Result UnregisterService(ulong processId, ServiceName name)
+ {
+ Result result = ValidateServiceName(name);
+
+ if (result.IsFailure)
+ {
+ return result;
+ }
+
+ // TODO: Validation with GetProcessInfo etc.
+
+ int serviceIndex = GetServiceInfo(name);
+
+ if (serviceIndex < 0)
+ {
+ return SmResult.NotRegistered;
+ }
+
+ ref var serviceInfo = ref _services[serviceIndex];
+
+ if (serviceInfo.OwnerProcessId != processId)
+ {
+ return SmResult.NotAllowed;
+ }
+
+ serviceInfo.Free();
+ return Result.Success;
+ }
+
+ private static Result ValidateServiceName(ServiceName name)
+ {
+ if (name[0] == 0)
+ {
+ return SmResult.InvalidServiceName;
+ }
+
+ int nameLength = 1;
+
+ for (; nameLength < name.Length; nameLength++)
+ {
+ if (name[nameLength] == 0)
+ {
+ break;
+ }
+ }
+
+ while (nameLength < name.Length)
+ {
+ if (name[nameLength++] != 0)
+ {
+ return SmResult.InvalidServiceName;
+ }
+ }
+
+ return Result.Success;
+ }
+
+ private bool HasServiceInfo(ServiceName name)
+ {
+ return GetServiceInfo(name) != -1;
+ }
+
+ private int GetFreeService()
+ {
+ return GetServiceInfo(ServiceName.Invalid);
+ }
+
+ private int GetServiceInfo(ServiceName name)
+ {
+ for (int index = 0; index < MaxServicesCount; index++)
+ {
+ if (_services[index].Name == name)
+ {
+ return index;
+ }
+ }
+
+ return -1;
+ }
+ }
+}
diff --git a/Ryujinx.Horizon/Sm/ManagerService.cs b/Ryujinx.Horizon/Sm/ManagerService.cs
new file mode 100644
index 00000000..1719dcfd
--- /dev/null
+++ b/Ryujinx.Horizon/Sm/ManagerService.cs
@@ -0,0 +1,8 @@
+using Ryujinx.Horizon.Sdk.Sf;
+
+namespace Ryujinx.Horizon.Sm
+{
+ partial class ManagerService : IServiceObject
+ {
+ }
+}
diff --git a/Ryujinx.Horizon/Sm/SmMain.cs b/Ryujinx.Horizon/Sm/SmMain.cs
new file mode 100644
index 00000000..8c37bece
--- /dev/null
+++ b/Ryujinx.Horizon/Sm/SmMain.cs
@@ -0,0 +1,30 @@
+using Ryujinx.Horizon.Sdk.Sf.Hipc;
+using Ryujinx.Horizon.Sdk.Sm;
+using Ryujinx.Horizon.Sm.Impl;
+
+namespace Ryujinx.Horizon.Sm
+{
+ public class SmMain
+ {
+ private enum PortIndex
+ {
+ User,
+ Manager
+ }
+
+ private const int MaxPortsCount = 2;
+
+ private readonly ServerManager _serverManager = new ServerManager(null, null, MaxPortsCount, ManagerOptions.Default, 0);
+ private readonly ServiceManager _serviceManager = new ServiceManager();
+
+ public void Main()
+ {
+ HorizonStatic.Syscall.ManageNamedPort(out int smHandle, "sm:", 64).AbortOnFailure();
+
+ _serverManager.RegisterServer((int)PortIndex.User, smHandle);
+ _serviceManager.RegisterServiceForSelf(out int smmHandle, ServiceName.Encode("sm:m"), 1).AbortOnFailure();
+ _serverManager.RegisterServer((int)PortIndex.Manager, smmHandle);
+ _serverManager.ServiceRequests();
+ }
+ }
+}
diff --git a/Ryujinx.Horizon/Sm/SmResult.cs b/Ryujinx.Horizon/Sm/SmResult.cs
new file mode 100644
index 00000000..3063445d
--- /dev/null
+++ b/Ryujinx.Horizon/Sm/SmResult.cs
@@ -0,0 +1,19 @@
+using Ryujinx.Horizon.Common;
+
+namespace Ryujinx.Horizon.Sm
+{
+ static class SmResult
+ {
+ private const int ModuleId = 21;
+
+ public static Result OutOfProcess => new Result(ModuleId, 1);
+ public static Result InvalidClient => new Result(ModuleId, 2);
+ public static Result OutOfSessions => new Result(ModuleId, 3);
+ public static Result AlreadyRegistered => new Result(ModuleId, 4);
+ public static Result OutOfServices => new Result(ModuleId, 5);
+ public static Result InvalidServiceName => new Result(ModuleId, 6);
+ public static Result NotRegistered => new Result(ModuleId, 7);
+ public static Result NotAllowed => new Result(ModuleId, 8);
+ public static Result TooLargeAccessControl => new Result(ModuleId, 9);
+ }
+}
diff --git a/Ryujinx.Horizon/Sm/UserService.cs b/Ryujinx.Horizon/Sm/UserService.cs
new file mode 100644
index 00000000..d3b4537b
--- /dev/null
+++ b/Ryujinx.Horizon/Sm/UserService.cs
@@ -0,0 +1,66 @@
+using Ryujinx.Horizon.Common;
+using Ryujinx.Horizon.Sdk.Sf;
+using Ryujinx.Horizon.Sdk.Sm;
+using Ryujinx.Horizon.Sm.Impl;
+
+namespace Ryujinx.Horizon.Sm
+{
+ partial class UserService : IServiceObject
+ {
+ private readonly ServiceManager _serviceManager;
+
+ private ulong _clientProcessId;
+ private bool _initialized;
+
+ public UserService(ServiceManager serviceManager)
+ {
+ _serviceManager = serviceManager;
+ }
+
+ [CmifCommand(0)]
+ public Result Initialize([ClientProcessId] ulong clientProcessId)
+ {
+ _clientProcessId = clientProcessId;
+ _initialized = true;
+
+ return Result.Success;
+ }
+
+ [CmifCommand(1)]
+ public Result GetService([MoveHandle] out int handle, ServiceName name)
+ {
+ if (!_initialized)
+ {
+ handle = 0;
+
+ return SmResult.InvalidClient;
+ }
+
+ return _serviceManager.GetService(out handle, _clientProcessId, name);
+ }
+
+ [CmifCommand(2)]
+ public Result RegisterService([MoveHandle] out int handle, ServiceName name, int maxSessions, bool isLight)
+ {
+ if (!_initialized)
+ {
+ handle = 0;
+
+ return SmResult.InvalidClient;
+ }
+
+ return _serviceManager.RegisterService(out handle, _clientProcessId, name, maxSessions, isLight);
+ }
+
+ [CmifCommand(3)]
+ public Result UnregisterService(ServiceName name)
+ {
+ if (!_initialized)
+ {
+ return SmResult.InvalidClient;
+ }
+
+ return _serviceManager.UnregisterService(_clientProcessId, name);
+ }
+ }
+}
diff --git a/Ryujinx.sln b/Ryujinx.sln
index 1eaf006c..007252fd 100644
--- a/Ryujinx.sln
+++ b/Ryujinx.sln
@@ -79,7 +79,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Vulkan", "
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Spv.Generator", "Spv.Generator\Spv.Generator.csproj", "{2BCB3D7A-38C0-4FE7-8FDA-374C6AD56D0E}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Ui.LocaleGenerator", "Ryujinx.Ui.LocaleGenerator\Ryujinx.Ui.LocaleGenerator.csproj", "{77D01AD9-2C98-478E-AE1D-8F7100738FB4}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Horizon.Common", "Ryujinx.Horizon.Common\Ryujinx.Horizon.Common.csproj", "{77F96ECE-4952-42DB-A528-DED25572A573}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Horizon", "Ryujinx.Horizon\Ryujinx.Horizon.csproj", "{AF34127A-3A92-43E5-8496-14960A50B1F1}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Horizon.Kernel.Generators", "Ryujinx.Horizon.Kernel.Generators\Ryujinx.Horizon.Kernel.Generators.csproj", "{7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -227,10 +231,18 @@ Global
{2BCB3D7A-38C0-4FE7-8FDA-374C6AD56D0E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2BCB3D7A-38C0-4FE7-8FDA-374C6AD56D0E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2BCB3D7A-38C0-4FE7-8FDA-374C6AD56D0E}.Release|Any CPU.Build.0 = Release|Any CPU
- {77D01AD9-2C98-478E-AE1D-8F7100738FB4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {77D01AD9-2C98-478E-AE1D-8F7100738FB4}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {77D01AD9-2C98-478E-AE1D-8F7100738FB4}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {77D01AD9-2C98-478E-AE1D-8F7100738FB4}.Release|Any CPU.Build.0 = Release|Any CPU
+ {77F96ECE-4952-42DB-A528-DED25572A573}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {77F96ECE-4952-42DB-A528-DED25572A573}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {77F96ECE-4952-42DB-A528-DED25572A573}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {77F96ECE-4952-42DB-A528-DED25572A573}.Release|Any CPU.Build.0 = Release|Any CPU
+ {AF34127A-3A92-43E5-8496-14960A50B1F1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {AF34127A-3A92-43E5-8496-14960A50B1F1}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {AF34127A-3A92-43E5-8496-14960A50B1F1}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {AF34127A-3A92-43E5-8496-14960A50B1F1}.Release|Any CPU.Build.0 = Release|Any CPU
+ {7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE