From 08831eecf77cedd3c4192ebab5a9c485fb15d51e Mon Sep 17 00:00:00 2001 From: gdkchan Date: Wed, 4 Jan 2023 19:15:45 -0300 Subject: [PATCH] IPC refactor part 3+4: New server HIPC message processor (#4188) * IPC refactor part 3 + 4: New server HIPC message processor with source generator based serialization * Make types match on calls to AlignUp/AlignDown * Formatting * Address some PR feedback * Move BitfieldExtensions to Ryujinx.Common.Utilities and consolidate implementations * Rename Reader/Writer to SpanReader/SpanWriter and move to Ryujinx.Common.Memory * Implement EventType * Address more PR feedback * Log request processing errors since they are not normal * Rename waitable to multiwait and add missing lock * PR feedback * Ac_K PR feedback --- Ryujinx.Common/Memory/SpanReader.cs | 51 + Ryujinx.Common/Memory/SpanWriter.cs | 45 + .../Utilities/BitfieldExtensions.cs | 57 + .../Decoders/BitfieldExtensions.cs | 15 - .../Optimizations/ConstantFolding.cs | 2 +- .../Translation/ShaderHeader.cs | 2 +- .../Types/BitfieldExtensions.cs | 39 - .../Types/BlendingSlotStruct.cs | 24 +- Ryujinx.Graphics.Vic/Types/ClearRectStruct.cs | 20 +- Ryujinx.Graphics.Vic/Types/LumaKeyStruct.cs | 18 +- Ryujinx.Graphics.Vic/Types/MatrixStruct.cs | 30 +- Ryujinx.Graphics.Vic/Types/OutputConfig.cs | 26 +- .../Types/OutputSurfaceConfig.cs | 24 +- Ryujinx.Graphics.Vic/Types/PipeConfig.cs | 8 +- Ryujinx.Graphics.Vic/Types/SlotConfig.cs | 58 +- .../Types/SlotSurfaceConfig.cs | 26 +- Ryujinx.HLE/HOS/Horizon.cs | 37 + Ryujinx.HLE/HOS/Kernel/Common/KAutoObject.cs | 9 +- .../HOS/Kernel/Common/KResourceLimit.cs | 5 +- Ryujinx.HLE/HOS/Kernel/Common/KernelInit.cs | 5 +- Ryujinx.HLE/HOS/Kernel/Common/KernelResult.cs | 37 - Ryujinx.HLE/HOS/Kernel/Common/OnScopeExit.cs | 11 - .../HOS/Kernel/Ipc/KBufferDescriptorTable.cs | 62 +- Ryujinx.HLE/HOS/Kernel/Ipc/KClientPort.cs | 15 +- Ryujinx.HLE/HOS/Kernel/Ipc/KClientSession.cs | 13 +- Ryujinx.HLE/HOS/Kernel/Ipc/KPort.cs | 21 +- Ryujinx.HLE/HOS/Kernel/Ipc/KServerSession.cs | 77 +- Ryujinx.HLE/HOS/Kernel/KernelStatic.cs | 7 +- Ryujinx.HLE/HOS/Kernel/Memory/KCodeMemory.cs | 43 +- .../HOS/Kernel/Memory/KMemoryBlockManager.cs | 6 +- .../HOS/Kernel/Memory/KMemoryRegionManager.cs | 18 +- Ryujinx.HLE/HOS/Kernel/Memory/KPageList.cs | 6 +- Ryujinx.HLE/HOS/Kernel/Memory/KPageTable.cs | 46 +- .../HOS/Kernel/Memory/KPageTableBase.cs | 261 +-- .../HOS/Kernel/Memory/KSharedMemory.cs | 5 +- .../HOS/Kernel/Memory/KTransferMemory.cs | 21 +- .../HOS/Kernel/Process/KHandleTable.cs | 13 +- Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs | 93 +- .../Kernel/Process/KProcessCapabilities.cs | 23 +- .../Kernel/Process/ProcessExecutionContext.cs | 18 +- .../HOS/Kernel/SupervisorCall/Syscall.cs | 392 ++-- .../HOS/Kernel/Threading/KAddressArbiter.cs | 37 +- .../HOS/Kernel/Threading/KReadableEvent.cs | 11 +- .../HOS/Kernel/Threading/KSynchronization.cs | 9 +- Ryujinx.HLE/HOS/Kernel/Threading/KThread.cs | 45 +- .../HOS/Kernel/Threading/KThreadContext.cs | 18 +- .../HOS/Kernel/Threading/KWritableEvent.cs | 3 +- Ryujinx.HLE/HOS/ProgramLoader.cs | 69 +- .../HOS/Services/Account/Acc/IAsyncContext.cs | 4 +- .../ILibraryAppletAccessor.cs | 8 +- .../SystemAppletProxy/ICommonStateGetter.cs | 6 +- .../SystemAppletProxy/IDisplayController.cs | 6 +- .../SystemAppletProxy/IHomeMenuFunctions.cs | 4 +- .../SystemAppletProxy/ISelfController.cs | 6 +- .../ApplicationProxy/IApplicationFunctions.cs | 21 +- .../Services/Audio/AudioIn/AudioInServer.cs | 4 +- .../Services/Audio/AudioOut/AudioOutServer.cs | 4 +- .../Audio/AudioRenderer/AudioDeviceServer.cs | 8 +- .../AudioRenderer/AudioRendererServer.cs | 4 +- .../IDeliveryCacheProgressService.cs | 4 +- .../Services/Bluetooth/IBluetoothDriver.cs | 14 +- .../BluetoothManager/BtmUser/IBtmUserCore.cs | 26 +- .../Friend/ServiceCreator/IFriendService.cs | 5 +- .../ServiceCreator/INotificationService.cs | 4 +- .../Services/Hid/HidServer/IAppletResource.cs | 4 +- Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs | 10 +- .../HOS/Services/Hid/Irs/IIrSensorServer.cs | 10 +- .../IUserLocalCommunicationService.cs | 4 +- .../HOS/Services/Nfc/Nfp/NfpManager/INfp.cs | 8 +- .../Services/Nifm/StaticService/IRequest.cs | 6 +- .../HOS/Services/Nim/IShopServiceAccessor.cs | 4 +- .../IEnsureNetworkClockAvailabilityService.cs | 6 +- .../Services/Ns/Aoc/IAddOnContentManager.cs | 6 +- .../Services/Ns/Aoc/IPurchaseEventManager.cs | 4 +- .../NvHostChannel/NvHostGpuDeviceFile.cs | 6 +- .../NvHostCtrl/Types/NvHostEvent.cs | 4 +- .../NvHostCtrlGpu/NvHostCtrlGpuDeviceFile.cs | 4 +- .../HOS/Services/Pcv/Clkrst/IClkrstManager.cs | 4 +- .../HOS/Services/Pm/IDebugMonitorInterface.cs | 4 +- .../HOS/Services/Ptm/Psm/IPsmSession.cs | 8 +- Ryujinx.HLE/HOS/Services/Ro/IRoInterface.cs | 38 +- .../HOS/Services/Sdb/Pl/ISharedFontManager.cs | 6 +- Ryujinx.HLE/HOS/Services/ServerBase.cs | 8 +- Ryujinx.HLE/HOS/Services/Sm/IUserInterface.cs | 14 +- .../SurfaceFlinger/IHOSBinderDriver.cs | 4 +- .../HOS/Services/Time/IStaticServiceForPsc.cs | 4 +- .../HOS/Services/Time/ITimeServiceManager.cs | 4 +- .../Time/StaticService/ISystemClock.cs | 4 +- .../RootService/IApplicationDisplayService.cs | 3 +- Ryujinx.HLE/Ryujinx.HLE.csproj | 4 +- Ryujinx.HLE/Switch.cs | 4 +- Ryujinx.Horizon.Common/ISyscallApi.cs | 33 + Ryujinx.Horizon.Common/IThreadContext.cs | 11 + .../InvalidResultException.cs | 23 + Ryujinx.Horizon.Common/KernelResult.cs | 39 + Ryujinx.Horizon.Common/OnScopeExit.cs | 19 + Ryujinx.Horizon.Common/Result.cs | 118 ++ Ryujinx.Horizon.Common/ResultNames.cs | 1701 +++++++++++++++++ .../Ryujinx.Horizon.Common.csproj | 11 + .../ThreadTerminatedException.cs | 19 + Ryujinx.Horizon.Generators/CodeGenerator.cs | 4 +- .../Hipc/CommandArgType.cs | 18 + .../Hipc/CommandInterface.cs | 17 + .../Hipc/HipcGenerator.cs | 749 ++++++++ .../Hipc/HipcSyntaxReceiver.cs | 58 + .../CodeGenerator.cs | 58 + .../Kernel/SyscallGenerator.cs | 36 +- .../Kernel/SyscallSyntaxReceiver.cs | 0 .../Ryujinx.Horizon.Kernel.Generators.csproj | 15 + Ryujinx.Horizon/HeapAllocator.cs | 143 ++ Ryujinx.Horizon/HorizonOptions.cs | 12 + Ryujinx.Horizon/HorizonStatic.cs | 44 + Ryujinx.Horizon/IService.cs | 7 + Ryujinx.Horizon/LogManager/LmIpcServer.cs | 54 + Ryujinx.Horizon/LogManager/LmLog.cs | 19 + Ryujinx.Horizon/LogManager/LmLogger.cs | 139 ++ Ryujinx.Horizon/LogManager/LmMain.cs | 14 + Ryujinx.Horizon/Ryujinx.Horizon.csproj | 14 + Ryujinx.Horizon/Sdk/DebugUtil.cs | 12 + Ryujinx.Horizon/Sdk/Diag/LogSeverity.cs | 11 + Ryujinx.Horizon/Sdk/Lm/LogDataChunkKey.cs | 19 + Ryujinx.Horizon/Sdk/Lm/LogDestination.cs | 14 + Ryujinx.Horizon/Sdk/Lm/LogPacketFlags.cs | 12 + Ryujinx.Horizon/Sdk/Lm/LogPacketHeader.cs | 15 + Ryujinx.Horizon/Sdk/OsTypes/Event.cs | 61 + Ryujinx.Horizon/Sdk/OsTypes/EventClearMode.cs | 8 + Ryujinx.Horizon/Sdk/OsTypes/EventType.cs | 15 + .../Sdk/OsTypes/Impl/InterProcessEvent.cs | 89 + .../Sdk/OsTypes/Impl/InterProcessEventImpl.cs | 136 ++ .../Sdk/OsTypes/Impl/MultiWaitImpl.cs | 250 +++ .../Sdk/OsTypes/InitializationState.cs | 8 + .../Sdk/OsTypes/InterProcessEventType.cs | 27 + Ryujinx.Horizon/Sdk/OsTypes/MultiWait.cs | 43 + .../Sdk/OsTypes/MultiWaitHolder.cs | 16 + .../Sdk/OsTypes/MultiWaitHolderBase.cs | 39 + .../Sdk/OsTypes/MultiWaitHolderOfEvent.cs | 45 + .../Sdk/OsTypes/MultiWaitHolderOfHandle.cs | 14 + Ryujinx.Horizon/Sdk/OsTypes/OsEvent.cs | 130 ++ Ryujinx.Horizon/Sdk/OsTypes/OsMultiWait.cs | 10 + .../Sdk/OsTypes/OsProcessHandle.cs | 33 + Ryujinx.Horizon/Sdk/OsTypes/OsResult.cs | 11 + Ryujinx.Horizon/Sdk/OsTypes/OsSystemEvent.cs | 85 + .../Sdk/OsTypes/OsThreadManager.cs | 10 + .../Sdk/OsTypes/SystemEventType.cs | 17 + Ryujinx.Horizon/Sdk/OsTypes/TriBool.cs | 9 + Ryujinx.Horizon/Sdk/ServiceUtil.cs | 38 + .../Sdk/Sf/Cmif/CmifDomainInHeader.cs | 12 + .../Sdk/Sf/Cmif/CmifDomainOutHeader.cs | 12 + .../Sdk/Sf/Cmif/CmifDomainRequestType.cs | 9 + Ryujinx.Horizon/Sdk/Sf/Cmif/CmifInHeader.cs | 10 + Ryujinx.Horizon/Sdk/Sf/Cmif/CmifMessage.cs | 128 ++ Ryujinx.Horizon/Sdk/Sf/Cmif/CmifOutHeader.cs | 14 + Ryujinx.Horizon/Sdk/Sf/Cmif/CmifRequest.cs | 14 + .../Sdk/Sf/Cmif/CmifRequestFormat.cs | 24 + Ryujinx.Horizon/Sdk/Sf/Cmif/CmifResponse.cs | 12 + Ryujinx.Horizon/Sdk/Sf/Cmif/CommandType.cs | 14 + .../Sdk/Sf/Cmif/DomainServiceObject.cs | 7 + .../Cmif/DomainServiceObjectDispatchTable.cs | 75 + .../Sf/Cmif/DomainServiceObjectProcessor.cs | 140 ++ Ryujinx.Horizon/Sdk/Sf/Cmif/HandlesToClose.cs | 52 + Ryujinx.Horizon/Sdk/Sf/Cmif/InlineContext.cs | 11 + Ryujinx.Horizon/Sdk/Sf/Cmif/PointerAndSize.cs | 17 + .../Sdk/Sf/Cmif/ScopedInlineContextChange.cs | 19 + .../Sdk/Sf/Cmif/ServerDomainBase.cs | 15 + .../Sdk/Sf/Cmif/ServerDomainManager.cs | 246 +++ .../Sdk/Sf/Cmif/ServerMessageProcessor.cs | 18 + .../Sf/Cmif/ServerMessageRuntimeMetadata.cs | 29 + .../Sdk/Sf/Cmif/ServiceDispatchContext.cs | 18 + .../Sdk/Sf/Cmif/ServiceDispatchMeta.cs | 12 + .../Sdk/Sf/Cmif/ServiceDispatchTable.cs | 33 + .../Sdk/Sf/Cmif/ServiceDispatchTableBase.cs | 90 + .../Sdk/Sf/Cmif/ServiceObjectHolder.cs | 34 + .../Sdk/Sf/CmifCommandAttribute.cs | 15 + Ryujinx.Horizon/Sdk/Sf/CommandArg.cs | 56 + .../Sdk/Sf/CommandArgAttributes.cs | 38 + Ryujinx.Horizon/Sdk/Sf/CommandHandler.cs | 57 + .../Sdk/Sf/CommandSerialization.cs | 68 + Ryujinx.Horizon/Sdk/Sf/Hipc/Api.cs | 89 + Ryujinx.Horizon/Sdk/Sf/Hipc/Header.cs | 65 + .../Sdk/Sf/Hipc/HipcBufferDescriptor.cs | 15 + .../Sdk/Sf/Hipc/HipcBufferFlags.cs | 17 + Ryujinx.Horizon/Sdk/Sf/Hipc/HipcBufferMode.cs | 10 + Ryujinx.Horizon/Sdk/Sf/Hipc/HipcManager.cs | 115 ++ Ryujinx.Horizon/Sdk/Sf/Hipc/HipcMessage.cs | 222 +++ .../Sdk/Sf/Hipc/HipcMessageData.cs | 16 + Ryujinx.Horizon/Sdk/Sf/Hipc/HipcMetadata.cs | 16 + .../Sdk/Sf/Hipc/HipcReceiveListEntry.cs | 14 + Ryujinx.Horizon/Sdk/Sf/Hipc/HipcResult.cs | 22 + .../Sdk/Sf/Hipc/HipcStaticDescriptor.cs | 22 + Ryujinx.Horizon/Sdk/Sf/Hipc/ManagerOptions.cs | 20 + Ryujinx.Horizon/Sdk/Sf/Hipc/ReceiveResult.cs | 9 + Ryujinx.Horizon/Sdk/Sf/Hipc/Server.cs | 36 + .../Sdk/Sf/Hipc/ServerDomainSessionManager.cs | 23 + Ryujinx.Horizon/Sdk/Sf/Hipc/ServerManager.cs | 198 ++ .../Sdk/Sf/Hipc/ServerManagerBase.cs | 307 +++ Ryujinx.Horizon/Sdk/Sf/Hipc/ServerSession.cs | 23 + .../Sdk/Sf/Hipc/ServerSessionManager.cs | 335 ++++ Ryujinx.Horizon/Sdk/Sf/Hipc/SpecialHeader.cs | 27 + .../Sdk/Sf/HipcCommandProcessor.cs | 421 ++++ Ryujinx.Horizon/Sdk/Sf/IServiceObject.cs | 9 + .../Sdk/Sf/RawDataOffsetCalculator.cs | 51 + Ryujinx.Horizon/Sdk/Sf/SfResult.cs | 31 + Ryujinx.Horizon/Sdk/Sm/ServiceName.cs | 98 + Ryujinx.Horizon/Sdk/Sm/SmApi.cs | 107 ++ Ryujinx.Horizon/ServiceEntry.cs | 25 + Ryujinx.Horizon/ServiceTable.cs | 22 + Ryujinx.Horizon/Sm/Impl/ServiceInfo.cs | 20 + Ryujinx.Horizon/Sm/Impl/ServiceManager.cs | 197 ++ Ryujinx.Horizon/Sm/ManagerService.cs | 8 + Ryujinx.Horizon/Sm/SmMain.cs | 30 + Ryujinx.Horizon/Sm/SmResult.cs | 19 + Ryujinx.Horizon/Sm/UserService.cs | 66 + Ryujinx.sln | 22 +- 213 files changed, 9762 insertions(+), 1010 deletions(-) create mode 100644 Ryujinx.Common/Memory/SpanReader.cs create mode 100644 Ryujinx.Common/Memory/SpanWriter.cs create mode 100644 Ryujinx.Common/Utilities/BitfieldExtensions.cs delete mode 100644 Ryujinx.Graphics.Shader/Decoders/BitfieldExtensions.cs delete mode 100644 Ryujinx.Graphics.Vic/Types/BitfieldExtensions.cs delete mode 100644 Ryujinx.HLE/HOS/Kernel/Common/KernelResult.cs delete mode 100644 Ryujinx.HLE/HOS/Kernel/Common/OnScopeExit.cs create mode 100644 Ryujinx.Horizon.Common/ISyscallApi.cs create mode 100644 Ryujinx.Horizon.Common/IThreadContext.cs create mode 100644 Ryujinx.Horizon.Common/InvalidResultException.cs create mode 100644 Ryujinx.Horizon.Common/KernelResult.cs create mode 100644 Ryujinx.Horizon.Common/OnScopeExit.cs create mode 100644 Ryujinx.Horizon.Common/Result.cs create mode 100644 Ryujinx.Horizon.Common/ResultNames.cs create mode 100644 Ryujinx.Horizon.Common/Ryujinx.Horizon.Common.csproj create mode 100644 Ryujinx.Horizon.Common/ThreadTerminatedException.cs create mode 100644 Ryujinx.Horizon.Generators/Hipc/CommandArgType.cs create mode 100644 Ryujinx.Horizon.Generators/Hipc/CommandInterface.cs create mode 100644 Ryujinx.Horizon.Generators/Hipc/HipcGenerator.cs create mode 100644 Ryujinx.Horizon.Generators/Hipc/HipcSyntaxReceiver.cs create mode 100644 Ryujinx.Horizon.Kernel.Generators/CodeGenerator.cs rename {Ryujinx.Horizon.Generators => Ryujinx.Horizon.Kernel.Generators}/Kernel/SyscallGenerator.cs (93%) rename {Ryujinx.Horizon.Generators => Ryujinx.Horizon.Kernel.Generators}/Kernel/SyscallSyntaxReceiver.cs (100%) create mode 100644 Ryujinx.Horizon.Kernel.Generators/Ryujinx.Horizon.Kernel.Generators.csproj create mode 100644 Ryujinx.Horizon/HeapAllocator.cs create mode 100644 Ryujinx.Horizon/HorizonOptions.cs create mode 100644 Ryujinx.Horizon/HorizonStatic.cs create mode 100644 Ryujinx.Horizon/IService.cs create mode 100644 Ryujinx.Horizon/LogManager/LmIpcServer.cs create mode 100644 Ryujinx.Horizon/LogManager/LmLog.cs create mode 100644 Ryujinx.Horizon/LogManager/LmLogger.cs create mode 100644 Ryujinx.Horizon/LogManager/LmMain.cs create mode 100644 Ryujinx.Horizon/Ryujinx.Horizon.csproj create mode 100644 Ryujinx.Horizon/Sdk/DebugUtil.cs create mode 100644 Ryujinx.Horizon/Sdk/Diag/LogSeverity.cs create mode 100644 Ryujinx.Horizon/Sdk/Lm/LogDataChunkKey.cs create mode 100644 Ryujinx.Horizon/Sdk/Lm/LogDestination.cs create mode 100644 Ryujinx.Horizon/Sdk/Lm/LogPacketFlags.cs create mode 100644 Ryujinx.Horizon/Sdk/Lm/LogPacketHeader.cs create mode 100644 Ryujinx.Horizon/Sdk/OsTypes/Event.cs create mode 100644 Ryujinx.Horizon/Sdk/OsTypes/EventClearMode.cs create mode 100644 Ryujinx.Horizon/Sdk/OsTypes/EventType.cs create mode 100644 Ryujinx.Horizon/Sdk/OsTypes/Impl/InterProcessEvent.cs create mode 100644 Ryujinx.Horizon/Sdk/OsTypes/Impl/InterProcessEventImpl.cs create mode 100644 Ryujinx.Horizon/Sdk/OsTypes/Impl/MultiWaitImpl.cs create mode 100644 Ryujinx.Horizon/Sdk/OsTypes/InitializationState.cs create mode 100644 Ryujinx.Horizon/Sdk/OsTypes/InterProcessEventType.cs create mode 100644 Ryujinx.Horizon/Sdk/OsTypes/MultiWait.cs create mode 100644 Ryujinx.Horizon/Sdk/OsTypes/MultiWaitHolder.cs create mode 100644 Ryujinx.Horizon/Sdk/OsTypes/MultiWaitHolderBase.cs create mode 100644 Ryujinx.Horizon/Sdk/OsTypes/MultiWaitHolderOfEvent.cs create mode 100644 Ryujinx.Horizon/Sdk/OsTypes/MultiWaitHolderOfHandle.cs create mode 100644 Ryujinx.Horizon/Sdk/OsTypes/OsEvent.cs create mode 100644 Ryujinx.Horizon/Sdk/OsTypes/OsMultiWait.cs create mode 100644 Ryujinx.Horizon/Sdk/OsTypes/OsProcessHandle.cs create mode 100644 Ryujinx.Horizon/Sdk/OsTypes/OsResult.cs create mode 100644 Ryujinx.Horizon/Sdk/OsTypes/OsSystemEvent.cs create mode 100644 Ryujinx.Horizon/Sdk/OsTypes/OsThreadManager.cs create mode 100644 Ryujinx.Horizon/Sdk/OsTypes/SystemEventType.cs create mode 100644 Ryujinx.Horizon/Sdk/OsTypes/TriBool.cs create mode 100644 Ryujinx.Horizon/Sdk/ServiceUtil.cs create mode 100644 Ryujinx.Horizon/Sdk/Sf/Cmif/CmifDomainInHeader.cs create mode 100644 Ryujinx.Horizon/Sdk/Sf/Cmif/CmifDomainOutHeader.cs create mode 100644 Ryujinx.Horizon/Sdk/Sf/Cmif/CmifDomainRequestType.cs create mode 100644 Ryujinx.Horizon/Sdk/Sf/Cmif/CmifInHeader.cs create mode 100644 Ryujinx.Horizon/Sdk/Sf/Cmif/CmifMessage.cs create mode 100644 Ryujinx.Horizon/Sdk/Sf/Cmif/CmifOutHeader.cs create mode 100644 Ryujinx.Horizon/Sdk/Sf/Cmif/CmifRequest.cs create mode 100644 Ryujinx.Horizon/Sdk/Sf/Cmif/CmifRequestFormat.cs create mode 100644 Ryujinx.Horizon/Sdk/Sf/Cmif/CmifResponse.cs create mode 100644 Ryujinx.Horizon/Sdk/Sf/Cmif/CommandType.cs create mode 100644 Ryujinx.Horizon/Sdk/Sf/Cmif/DomainServiceObject.cs create mode 100644 Ryujinx.Horizon/Sdk/Sf/Cmif/DomainServiceObjectDispatchTable.cs create mode 100644 Ryujinx.Horizon/Sdk/Sf/Cmif/DomainServiceObjectProcessor.cs create mode 100644 Ryujinx.Horizon/Sdk/Sf/Cmif/HandlesToClose.cs create mode 100644 Ryujinx.Horizon/Sdk/Sf/Cmif/InlineContext.cs create mode 100644 Ryujinx.Horizon/Sdk/Sf/Cmif/PointerAndSize.cs create mode 100644 Ryujinx.Horizon/Sdk/Sf/Cmif/ScopedInlineContextChange.cs create mode 100644 Ryujinx.Horizon/Sdk/Sf/Cmif/ServerDomainBase.cs create mode 100644 Ryujinx.Horizon/Sdk/Sf/Cmif/ServerDomainManager.cs create mode 100644 Ryujinx.Horizon/Sdk/Sf/Cmif/ServerMessageProcessor.cs create mode 100644 Ryujinx.Horizon/Sdk/Sf/Cmif/ServerMessageRuntimeMetadata.cs create mode 100644 Ryujinx.Horizon/Sdk/Sf/Cmif/ServiceDispatchContext.cs create mode 100644 Ryujinx.Horizon/Sdk/Sf/Cmif/ServiceDispatchMeta.cs create mode 100644 Ryujinx.Horizon/Sdk/Sf/Cmif/ServiceDispatchTable.cs create mode 100644 Ryujinx.Horizon/Sdk/Sf/Cmif/ServiceDispatchTableBase.cs create mode 100644 Ryujinx.Horizon/Sdk/Sf/Cmif/ServiceObjectHolder.cs create mode 100644 Ryujinx.Horizon/Sdk/Sf/CmifCommandAttribute.cs create mode 100644 Ryujinx.Horizon/Sdk/Sf/CommandArg.cs create mode 100644 Ryujinx.Horizon/Sdk/Sf/CommandArgAttributes.cs create mode 100644 Ryujinx.Horizon/Sdk/Sf/CommandHandler.cs create mode 100644 Ryujinx.Horizon/Sdk/Sf/CommandSerialization.cs create mode 100644 Ryujinx.Horizon/Sdk/Sf/Hipc/Api.cs create mode 100644 Ryujinx.Horizon/Sdk/Sf/Hipc/Header.cs create mode 100644 Ryujinx.Horizon/Sdk/Sf/Hipc/HipcBufferDescriptor.cs create mode 100644 Ryujinx.Horizon/Sdk/Sf/Hipc/HipcBufferFlags.cs create mode 100644 Ryujinx.Horizon/Sdk/Sf/Hipc/HipcBufferMode.cs create mode 100644 Ryujinx.Horizon/Sdk/Sf/Hipc/HipcManager.cs create mode 100644 Ryujinx.Horizon/Sdk/Sf/Hipc/HipcMessage.cs create mode 100644 Ryujinx.Horizon/Sdk/Sf/Hipc/HipcMessageData.cs create mode 100644 Ryujinx.Horizon/Sdk/Sf/Hipc/HipcMetadata.cs create mode 100644 Ryujinx.Horizon/Sdk/Sf/Hipc/HipcReceiveListEntry.cs create mode 100644 Ryujinx.Horizon/Sdk/Sf/Hipc/HipcResult.cs create mode 100644 Ryujinx.Horizon/Sdk/Sf/Hipc/HipcStaticDescriptor.cs create mode 100644 Ryujinx.Horizon/Sdk/Sf/Hipc/ManagerOptions.cs create mode 100644 Ryujinx.Horizon/Sdk/Sf/Hipc/ReceiveResult.cs create mode 100644 Ryujinx.Horizon/Sdk/Sf/Hipc/Server.cs create mode 100644 Ryujinx.Horizon/Sdk/Sf/Hipc/ServerDomainSessionManager.cs create mode 100644 Ryujinx.Horizon/Sdk/Sf/Hipc/ServerManager.cs create mode 100644 Ryujinx.Horizon/Sdk/Sf/Hipc/ServerManagerBase.cs create mode 100644 Ryujinx.Horizon/Sdk/Sf/Hipc/ServerSession.cs create mode 100644 Ryujinx.Horizon/Sdk/Sf/Hipc/ServerSessionManager.cs create mode 100644 Ryujinx.Horizon/Sdk/Sf/Hipc/SpecialHeader.cs create mode 100644 Ryujinx.Horizon/Sdk/Sf/HipcCommandProcessor.cs create mode 100644 Ryujinx.Horizon/Sdk/Sf/IServiceObject.cs create mode 100644 Ryujinx.Horizon/Sdk/Sf/RawDataOffsetCalculator.cs create mode 100644 Ryujinx.Horizon/Sdk/Sf/SfResult.cs create mode 100644 Ryujinx.Horizon/Sdk/Sm/ServiceName.cs create mode 100644 Ryujinx.Horizon/Sdk/Sm/SmApi.cs create mode 100644 Ryujinx.Horizon/ServiceEntry.cs create mode 100644 Ryujinx.Horizon/ServiceTable.cs create mode 100644 Ryujinx.Horizon/Sm/Impl/ServiceInfo.cs create mode 100644 Ryujinx.Horizon/Sm/Impl/ServiceManager.cs create mode 100644 Ryujinx.Horizon/Sm/ManagerService.cs create mode 100644 Ryujinx.Horizon/Sm/SmMain.cs create mode 100644 Ryujinx.Horizon/Sm/SmResult.cs create mode 100644 Ryujinx.Horizon/Sm/UserService.cs 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 _input; + + public int Length => _input.Length; + + public SpanReader(ReadOnlySpan input) + { + _input = input; + } + + public T Read() where T : unmanaged + { + T value = MemoryMarshal.Cast(_input)[0]; + + _input = _input.Slice(Unsafe.SizeOf()); + + return value; + } + + public ReadOnlySpan GetSpan(int size) + { + ReadOnlySpan data = _input.Slice(0, size); + + _input = _input.Slice(size); + + return data; + } + + public T ReadAt(int offset) where T : unmanaged + { + return MemoryMarshal.Cast(_input.Slice(offset))[0]; + } + + public ReadOnlySpan 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 _output; + + public int Length => _output.Length; + + public SpanWriter(Span output) + { + _output = output; + } + + public void Write(T value) where T : unmanaged + { + MemoryMarshal.Cast(_output)[0] = value; + _output = _output.Slice(Unsafe.SizeOf()); + } + + public void Write(ReadOnlySpan data) + { + data.CopyTo(_output.Slice(0, data.Length)); + _output = _output.Slice(data.Length); + } + + public void WriteAt(int offset, T value) where T : unmanaged + { + MemoryMarshal.Cast(_output.Slice(offset))[0] = value; + } + + public void WriteAt(int offset, ReadOnlySpan 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(this T value, int lsb) where T : IBinaryInteger + { + int bitSize = Unsafe.SizeOf() * 8; + lsb &= bitSize - 1; + + return !T.IsZero((value >>> lsb) & T.One); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static T Extract(this T value, int lsb, int length) where T : IBinaryInteger + { + int bitSize = Unsafe.SizeOf() * 8; + lsb &= bitSize - 1; + + return (value >>> lsb) & (~T.Zero >>> (bitSize - length)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static T ExtractSx(this T value, int lsb, int length) where T : IBinaryInteger + { + int bitSize = Unsafe.SizeOf() * 8; + int shift = lsb & (bitSize - 1); + + return (value << (bitSize - (shift + length))) >> (bitSize - length); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static T Insert(this T value, int lsb, bool toInsert) where T : IBinaryInteger + { + int bitSize = Unsafe.SizeOf() * 8; + lsb &= bitSize - 1; + + T mask = T.One << lsb; + + return (value & ~mask) | (toInsert ? mask : T.Zero); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static T Insert(this T value, int lsb, int length, T toInsert) where T : IBinaryInteger + { + int bitSize = Unsafe.SizeOf() * 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(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 list, ulong src, ulong dst, ulong size, MemoryState state) + private Result Add(List 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 list) + private Result CopyToClient(KPageTableBase memoryManager, List 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 list) + private Result UnmapServer(KPageTableBase memoryManager, List 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 list) + private Result RestoreClient(KPageTableBase memoryManager, List 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(); } - 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(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(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 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(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(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(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(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(); } - 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(); } - 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 } /// - 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; } /// - 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; } /// - 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; } /// - 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; } /// - 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; } /// - 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; } /// - 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; } /// 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 /// Current protection of the source memory region /// Desired protection for the destination memory region /// Result of the mapping operation - 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); /// /// Unmaps a region of memory that was previously mapped with . @@ -2926,7 +2927,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory /// Current protection of the destination memory region /// Desired protection of the source memory region /// Result of the unmapping operation - 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); /// /// Maps a region of memory into the specified physical memory region. @@ -2938,7 +2939,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory /// Indicate if the pages should be filled with the value /// The value used to fill pages when is set to true /// Result of the mapping operation - 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); /// /// Maps a region of memory into the specified physical memory region. @@ -2949,7 +2950,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory /// Indicate if the pages should be filled with the value /// The value used to fill pages when is set to true /// Result of the mapping operation - 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); /// /// 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 /// Virtual address of the region to unmap /// Number of pages to unmap /// Result of the unmapping operation - protected abstract KernelResult Unmap(ulong address, ulong pagesCount); + protected abstract Result Unmap(ulong address, ulong pagesCount); /// /// Changes the permissions of a given virtual memory region. @@ -2966,7 +2967,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory /// Number of pages to have their permissions changed /// New permission /// Result of the permission change operation - protected abstract KernelResult Reprotect(ulong address, ulong pagesCount, KMemoryPermission permission); + protected abstract Result Reprotect(ulong address, ulong pagesCount, KMemoryPermission permission); /// /// Changes the permissions of a given virtual memory region. @@ -2975,7 +2976,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory /// Number of pages to have their permissions changed /// New permission /// Result of the permission change operation - protected abstract KernelResult ReprotectWithAttributes(ulong address, ulong pagesCount, KMemoryPermission permission); + protected abstract Result ReprotectWithAttributes(ulong address, ulong pagesCount, KMemoryPermission permission); /// /// 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(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 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 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(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 capabilities, KPageTableBase memoryManager) + public Result InitializeForKernel(ReadOnlySpan 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 capabilities, KPageTableBase memoryManager) + public Result InitializeForUser(ReadOnlySpan capabilities, KPageTableBase memoryManager) { return Parse(capabilities, memoryManager); } - private KernelResult Parse(ReadOnlySpan capabilities, KPageTableBase memoryManager) + private Result Parse(ReadOnlySpan 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 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(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,11 +376,20 @@ 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 handles, int replyTargetHandle, long timeout) + public Result ReplyAndReceive(out int handleIndex, ReadOnlySpan 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(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(handles[handleIndex]); @@ -705,12 +715,23 @@ 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; @@ -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(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(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(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(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.Empty, timeout); + } + + public Result WaitSynchronization(out int handleIndex, ReadOnlySpan handles, long timeout) + { + handleIndex = 0; + + if ((uint)handles.Length > KThread.MaxWaitSyncObjects) + { + return KernelResult.MaximumExceeded; + } + + KThread currentThread = KernelStatic.GetCurrentThread(); + + var syncObjs = new Span(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(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(); } - 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(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 syncObjs, long timeout, out int handleIndex) + public Result WaitFor(Span 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(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 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 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) 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) 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) 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) 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 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 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, buffer, buffer) 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 @@ - + + + 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 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 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 + { + 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 _names = new Dictionary() + { + { 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 @@ + + + + net7.0 + + + + + + + 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 CommandImplementations { get; } + + public CommandInterface(ClassDeclarationSyntax classDeclarationSyntax) + { + ClassDeclarationSyntax = classDeclarationSyntax; + CommandImplementations = new List(); + } + } +} 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 GetCommandHandlers()"); + generator.EnterScope($"return new Dictionary()"); + + 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 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 inRawData, " + + "ref Span 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 outParameters = new List(); + + 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 {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 {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({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 CommandInterfaces { get; } + + public HipcSyntaxReceiver() + { + CommandInterfaces = new List(); + } + + 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 similarity index 93% rename from Ryujinx.Horizon.Generators/Kernel/SyscallGenerator.cs rename to 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 similarity index 100% rename from Ryujinx.Horizon.Generators/Kernel/SyscallSyntaxReceiver.cs rename to 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 @@ + + + + netstandard2.0 + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + 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 + { + 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 _freeRanges; + private ulong _currentHeapSize; + + public HeapAllocator() + { + _freeRanges = new List(); + _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 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 message, ulong processId) + { + ref LogPacketHeader header = ref MemoryMarshal.Cast(message)[0]; + + uint expectedMessageSize = (uint)Unsafe.SizeOf() + 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 message) + { + SpanReader reader = new SpanReader(message); + + LogPacketHeader header = reader.Read(); + + 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()}"; + } + else if (field == LogDataChunkKey.DropCount) + { + fieldStr = $"{field}: {reader.Read()}"; + } + else if (field == LogDataChunkKey.Time) + { + fieldStr = $"{field}: {reader.Read()}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(); + + 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 @@ + + + + net7.0 + + + + + + + + + + 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 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 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 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 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 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 _multiWaits; + + private object _lock; + + private int _waitingThreadHandle; + + private MultiWaitHolderBase _signaledHolder; + + public long CurrentTime { get; private set; } + + public MultiWaitImpl() + { + _multiWaits = new List(); + + _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 objectHandles = new int[64]; + + Span 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 handles, Span 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 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 _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(), + 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 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 output, CmifRequestFormat format) + { + int totalSize = 16; + + if (format.ObjectId != 0) + { + totalSize += Unsafe.SizeOf() + format.ObjectsCount * sizeof(int); + } + + totalSize += Unsafe.SizeOf() + 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 data = request.Hipc.DataWords; + + if (format.ObjectId != 0) + { + ref CmifDomainInHeader domainHeader = ref MemoryMarshal.Cast(data)[0]; + + int payloadSize = Unsafe.SizeOf() + 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() / sizeof(uint)); + + request.Objects = data.Slice((payloadSize + sizeof(uint) - 1) / sizeof(uint)); + } + + ref CmifInHeader header = ref MemoryMarshal.Cast(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(data).Slice(Unsafe.SizeOf()); + + int paddingSizeBefore = (rawDataSizeInWords - request.Hipc.DataWords.Length) * sizeof(uint); + + Span outPointerTable = MemoryMarshal.Cast(request.Hipc.DataWords).Slice(outPointerSizeTableOffset - paddingSizeBefore); + request.OutPointerSizes = MemoryMarshal.Cast(outPointerTable); + request.ServerPointerSize = format.ServerPointerSize; + + return request; + } + + public static Result ParseResponse(out CmifResponse response, Span input, bool isDomain, int size) + { + HipcMessage responseMessage = new HipcMessage(input); + + Span data = MemoryMarshal.Cast(responseMessage.Data.DataWords); + Span objects = Span.Empty; + + if (isDomain) + { + data = data.Slice(Unsafe.SizeOf()); + objects = MemoryMarshal.Cast(data.Slice(Unsafe.SizeOf() + size)); + } + + CmifOutHeader header = MemoryMarshal.Cast(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()), + 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 Data; + public Span OutPointerSizes; + public Span 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 Data; + public ReadOnlySpan Objects; + public ReadOnlySpan CopyHandles; + public ReadOnlySpan 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 inRawData) + { + return ProcessMessageImpl(ref context, ((DomainServiceObject)context.ServiceObject).GetServerDomain(), inRawData); + } + + private Result ProcessMessageImpl(ref ServiceDispatchContext context, ServerDomainBase domain, ReadOnlySpan inRawData) + { + if (inRawData.Length < Unsafe.SizeOf()) + { + return SfResult.InvalidHeaderSize; + } + + var inHeader = MemoryMarshal.Cast(inRawData)[0]; + + ReadOnlySpan inDomainRawData = inRawData.Slice(Unsafe.SizeOf()); + + 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 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()), + (byte)(runtimeMetadata.OutHeadersSize + Unsafe.SizeOf()), + 0, + 0); + } + + public override Result PrepareForProcess(ref ServiceDispatchContext context, ServerMessageRuntimeMetadata runtimeMetadata) + { + if (_implMetadata.InObjectsCount != InObjectsCount) + { + return SfResult.InvalidInObjectsCount; + } + + Result result = _domain.ReserveIds(new Span(_reservedObjectIds).Slice(0, OutObjectsCount)); + + if (result.IsFailure) + { + return result; + } + + return _implProcessor.PrepareForProcess(ref context, runtimeMetadata); + } + + public override Result GetInObjects(Span 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 outRawData, ServerMessageRuntimeMetadata runtimeMetadata) + { + var response = _implProcessor.PrepareForReply(ref context, out outRawData, runtimeMetadata); + + int outHeaderSize = Unsafe.SizeOf(); + 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 outRawData, ServerMessageRuntimeMetadata runtimeMetadata) + { + _implProcessor.PrepareForErrorReply(ref context, out outRawData, runtimeMetadata); + + int outHeaderSize = Unsafe.SizeOf(); + int implOutDataTotalSize = ImplOutDataTotalSize; + + DebugUtil.Assert(outHeaderSize + implOutDataTotalSize <= outRawData.Length); + + outRawData = outRawData.Slice(outHeaderSize); + + _domain.UnreserveIds(new Span(_reservedObjectIds).Slice(0, OutObjectsCount)); + } + + public override void SetOutObjects(scoped ref ServiceDispatchContext context, HipcMessageData response, Span outObjects) + { + int outObjectsCount = OutObjectsCount; + Span 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 outObjectIds = MemoryMarshal.Cast(MemoryMarshal.Cast(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 outIds); + public abstract void UnreserveIds(ReadOnlySpan 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 Node { get; set; } + + public Entry(int id) + { + Id = id; + } + } + + private readonly LinkedList _freeList; + private readonly Entry[] _entries; + + public EntryManager(int count) + { + _freeList = new LinkedList(); + _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 _entries; + + public Domain(ServerDomainManager manager) + { + _manager = manager; + _entries = new LinkedList(); + } + + 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 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 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 _domains; + private int _maxDomains; + + public ServerDomainManager(int entryCount, int maxDomains) + { + _entryManager = new EntryManager(entryCount); + _entryOwnerLock = new object(); + _domains = new HashSet(); + _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 inObjects); + public abstract HipcMessageData PrepareForReply(scoped ref ServiceDispatchContext context, out Span outRawData, ServerMessageRuntimeMetadata runtimeMetadata); + public abstract void PrepareForErrorReply(scoped ref ServiceDispatchContext context, out Span outRawData, ServerMessageRuntimeMetadata runtimeMetadata); + public abstract void SetOutObjects(scoped ref ServiceDispatchContext context, HipcMessageData response, Span 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 InMessageBuffer; + public Span 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 _entries; + + public ServiceDispatchTable(string objectName, IReadOnlyDictionary entries) + { + _objectName = objectName; + _entries = entries; + } + + public override Result ProcessMessage(ref ServiceDispatchContext context, ReadOnlySpan 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 inRawData); + + protected Result ProcessMessageImpl(ref ServiceDispatchContext context, ReadOnlySpan inRawData, IReadOnlyDictionary entries, string objectName) + { + if (inRawData.Length < Unsafe.SizeOf()) + { + Logger.Warning?.Print(LogClass.KernelIpc, $"Request message size 0x{inRawData.Length:X} is invalid"); + + return SfResult.InvalidHeaderSize; + } + + CmifInHeader inHeader = MemoryMarshal.Cast(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 inMessageRawData = inRawData[Unsafe.SizeOf()..]; + uint commandId = inHeader.CommandId; + + var outHeader = Span.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 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 outRawData) + { + var response = HipcMessage.WriteResponse(context.OutMessageBuffer, 0, 0x20 / sizeof(uint), 0, 0); + outRawData = MemoryMarshal.Cast(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 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 inRawData, + ref Span 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 outHeader, ref ServiceDispatchContext context, ReadOnlySpan 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 outHeader, ref Span outRawData) + { + outHeader = MemoryMarshal.Cast(outRawData).Slice(0, 1); + outRawData = outRawData.Slice(Unsafe.SizeOf()); + } + } +} 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 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(PointerAndSize bufferRange) where T : unmanaged + { + var writableRegion = GetWritableRegion(bufferRange); + return ref MemoryMarshal.Cast(writableRegion.Memory.Span)[0]; + } + + public static object DeserializeArg(ref ServiceDispatchContext context, ReadOnlySpan inRawData, int offset) where T : unmanaged + { + return MemoryMarshal.Cast(inRawData.Slice(offset, Unsafe.SizeOf()))[0]; + } + + public static T DeserializeArg(ReadOnlySpan inRawData, int offset) where T : unmanaged + { + return MemoryMarshal.Cast(inRawData.Slice(offset, Unsafe.SizeOf()))[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(Span outRawData, int offset, T value) where T : unmanaged + { + MemoryMarshal.Cast(outRawData.Slice(offset, Unsafe.SizeOf()))[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 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 messageBuffer) + { + Span 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 messageBuffer) + { + Result result = ReplyImpl(sessionHandle, messageBuffer); + + result.AbortUnless(KernelResult.TimedOut, KernelResult.PortRemoteClosed); + + return Result.Success; + } + + private static Result ReplyImpl(int sessionHandle, ReadOnlySpan messageBuffer) + { + Span 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 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 data) + { + int initialLength = data.Length; + + Header header = MemoryMarshal.Cast(data)[0]; + + data = data.Slice(Unsafe.SizeOf
()); + + 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(data)[0]; + + data = data.Slice(Unsafe.SizeOf()); + + if (specialHeader.SendPid) + { + pid = MemoryMarshal.Cast(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 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 destination, HipcMetadata meta) + { + int initialLength = destination.Length; + + bool hasSpecialHeader = meta.SendPid || meta.CopyHandlesCount != 0 || meta.MoveHandlesCount != 0; + + MemoryMarshal.Cast(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
()); + + if (hasSpecialHeader) + { + MemoryMarshal.Cast(destination)[0] = new SpecialHeader() + { + SendPid = meta.SendPid, + CopyHandlesCount = meta.CopyHandlesCount, + MoveHandlesCount = meta.MoveHandlesCount + }; + + destination = destination.Slice(Unsafe.SizeOf()); + + if (meta.SendPid) + { + destination = destination.Slice(sizeof(ulong)); + } + } + + return CreateMessageData(meta, destination, initialLength); + } + + private static HipcMessageData CreateMessageData(HipcMetadata meta, Span data, int initialLength) + { + Span copyHandles = Span.Empty; + + if (meta.CopyHandlesCount != 0) + { + copyHandles = MemoryMarshal.Cast(data).Slice(0, meta.CopyHandlesCount); + + data = data.Slice(meta.CopyHandlesCount * sizeof(int)); + } + + Span moveHandles = Span.Empty; + + if (meta.MoveHandlesCount != 0) + { + moveHandles = MemoryMarshal.Cast(data).Slice(0, meta.MoveHandlesCount); + + data = data.Slice(meta.MoveHandlesCount * sizeof(int)); + } + + Span sendStatics = Span.Empty; + + if (meta.SendStaticsCount != 0) + { + sendStatics = MemoryMarshal.Cast(data).Slice(0, meta.SendStaticsCount); + + data = data.Slice(meta.SendStaticsCount * Unsafe.SizeOf()); + } + + Span sendBuffers = Span.Empty; + + if (meta.SendBuffersCount != 0) + { + sendBuffers = MemoryMarshal.Cast(data).Slice(0, meta.SendBuffersCount); + + data = data.Slice(meta.SendBuffersCount * Unsafe.SizeOf()); + } + + Span receiveBuffers = Span.Empty; + + if (meta.ReceiveBuffersCount != 0) + { + receiveBuffers = MemoryMarshal.Cast(data).Slice(0, meta.ReceiveBuffersCount); + + data = data.Slice(meta.ReceiveBuffersCount * Unsafe.SizeOf()); + } + + Span exchangeBuffers = Span.Empty; + + if (meta.ExchangeBuffersCount != 0) + { + exchangeBuffers = MemoryMarshal.Cast(data).Slice(0, meta.ExchangeBuffersCount); + + data = data.Slice(meta.ExchangeBuffersCount * Unsafe.SizeOf()); + } + + Span dataWords = Span.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(data).Slice(padding, meta.DataWordsCount - padding); + + data = data.Slice(meta.DataWordsCount * sizeof(uint)); + } + + Span receiveList = Span.Empty; + + if (meta.ReceiveStaticsCount != 0) + { + int receiveListSize = meta.ReceiveStaticsCount == AutoReceiveStatic ? 1 : meta.ReceiveStaticsCount; + + receiveList = MemoryMarshal.Cast(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 SendStatics; + public Span SendBuffers; + public Span ReceiveBuffers; + public Span ExchangeBuffers; + public Span DataWords; + public Span ReceiveList; + public Span CopyHandles; + public Span 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 inMessage, Span 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 _sessions; + private readonly HashSet _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(); + _servers = new HashSet(); + } + + 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 message) + { + return MemoryMarshal.Cast(message)[0].Type; + } + + public Result ProcessRequest(ServerSession session, Span 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 inMessage, Span 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 inMessage) + { + switch (commandType) + { + case CommandType.RequestWithContext: + case CommandType.ControlWithContext: + if (inMessage.Length >= 0x10) + { + return MemoryMarshal.Cast(inMessage)[3]; + } + break; + } + + return 0; + } + + protected Result ReceiveRequest(ServerSession session, Span message) + { + return ReceiveRequestImpl(session, message); + } + + private Result ReceiveRequestImpl(ServerSession session, Span 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(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 inMessage, Span outMessage) + { + return SfResult.NotSupported; + } + + protected virtual Result DispatchRequest( + ServiceObjectHolder objectHolder, + ServerSession session, + Span inMessage, + Span 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 inRawData = MemoryMarshal.Cast(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(context.Request.Data.DataWords); + var recvPointerSizes = MemoryMarshal.Cast(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(), + (byte)Unsafe.SizeOf(), + (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 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 inObjects) + { + return SfResult.NotSupported; + } + + public override HipcMessageData PrepareForReply(scoped ref ServiceDispatchContext context, out Span 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(response.DataWords); + return response; + } + + public override void PrepareForErrorReply(scoped ref ServiceDispatchContext context, out Span 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(response.DataWords); + } + + public void SetOutObjects(ref ServiceDispatchContext context, HipcMessageData response, Span 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 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 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 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 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 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 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 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 GetServices(HorizonOptions options) + { + List entries = new List(); + + void RegisterService() where T : IService + { + entries.Add(new ServiceEntry(T.Main, options)); + } + + RegisterService(); + + 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