From 521751795a1c97c0d97f6f8904a3be69b13d3a9d Mon Sep 17 00:00:00 2001 From: gdkchan Date: Thu, 16 Aug 2018 20:47:36 -0300 Subject: Code style fixes and nits on the HLE project (#355) * Some style fixes and nits on ITimeZoneService * Remove some unneeded usings * Remove the Ryujinx.HLE.OsHle.Handles namespace * Remove hbmenu automatic load on process exit * Rename Ns to Device, rename Os to System, rename SystemState to State * Move Exceptions and Utilities out of OsHle * Rename OsHle to HOS * Rename OsHle folder to HOS * IManagerDisplayService and ISystemDisplayService style fixes * BsdError shouldn't be public * Add a empty new line before using static * Remove unused file * Some style fixes on NPDM * Exit gracefully when the application is closed * Code style fixes on IGeneralService * Add 0x prefix on values printed as hex * Small improvements on finalization code * Move ProcessId and ThreadId out of AThreadState * Rename VFs to FileSystem * FsAccessHeader shouldn't be public. Also fix file names casing * More case changes on NPDM * Remove unused files * Move using to the correct place on NPDM * Use properties on KernelAccessControlMmio * Address PR feedback --- ChocolArm64/AThread.cs | 2 - ChocolArm64/Memory/AMemory.cs | 16 +- ChocolArm64/State/AThreadState.cs | 8 +- ChocolArm64/Translation/AILEmitterCtx.cs | 21 + Ryujinx.Audio/IAalOutput.cs | 4 +- Ryujinx.Audio/OpenAL/OpenALAudioOut.cs | 24 +- Ryujinx.Graphics/Gal/IGalShader.cs | 1 - Ryujinx.Graphics/Gal/OpenGL/OGLFrameBuffer.cs | 1 - Ryujinx.Graphics/Gal/OpenGL/OGLRasterizer.cs | 1 - Ryujinx.Graphics/Gal/OpenGL/OGLShaderProgram.cs | 1 - Ryujinx.Graphics/Gal/Shader/ShaderDecodeSpecial.cs | 4 +- .../Exceptions/GuestBrokeExecutionException.cs | 11 + Ryujinx.HLE/Exceptions/InvalidNpdmException.cs | 9 + .../Exceptions/UndefinedInstructionException.cs | 13 + Ryujinx.HLE/Gpu/Texture/TextureHelper.cs | 2 +- Ryujinx.HLE/Gpu/Texture/TextureReader.cs | 2 +- Ryujinx.HLE/Gpu/Texture/TextureWriter.cs | 2 - Ryujinx.HLE/HOS/Diagnostics/Demangler.cs | 416 +++++ Ryujinx.HLE/HOS/ErrorCode.cs | 10 + Ryujinx.HLE/HOS/ErrorModule.cs | 101 ++ Ryujinx.HLE/HOS/Font/SharedFontManager.cs | 122 ++ Ryujinx.HLE/HOS/Font/SharedFontType.cs | 13 + Ryujinx.HLE/HOS/GlobalStateTable.cs | 69 + Ryujinx.HLE/HOS/Homebrew.cs | 77 + Ryujinx.HLE/HOS/Horizon.cs | 227 +++ Ryujinx.HLE/HOS/IdDictionary.cs | 73 + Ryujinx.HLE/HOS/Ipc/IpcBuffDesc.cs | 27 + Ryujinx.HLE/HOS/Ipc/IpcHandleDesc.cs | 92 ++ Ryujinx.HLE/HOS/Ipc/IpcHandler.cs | 140 ++ Ryujinx.HLE/HOS/Ipc/IpcMagic.cs | 8 + Ryujinx.HLE/HOS/Ipc/IpcMessage.cs | 215 +++ Ryujinx.HLE/HOS/Ipc/IpcMessageType.cs | 12 + Ryujinx.HLE/HOS/Ipc/IpcPtrBuffDesc.cs | 26 + Ryujinx.HLE/HOS/Ipc/IpcRecvListBuffDesc.cs | 19 + Ryujinx.HLE/HOS/Ipc/ServiceProcessRequest.cs | 4 + Ryujinx.HLE/HOS/Kernel/AddressArbiter.cs | 111 ++ Ryujinx.HLE/HOS/Kernel/AddressSpaceType.cs | 10 + Ryujinx.HLE/HOS/Kernel/KEvent.cs | 4 + Ryujinx.HLE/HOS/Kernel/KMemoryBlock.cs | 43 + Ryujinx.HLE/HOS/Kernel/KMemoryInfo.cs | 33 + Ryujinx.HLE/HOS/Kernel/KMemoryManager.cs | 1081 +++++++++++++ Ryujinx.HLE/HOS/Kernel/KProcessHandleTable.cs | 34 + Ryujinx.HLE/HOS/Kernel/KProcessScheduler.cs | 370 +++++ Ryujinx.HLE/HOS/Kernel/KSession.cs | 31 + Ryujinx.HLE/HOS/Kernel/KSharedMemory.cs | 14 + Ryujinx.HLE/HOS/Kernel/KSynchronizationObject.cs | 28 + Ryujinx.HLE/HOS/Kernel/KThread.cs | 98 ++ Ryujinx.HLE/HOS/Kernel/KTlsPageManager.cs | 60 + Ryujinx.HLE/HOS/Kernel/KTransferMemory.cs | 14 + Ryujinx.HLE/HOS/Kernel/KernelErr.cs | 22 + Ryujinx.HLE/HOS/Kernel/MemoryAttribute.cs | 22 + Ryujinx.HLE/HOS/Kernel/MemoryPermission.cs | 18 + Ryujinx.HLE/HOS/Kernel/MemoryState.cs | 49 + Ryujinx.HLE/HOS/Kernel/NsTimeConverter.cs | 19 + Ryujinx.HLE/HOS/Kernel/SchedulerThread.cs | 48 + Ryujinx.HLE/HOS/Kernel/SvcHandler.cs | 123 ++ Ryujinx.HLE/HOS/Kernel/SvcMemory.cs | 577 +++++++ Ryujinx.HLE/HOS/Kernel/SvcSystem.cs | 373 +++++ Ryujinx.HLE/HOS/Kernel/SvcThread.cs | 385 +++++ Ryujinx.HLE/HOS/Kernel/SvcThreadSync.cs | 523 ++++++ Ryujinx.HLE/HOS/Kernel/ThreadQueue.cs | 158 ++ Ryujinx.HLE/HOS/Process.cs | 438 +++++ Ryujinx.HLE/HOS/ServiceCtx.cs | 39 + Ryujinx.HLE/HOS/Services/Acc/AccErr.cs | 7 + .../Services/Acc/IAccountServiceForApplication.cs | 125 ++ .../HOS/Services/Acc/IManagerForApplication.cs | 38 + Ryujinx.HLE/HOS/Services/Acc/IProfile.cs | 58 + Ryujinx.HLE/HOS/Services/Am/AmErr.cs | 7 + Ryujinx.HLE/HOS/Services/Am/FocusState.cs | 8 + .../Services/Am/IAllSystemAppletProxiesService.cs | 27 + Ryujinx.HLE/HOS/Services/Am/IApplicationCreator.cs | 20 + .../HOS/Services/Am/IApplicationFunctions.cs | 117 ++ Ryujinx.HLE/HOS/Services/Am/IApplicationProxy.cs | 83 + .../HOS/Services/Am/IApplicationProxyService.cs | 27 + Ryujinx.HLE/HOS/Services/Am/IAudioController.cs | 72 + Ryujinx.HLE/HOS/Services/Am/ICommonStateGetter.cs | 115 ++ Ryujinx.HLE/HOS/Services/Am/IDebugFunctions.cs | 20 + Ryujinx.HLE/HOS/Services/Am/IDisplayController.cs | 20 + .../HOS/Services/Am/IGlobalStateController.cs | 20 + Ryujinx.HLE/HOS/Services/Am/IHomeMenuFunctions.cs | 46 + .../HOS/Services/Am/ILibraryAppletAccessor.cs | 71 + .../HOS/Services/Am/ILibraryAppletCreator.cs | 37 + Ryujinx.HLE/HOS/Services/Am/ISelfController.cs | 145 ++ Ryujinx.HLE/HOS/Services/Am/IStorage.cs | 31 + Ryujinx.HLE/HOS/Services/Am/IStorageAccessor.cs | 83 + Ryujinx.HLE/HOS/Services/Am/ISystemAppletProxy.cs | 99 ++ Ryujinx.HLE/HOS/Services/Am/IWindowController.cs | 38 + Ryujinx.HLE/HOS/Services/Am/MessageInfo.cs | 9 + Ryujinx.HLE/HOS/Services/Am/OperationMode.cs | 8 + Ryujinx.HLE/HOS/Services/Am/StorageHelper.cs | 27 + Ryujinx.HLE/HOS/Services/Apm/IManager.cs | 27 + Ryujinx.HLE/HOS/Services/Apm/ISession.cs | 41 + .../HOS/Services/Apm/PerformanceConfiguration.cs | 18 + Ryujinx.HLE/HOS/Services/Apm/PerformanceMode.cs | 8 + Ryujinx.HLE/HOS/Services/Aud/AudErr.cs | 9 + .../HOS/Services/Aud/AudioOut/AudioOutData.cs | 14 + Ryujinx.HLE/HOS/Services/Aud/AudioOut/IAudioOut.cs | 163 ++ .../HOS/Services/Aud/AudioRenderer/AudioConsts.cs | 8 + .../HOS/Services/Aud/AudioRenderer/BehaviorIn.cs | 11 + .../HOS/Services/Aud/AudioRenderer/BiquadFilter.cs | 16 + .../Services/Aud/AudioRenderer/IAudioRenderer.cs | 318 ++++ .../Aud/AudioRenderer/MemoryPoolContext.cs | 12 + .../HOS/Services/Aud/AudioRenderer/MemoryPoolIn.cs | 14 + .../Services/Aud/AudioRenderer/MemoryPoolOut.cs | 12 + .../Services/Aud/AudioRenderer/MemoryPoolState.cs | 13 + .../HOS/Services/Aud/AudioRenderer/PlayState.cs | 9 + .../HOS/Services/Aud/AudioRenderer/Resampler.cs | 191 +++ .../Services/Aud/AudioRenderer/UpdateDataHeader.cs | 22 + .../Aud/AudioRenderer/VoiceChannelResourceIn.cs | 10 + .../HOS/Services/Aud/AudioRenderer/VoiceContext.cs | 188 +++ .../HOS/Services/Aud/AudioRenderer/VoiceIn.cs | 49 + .../HOS/Services/Aud/AudioRenderer/VoiceOut.cs | 12 + .../HOS/Services/Aud/AudioRenderer/WaveBuffer.cs | 20 + .../HOS/Services/Aud/AudioRendererParameter.cs | 22 + Ryujinx.HLE/HOS/Services/Aud/IAudioDevice.cs | 223 +++ Ryujinx.HLE/HOS/Services/Aud/IAudioOutManager.cs | 170 ++ .../HOS/Services/Aud/IAudioRendererManager.cs | 169 ++ Ryujinx.HLE/HOS/Services/Aud/SampleFormat.cs | 13 + Ryujinx.HLE/HOS/Services/Bcat/IBcatService.cs | 21 + .../Services/Bcat/IDeliveryCacheStorageService.cs | 21 + Ryujinx.HLE/HOS/Services/Bcat/IServiceCreator.cs | 39 + Ryujinx.HLE/HOS/Services/Bsd/BsdError.cs | 8 + Ryujinx.HLE/HOS/Services/Bsd/BsdSocket.cs | 18 + Ryujinx.HLE/HOS/Services/Bsd/IClient.cs | 445 +++++ .../HOS/Services/Caps/IAlbumAccessorService.cs | 20 + .../HOS/Services/Caps/IScreenshotService.cs | 20 + Ryujinx.HLE/HOS/Services/Friend/IFriendService.cs | 49 + Ryujinx.HLE/HOS/Services/Friend/IServiceCreator.cs | 27 + Ryujinx.HLE/HOS/Services/FspSrv/FsErr.cs | 9 + Ryujinx.HLE/HOS/Services/FspSrv/IDirectory.cs | 116 ++ Ryujinx.HLE/HOS/Services/FspSrv/IFile.cs | 110 ++ Ryujinx.HLE/HOS/Services/FspSrv/IFileSystem.cs | 412 +++++ .../HOS/Services/FspSrv/IFileSystemProxy.cs | 74 + Ryujinx.HLE/HOS/Services/FspSrv/IStorage.cs | 51 + .../HOS/Services/Hid/IActiveVibrationDeviceList.cs | 27 + Ryujinx.HLE/HOS/Services/Hid/IAppletResource.cs | 34 + Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs | 299 ++++ Ryujinx.HLE/HOS/Services/IIpcService.cs | 10 + Ryujinx.HLE/HOS/Services/IpcService.cs | 183 +++ Ryujinx.HLE/HOS/Services/Lm/ILogService.cs | 27 + Ryujinx.HLE/HOS/Services/Lm/ILogger.cs | 86 + Ryujinx.HLE/HOS/Services/Lm/LmLogField.cs | 13 + Ryujinx.HLE/HOS/Services/Lm/LmLogLevel.cs | 11 + Ryujinx.HLE/HOS/Services/Mm/IRequest.cs | 46 + Ryujinx.HLE/HOS/Services/Nfp/DeviceState.cs | 7 + Ryujinx.HLE/HOS/Services/Nfp/IUser.cs | 114 ++ Ryujinx.HLE/HOS/Services/Nfp/IUserManager.cs | 27 + Ryujinx.HLE/HOS/Services/Nfp/State.cs | 8 + Ryujinx.HLE/HOS/Services/Nifm/IGeneralService.cs | 58 + Ryujinx.HLE/HOS/Services/Nifm/IRequest.cs | 95 ++ Ryujinx.HLE/HOS/Services/Nifm/IStaticService.cs | 35 + Ryujinx.HLE/HOS/Services/Nifm/NifmErr.cs | 7 + .../HOS/Services/Ns/IAddOnContentManager.cs | 42 + .../HOS/Services/Ns/IServiceGetterInterface.cs | 20 + .../HOS/Services/Ns/ISystemUpdateInterface.cs | 20 + .../Services/Ns/IVulnerabilityManagerInterface.cs | 20 + Ryujinx.HLE/HOS/Services/Nv/INvDrvServices.cs | 231 +++ Ryujinx.HLE/HOS/Services/Nv/NvFd.cs | 12 + .../HOS/Services/Nv/NvGpuAS/NvGpuASAllocSpace.cs | 11 + Ryujinx.HLE/HOS/Services/Nv/NvGpuAS/NvGpuASCtx.cs | 197 +++ .../HOS/Services/Nv/NvGpuAS/NvGpuASIoctl.cs | 329 ++++ .../HOS/Services/Nv/NvGpuAS/NvGpuASMapBufferEx.cs | 13 + .../HOS/Services/Nv/NvGpuAS/NvGpuASRemap.cs | 12 + .../HOS/Services/Nv/NvGpuAS/NvGpuASUnmapBuffer.cs | 7 + .../Nv/NvGpuGpu/NvGpuGpuGetActiveSlotMask.cs | 8 + .../Nv/NvGpuGpu/NvGpuGpuGetCharacteristics.cs | 43 + .../Services/Nv/NvGpuGpu/NvGpuGpuGetTpcMasks.cs | 11 + .../HOS/Services/Nv/NvGpuGpu/NvGpuGpuIoctl.cs | 187 +++ .../Nv/NvGpuGpu/NvGpuGpuZcullGetCtxSize.cs | 7 + .../Services/Nv/NvGpuGpu/NvGpuGpuZcullGetInfo.cs | 16 + Ryujinx.HLE/HOS/Services/Nv/NvHelper.cs | 10 + .../HOS/Services/Nv/NvHostChannel/NvChannel.cs | 7 + .../HOS/Services/Nv/NvHostChannel/NvChannelName.cs | 7 + .../Nv/NvHostChannel/NvHostChannelIoctl.cs | 210 +++ .../Nv/NvHostChannel/NvHostChannelSubmitGpfifo.cs | 11 + .../HOS/Services/Nv/NvHostCtrl/NvHostCtrlIoctl.cs | 398 +++++ .../Services/Nv/NvHostCtrl/NvHostCtrlSyncPtRead.cs | 8 + .../Services/Nv/NvHostCtrl/NvHostCtrlSyncPtWait.cs | 9 + .../Nv/NvHostCtrl/NvHostCtrlSyncPtWaitEx.cs | 10 + .../Services/Nv/NvHostCtrl/NvHostCtrlUserCtx.cs | 19 + .../HOS/Services/Nv/NvHostCtrl/NvHostEvent.cs | 10 + .../HOS/Services/Nv/NvHostCtrl/NvHostEventState.cs | 10 + .../HOS/Services/Nv/NvHostCtrl/NvHostSyncPt.cs | 107 ++ Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapAlloc.cs | 12 + Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapCreate.cs | 8 + Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapFree.cs | 11 + Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapFromId.cs | 8 + Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapGetId.cs | 8 + Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapHandle.cs | 37 + .../HOS/Services/Nv/NvMap/NvMapHandleParam.cs | 12 + Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapIoctl.cs | 302 ++++ Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapParam.cs | 9 + Ryujinx.HLE/HOS/Services/Nv/NvResult.cs | 14 + .../HOS/Services/Pctl/IParentalControlService.cs | 41 + .../Pctl/IParentalControlServiceFactory.cs | 35 + Ryujinx.HLE/HOS/Services/Pl/ISharedFontManager.cs | 125 ++ Ryujinx.HLE/HOS/Services/Prepo/IPrepoService.cs | 28 + Ryujinx.HLE/HOS/Services/ServiceFactory.cs | 181 +++ Ryujinx.HLE/HOS/Services/Set/ISettingsServer.cs | 79 + .../HOS/Services/Set/ISystemSettingsServer.cs | 151 ++ Ryujinx.HLE/HOS/Services/Set/NxSettings.cs | 1711 ++++++++++++++++++++ Ryujinx.HLE/HOS/Services/Sfdnsres/IResolver.cs | 20 + Ryujinx.HLE/HOS/Services/Sm/IUserInterface.cs | 69 + Ryujinx.HLE/HOS/Services/Spl/IRandomInterface.cs | 50 + Ryujinx.HLE/HOS/Services/Ssl/ISslService.cs | 30 + Ryujinx.HLE/HOS/Services/Time/IStaticService.cs | 74 + Ryujinx.HLE/HOS/Services/Time/ISteadyClock.cs | 53 + Ryujinx.HLE/HOS/Services/Time/ISystemClock.cs | 107 ++ Ryujinx.HLE/HOS/Services/Time/ITimeZoneService.cs | 280 ++++ Ryujinx.HLE/HOS/Services/Time/SystemClockType.cs | 10 + Ryujinx.HLE/HOS/Services/Vi/Display.cs | 12 + Ryujinx.HLE/HOS/Services/Vi/GbpBuffer.cs | 60 + .../HOS/Services/Vi/IApplicationDisplayService.cs | 233 +++ .../HOS/Services/Vi/IApplicationRootService.cs | 29 + Ryujinx.HLE/HOS/Services/Vi/IHOSBinderDriver.cs | 100 ++ .../HOS/Services/Vi/IManagerDisplayService.cs | 54 + Ryujinx.HLE/HOS/Services/Vi/IManagerRootService.cs | 29 + .../HOS/Services/Vi/ISystemDisplayService.cs | 48 + Ryujinx.HLE/HOS/Services/Vi/ISystemRootService.cs | 29 + Ryujinx.HLE/HOS/Services/Vi/NvFlinger.cs | 416 +++++ Ryujinx.HLE/HOS/Services/Vi/Parcel.cs | 58 + Ryujinx.HLE/HOS/SystemState/AppletStateMgr.cs | 62 + Ryujinx.HLE/HOS/SystemState/ColorSet.cs | 8 + Ryujinx.HLE/HOS/SystemState/OpenCloseState.cs | 8 + Ryujinx.HLE/HOS/SystemState/SystemLanguage.cs | 23 + Ryujinx.HLE/HOS/SystemState/SystemStateMgr.cs | 145 ++ Ryujinx.HLE/HOS/SystemState/UserId.cs | 76 + Ryujinx.HLE/HOS/SystemState/UserProfile.cs | 36 + Ryujinx.HLE/Hid/Hid.cs | 2 +- Ryujinx.HLE/Loaders/Executable.cs | 6 +- Ryujinx.HLE/Loaders/Npdm/ACI0.cs | 58 +- Ryujinx.HLE/Loaders/Npdm/ACID.cs | 72 +- Ryujinx.HLE/Loaders/Npdm/ApplicationType.cs | 9 + Ryujinx.HLE/Loaders/Npdm/FSAccessControl.cs | 28 - Ryujinx.HLE/Loaders/Npdm/FSAccessHeader.cs | 37 - Ryujinx.HLE/Loaders/Npdm/FsAccessControl.cs | 28 + Ryujinx.HLE/Loaders/Npdm/FsAccessHeader.cs | 37 + Ryujinx.HLE/Loaders/Npdm/FsPermissionBool.cs | 33 + Ryujinx.HLE/Loaders/Npdm/FsPermissionRw.cs | 45 + Ryujinx.HLE/Loaders/Npdm/KernelAccessControl.cs | 171 +- Ryujinx.HLE/Loaders/Npdm/KernelAccessControlIrq.cs | 14 + .../Loaders/Npdm/KernelAccessControlMmio.cs | 22 + Ryujinx.HLE/Loaders/Npdm/KernelAccessItem.cs | 33 + Ryujinx.HLE/Loaders/Npdm/Npdm.cs | 85 +- Ryujinx.HLE/Loaders/Npdm/NpdmException.cs | 9 - Ryujinx.HLE/Loaders/Npdm/NpdmInfo.cs | 215 --- Ryujinx.HLE/Loaders/Npdm/ServiceAccessControl.cs | 26 +- Ryujinx.HLE/Loaders/Npdm/SvcName.cs | 134 ++ Ryujinx.HLE/OsHle/Diagnostics/Demangler.cs | 416 ----- Ryujinx.HLE/OsHle/ErrorCode.cs | 10 - Ryujinx.HLE/OsHle/ErrorModule.cs | 101 -- .../Exceptions/GuestBrokeExecutionException.cs | 11 - .../Exceptions/UndefinedInstructionException.cs | 13 - Ryujinx.HLE/OsHle/Font/SharedFontManager.cs | 122 -- Ryujinx.HLE/OsHle/Font/SharedFontType.cs | 13 - Ryujinx.HLE/OsHle/GlobalStateTable.cs | 69 - Ryujinx.HLE/OsHle/Handles/AddressSpaceType.cs | 10 - Ryujinx.HLE/OsHle/Handles/KEvent.cs | 4 - Ryujinx.HLE/OsHle/Handles/KMemoryBlock.cs | 43 - Ryujinx.HLE/OsHle/Handles/KMemoryInfo.cs | 33 - Ryujinx.HLE/OsHle/Handles/KMemoryManager.cs | 1082 ------------- Ryujinx.HLE/OsHle/Handles/KProcessHandleTable.cs | 34 - Ryujinx.HLE/OsHle/Handles/KProcessScheduler.cs | 360 ---- Ryujinx.HLE/OsHle/Handles/KSession.cs | 31 - Ryujinx.HLE/OsHle/Handles/KSharedMemory.cs | 14 - .../OsHle/Handles/KSynchronizationObject.cs | 28 - Ryujinx.HLE/OsHle/Handles/KThread.cs | 96 -- Ryujinx.HLE/OsHle/Handles/KTlsPageManager.cs | 60 - Ryujinx.HLE/OsHle/Handles/KTransferMemory.cs | 14 - Ryujinx.HLE/OsHle/Handles/MemoryAttribute.cs | 22 - Ryujinx.HLE/OsHle/Handles/MemoryPermission.cs | 18 - Ryujinx.HLE/OsHle/Handles/MemoryState.cs | 49 - Ryujinx.HLE/OsHle/Handles/SchedulerThread.cs | 48 - Ryujinx.HLE/OsHle/Handles/ThreadQueue.cs | 158 -- Ryujinx.HLE/OsHle/Homebrew.cs | 77 - Ryujinx.HLE/OsHle/Horizon.cs | 248 --- Ryujinx.HLE/OsHle/IdDictionary.cs | 73 - Ryujinx.HLE/OsHle/Ipc/IpcBuffDesc.cs | 27 - Ryujinx.HLE/OsHle/Ipc/IpcHandleDesc.cs | 92 -- Ryujinx.HLE/OsHle/Ipc/IpcHandler.cs | 140 -- Ryujinx.HLE/OsHle/Ipc/IpcMagic.cs | 8 - Ryujinx.HLE/OsHle/Ipc/IpcMessage.cs | 215 --- Ryujinx.HLE/OsHle/Ipc/IpcMessageType.cs | 12 - Ryujinx.HLE/OsHle/Ipc/IpcPtrBuffDesc.cs | 26 - Ryujinx.HLE/OsHle/Ipc/IpcRecvListBuffDesc.cs | 19 - Ryujinx.HLE/OsHle/Ipc/ServiceProcessRequest.cs | 4 - Ryujinx.HLE/OsHle/Kernel/AddressArbiter.cs | 112 -- Ryujinx.HLE/OsHle/Kernel/KernelErr.cs | 22 - Ryujinx.HLE/OsHle/Kernel/NsTimeConverter.cs | 19 - Ryujinx.HLE/OsHle/Kernel/SvcHandler.cs | 124 -- Ryujinx.HLE/OsHle/Kernel/SvcMemory.cs | 578 ------- Ryujinx.HLE/OsHle/Kernel/SvcSystem.cs | 374 ----- Ryujinx.HLE/OsHle/Kernel/SvcThread.cs | 386 ----- Ryujinx.HLE/OsHle/Kernel/SvcThreadSync.cs | 524 ------ Ryujinx.HLE/OsHle/MemoryType.cs | 25 - Ryujinx.HLE/OsHle/Process.cs | 457 ------ Ryujinx.HLE/OsHle/ServiceCtx.cs | 39 - Ryujinx.HLE/OsHle/Services/Acc/AccErr.cs | 7 - .../Services/Acc/IAccountServiceForApplication.cs | 126 -- .../OsHle/Services/Acc/IManagerForApplication.cs | 38 - Ryujinx.HLE/OsHle/Services/Acc/IProfile.cs | 58 - Ryujinx.HLE/OsHle/Services/Am/AmErr.cs | 7 - Ryujinx.HLE/OsHle/Services/Am/FocusState.cs | 8 - .../Services/Am/IAllSystemAppletProxiesService.cs | 27 - .../OsHle/Services/Am/IApplicationCreator.cs | 20 - .../OsHle/Services/Am/IApplicationFunctions.cs | 117 -- Ryujinx.HLE/OsHle/Services/Am/IApplicationProxy.cs | 83 - .../OsHle/Services/Am/IApplicationProxyService.cs | 27 - Ryujinx.HLE/OsHle/Services/Am/IAudioController.cs | 72 - .../OsHle/Services/Am/ICommonStateGetter.cs | 115 -- Ryujinx.HLE/OsHle/Services/Am/IDebugFunctions.cs | 20 - .../OsHle/Services/Am/IDisplayController.cs | 20 - .../OsHle/Services/Am/IGlobalStateController.cs | 20 - .../OsHle/Services/Am/IHomeMenuFunctions.cs | 46 - .../OsHle/Services/Am/ILibraryAppletAccessor.cs | 71 - .../OsHle/Services/Am/ILibraryAppletCreator.cs | 37 - Ryujinx.HLE/OsHle/Services/Am/ISelfController.cs | 145 -- Ryujinx.HLE/OsHle/Services/Am/IStorage.cs | 31 - Ryujinx.HLE/OsHle/Services/Am/IStorageAccessor.cs | 83 - .../OsHle/Services/Am/ISystemAppletProxy.cs | 99 -- Ryujinx.HLE/OsHle/Services/Am/IWindowController.cs | 38 - Ryujinx.HLE/OsHle/Services/Am/MessageInfo.cs | 9 - Ryujinx.HLE/OsHle/Services/Am/OperationMode.cs | 8 - Ryujinx.HLE/OsHle/Services/Am/StorageHelper.cs | 27 - Ryujinx.HLE/OsHle/Services/Apm/IManager.cs | 27 - Ryujinx.HLE/OsHle/Services/Apm/ISession.cs | 41 - .../OsHle/Services/Apm/PerformanceConfiguration.cs | 18 - Ryujinx.HLE/OsHle/Services/Apm/PerformanceMode.cs | 8 - Ryujinx.HLE/OsHle/Services/Aud/AudErr.cs | 9 - .../OsHle/Services/Aud/AudioOut/AudioOutData.cs | 14 - .../OsHle/Services/Aud/AudioOut/IAudioOut.cs | 163 -- .../Services/Aud/AudioRenderer/AudioConsts.cs | 8 - .../OsHle/Services/Aud/AudioRenderer/BehaviorIn.cs | 11 - .../Services/Aud/AudioRenderer/BiquadFilter.cs | 16 - .../Services/Aud/AudioRenderer/IAudioRenderer.cs | 316 ---- .../Aud/AudioRenderer/MemoryPoolContext.cs | 12 - .../Services/Aud/AudioRenderer/MemoryPoolIn.cs | 14 - .../Services/Aud/AudioRenderer/MemoryPoolOut.cs | 12 - .../Services/Aud/AudioRenderer/MemoryPoolState.cs | 13 - .../OsHle/Services/Aud/AudioRenderer/PlayState.cs | 9 - .../OsHle/Services/Aud/AudioRenderer/Resampler.cs | 191 --- .../Services/Aud/AudioRenderer/UpdateDataHeader.cs | 22 - .../Aud/AudioRenderer/VoiceChannelResourceIn.cs | 10 - .../Services/Aud/AudioRenderer/VoiceContext.cs | 188 --- .../OsHle/Services/Aud/AudioRenderer/VoiceIn.cs | 49 - .../OsHle/Services/Aud/AudioRenderer/VoiceOut.cs | 12 - .../OsHle/Services/Aud/AudioRenderer/WaveBuffer.cs | 20 - .../OsHle/Services/Aud/AudioRendererParameter.cs | 22 - Ryujinx.HLE/OsHle/Services/Aud/IAudioDevice.cs | 223 --- Ryujinx.HLE/OsHle/Services/Aud/IAudioOutManager.cs | 170 -- .../OsHle/Services/Aud/IAudioRendererManager.cs | 169 -- Ryujinx.HLE/OsHle/Services/Aud/SampleFormat.cs | 13 - Ryujinx.HLE/OsHle/Services/Bcat/IBcatService.cs | 21 - .../Services/Bcat/IDeliveryCacheStorageService.cs | 21 - Ryujinx.HLE/OsHle/Services/Bcat/IServiceCreator.cs | 39 - Ryujinx.HLE/OsHle/Services/Bsd/BsdError.cs | 8 - Ryujinx.HLE/OsHle/Services/Bsd/BsdSocket.cs | 18 - Ryujinx.HLE/OsHle/Services/Bsd/IClient.cs | 445 ----- .../OsHle/Services/Caps/IAlbumAccessorService.cs | 20 - .../OsHle/Services/Caps/IScreenshotService.cs | 20 - .../OsHle/Services/Friend/IFriendService.cs | 49 - .../OsHle/Services/Friend/IServiceCreator.cs | 27 - Ryujinx.HLE/OsHle/Services/FspSrv/FsErr.cs | 9 - Ryujinx.HLE/OsHle/Services/FspSrv/IDirectory.cs | 116 -- Ryujinx.HLE/OsHle/Services/FspSrv/IFile.cs | 110 -- Ryujinx.HLE/OsHle/Services/FspSrv/IFileSystem.cs | 412 ----- .../OsHle/Services/FspSrv/IFileSystemProxy.cs | 74 - Ryujinx.HLE/OsHle/Services/FspSrv/IStorage.cs | 51 - .../Services/Hid/IActiveVibrationDeviceList.cs | 27 - Ryujinx.HLE/OsHle/Services/Hid/IAppletResource.cs | 34 - Ryujinx.HLE/OsHle/Services/Hid/IHidServer.cs | 299 ---- Ryujinx.HLE/OsHle/Services/IIpcService.cs | 10 - Ryujinx.HLE/OsHle/Services/IpcService.cs | 183 --- Ryujinx.HLE/OsHle/Services/Lm/ILogService.cs | 27 - Ryujinx.HLE/OsHle/Services/Lm/ILogger.cs | 86 - Ryujinx.HLE/OsHle/Services/Lm/LmLogField.cs | 13 - Ryujinx.HLE/OsHle/Services/Lm/LmLogLevel.cs | 11 - Ryujinx.HLE/OsHle/Services/Mm/IRequest.cs | 46 - Ryujinx.HLE/OsHle/Services/Nfp/DeviceState.cs | 7 - Ryujinx.HLE/OsHle/Services/Nfp/IUser.cs | 114 -- Ryujinx.HLE/OsHle/Services/Nfp/IUserManager.cs | 27 - Ryujinx.HLE/OsHle/Services/Nfp/State.cs | 8 - Ryujinx.HLE/OsHle/Services/Nifm/IGeneralService.cs | 58 - Ryujinx.HLE/OsHle/Services/Nifm/IRequest.cs | 95 -- Ryujinx.HLE/OsHle/Services/Nifm/IStaticService.cs | 35 - .../OsHle/Services/Ns/IAddOnContentManager.cs | 42 - .../OsHle/Services/Ns/IServiceGetterInterface.cs | 20 - .../OsHle/Services/Ns/ISystemUpdateInterface.cs | 20 - .../Services/Ns/IVulnerabilityManagerInterface.cs | 20 - Ryujinx.HLE/OsHle/Services/Nv/INvDrvServices.cs | 231 --- Ryujinx.HLE/OsHle/Services/Nv/NvFd.cs | 12 - .../OsHle/Services/Nv/NvGpuAS/NvGpuASAllocSpace.cs | 11 - .../OsHle/Services/Nv/NvGpuAS/NvGpuASCtx.cs | 198 --- .../OsHle/Services/Nv/NvGpuAS/NvGpuASIoctl.cs | 329 ---- .../Services/Nv/NvGpuAS/NvGpuASMapBufferEx.cs | 13 - .../OsHle/Services/Nv/NvGpuAS/NvGpuASRemap.cs | 12 - .../Services/Nv/NvGpuAS/NvGpuASUnmapBuffer.cs | 7 - .../Nv/NvGpuGpu/NvGpuGpuGetActiveSlotMask.cs | 8 - .../Nv/NvGpuGpu/NvGpuGpuGetCharacteristics.cs | 43 - .../Services/Nv/NvGpuGpu/NvGpuGpuGetTpcMasks.cs | 11 - .../OsHle/Services/Nv/NvGpuGpu/NvGpuGpuIoctl.cs | 187 --- .../Nv/NvGpuGpu/NvGpuGpuZcullGetCtxSize.cs | 7 - .../Services/Nv/NvGpuGpu/NvGpuGpuZcullGetInfo.cs | 16 - Ryujinx.HLE/OsHle/Services/Nv/NvHelper.cs | 10 - .../OsHle/Services/Nv/NvHostChannel/NvChannel.cs | 7 - .../Services/Nv/NvHostChannel/NvChannelName.cs | 7 - .../Nv/NvHostChannel/NvHostChannelIoctl.cs | 210 --- .../Nv/NvHostChannel/NvHostChannelSubmitGpfifo.cs | 11 - .../Services/Nv/NvHostCtrl/NvHostCtrlIoctl.cs | 398 ----- .../Services/Nv/NvHostCtrl/NvHostCtrlSyncPtRead.cs | 8 - .../Services/Nv/NvHostCtrl/NvHostCtrlSyncPtWait.cs | 9 - .../Nv/NvHostCtrl/NvHostCtrlSyncPtWaitEx.cs | 10 - .../Services/Nv/NvHostCtrl/NvHostCtrlUserCtx.cs | 19 - .../OsHle/Services/Nv/NvHostCtrl/NvHostEvent.cs | 10 - .../Services/Nv/NvHostCtrl/NvHostEventState.cs | 10 - .../OsHle/Services/Nv/NvHostCtrl/NvHostSyncPt.cs | 107 -- Ryujinx.HLE/OsHle/Services/Nv/NvMap/NvMapAlloc.cs | 12 - Ryujinx.HLE/OsHle/Services/Nv/NvMap/NvMapCreate.cs | 8 - Ryujinx.HLE/OsHle/Services/Nv/NvMap/NvMapFree.cs | 11 - Ryujinx.HLE/OsHle/Services/Nv/NvMap/NvMapFromId.cs | 8 - Ryujinx.HLE/OsHle/Services/Nv/NvMap/NvMapGetId.cs | 8 - Ryujinx.HLE/OsHle/Services/Nv/NvMap/NvMapHandle.cs | 37 - .../OsHle/Services/Nv/NvMap/NvMapHandleParam.cs | 12 - Ryujinx.HLE/OsHle/Services/Nv/NvMap/NvMapIoctl.cs | 302 ---- Ryujinx.HLE/OsHle/Services/Nv/NvMap/NvMapParam.cs | 9 - Ryujinx.HLE/OsHle/Services/Nv/NvResult.cs | 14 - .../OsHle/Services/Pctl/IParentalControlService.cs | 41 - .../Pctl/IParentalControlServiceFactory.cs | 35 - .../OsHle/Services/Pl/ISharedFontManager.cs | 125 -- Ryujinx.HLE/OsHle/Services/Prepo/IPrepoService.cs | 28 - Ryujinx.HLE/OsHle/Services/ServiceFactory.cs | 183 --- Ryujinx.HLE/OsHle/Services/Set/ISettingsServer.cs | 79 - .../OsHle/Services/Set/ISystemSettingsServer.cs | 151 -- Ryujinx.HLE/OsHle/Services/Set/NxSettings.cs | 1711 -------------------- Ryujinx.HLE/OsHle/Services/Sfdnsres/IResolver.cs | 20 - Ryujinx.HLE/OsHle/Services/Sm/IUserInterface.cs | 69 - Ryujinx.HLE/OsHle/Services/Spl/IRandomInterface.cs | 50 - Ryujinx.HLE/OsHle/Services/Ssl/ISslService.cs | 30 - Ryujinx.HLE/OsHle/Services/Time/IStaticService.cs | 74 - Ryujinx.HLE/OsHle/Services/Time/ISteadyClock.cs | 53 - Ryujinx.HLE/OsHle/Services/Time/ISystemClock.cs | 107 -- .../OsHle/Services/Time/ITimeZoneService.cs | 267 --- Ryujinx.HLE/OsHle/Services/Time/SystemClockType.cs | 10 - Ryujinx.HLE/OsHle/Services/Vi/Display.cs | 12 - Ryujinx.HLE/OsHle/Services/Vi/GbpBuffer.cs | 60 - .../Services/Vi/IApplicationDisplayService.cs | 233 --- .../OsHle/Services/Vi/IApplicationRootService.cs | 29 - Ryujinx.HLE/OsHle/Services/Vi/IHOSBinderDriver.cs | 100 -- .../OsHle/Services/Vi/IManagerDisplayService.cs | 49 - .../OsHle/Services/Vi/IManagerRootService.cs | 29 - .../OsHle/Services/Vi/ISystemDisplayService.cs | 44 - .../OsHle/Services/Vi/ISystemRootService.cs | 29 - Ryujinx.HLE/OsHle/Services/Vi/NvFlinger.cs | 416 ----- Ryujinx.HLE/OsHle/Services/Vi/Parcel.cs | 58 - Ryujinx.HLE/OsHle/SystemState/AppletStateMgr.cs | 62 - Ryujinx.HLE/OsHle/SystemState/ColorSet.cs | 8 - Ryujinx.HLE/OsHle/SystemState/OpenCloseState.cs | 8 - Ryujinx.HLE/OsHle/SystemState/SystemLanguage.cs | 23 - Ryujinx.HLE/OsHle/SystemState/SystemStateMgr.cs | 145 -- Ryujinx.HLE/OsHle/SystemState/UserId.cs | 76 - Ryujinx.HLE/OsHle/SystemState/UserProfile.cs | 36 - Ryujinx.HLE/OsHle/Utilities/EndianSwap.cs | 17 - Ryujinx.HLE/OsHle/Utilities/IntUtils.cs | 25 - Ryujinx.HLE/OsHle/Utilities/StringUtils.cs | 51 - Ryujinx.HLE/OsHle/Utilities/StructReader.cs | 45 - Ryujinx.HLE/OsHle/Utilities/StructWriter.cs | 25 - Ryujinx.HLE/Switch.cs | 28 +- Ryujinx.HLE/Utilities/EndianSwap.cs | 17 + Ryujinx.HLE/Utilities/IntUtils.cs | 25 + Ryujinx.HLE/Utilities/StringUtils.cs | 51 + Ryujinx.HLE/Utilities/StructReader.cs | 45 + Ryujinx.HLE/Utilities/StructWriter.cs | 25 + Ryujinx/Config.cs | 2 +- Ryujinx/Ui/GLScreen.cs | 31 +- Ryujinx/Ui/Program.cs | 24 +- 475 files changed, 19777 insertions(+), 19749 deletions(-) create mode 100644 Ryujinx.HLE/Exceptions/GuestBrokeExecutionException.cs create mode 100644 Ryujinx.HLE/Exceptions/InvalidNpdmException.cs create mode 100644 Ryujinx.HLE/Exceptions/UndefinedInstructionException.cs create mode 100644 Ryujinx.HLE/HOS/Diagnostics/Demangler.cs create mode 100644 Ryujinx.HLE/HOS/ErrorCode.cs create mode 100644 Ryujinx.HLE/HOS/ErrorModule.cs create mode 100644 Ryujinx.HLE/HOS/Font/SharedFontManager.cs create mode 100644 Ryujinx.HLE/HOS/Font/SharedFontType.cs create mode 100644 Ryujinx.HLE/HOS/GlobalStateTable.cs create mode 100644 Ryujinx.HLE/HOS/Homebrew.cs create mode 100644 Ryujinx.HLE/HOS/Horizon.cs create mode 100644 Ryujinx.HLE/HOS/IdDictionary.cs create mode 100644 Ryujinx.HLE/HOS/Ipc/IpcBuffDesc.cs create mode 100644 Ryujinx.HLE/HOS/Ipc/IpcHandleDesc.cs create mode 100644 Ryujinx.HLE/HOS/Ipc/IpcHandler.cs create mode 100644 Ryujinx.HLE/HOS/Ipc/IpcMagic.cs create mode 100644 Ryujinx.HLE/HOS/Ipc/IpcMessage.cs create mode 100644 Ryujinx.HLE/HOS/Ipc/IpcMessageType.cs create mode 100644 Ryujinx.HLE/HOS/Ipc/IpcPtrBuffDesc.cs create mode 100644 Ryujinx.HLE/HOS/Ipc/IpcRecvListBuffDesc.cs create mode 100644 Ryujinx.HLE/HOS/Ipc/ServiceProcessRequest.cs create mode 100644 Ryujinx.HLE/HOS/Kernel/AddressArbiter.cs create mode 100644 Ryujinx.HLE/HOS/Kernel/AddressSpaceType.cs create mode 100644 Ryujinx.HLE/HOS/Kernel/KEvent.cs create mode 100644 Ryujinx.HLE/HOS/Kernel/KMemoryBlock.cs create mode 100644 Ryujinx.HLE/HOS/Kernel/KMemoryInfo.cs create mode 100644 Ryujinx.HLE/HOS/Kernel/KMemoryManager.cs create mode 100644 Ryujinx.HLE/HOS/Kernel/KProcessHandleTable.cs create mode 100644 Ryujinx.HLE/HOS/Kernel/KProcessScheduler.cs create mode 100644 Ryujinx.HLE/HOS/Kernel/KSession.cs create mode 100644 Ryujinx.HLE/HOS/Kernel/KSharedMemory.cs create mode 100644 Ryujinx.HLE/HOS/Kernel/KSynchronizationObject.cs create mode 100644 Ryujinx.HLE/HOS/Kernel/KThread.cs create mode 100644 Ryujinx.HLE/HOS/Kernel/KTlsPageManager.cs create mode 100644 Ryujinx.HLE/HOS/Kernel/KTransferMemory.cs create mode 100644 Ryujinx.HLE/HOS/Kernel/KernelErr.cs create mode 100644 Ryujinx.HLE/HOS/Kernel/MemoryAttribute.cs create mode 100644 Ryujinx.HLE/HOS/Kernel/MemoryPermission.cs create mode 100644 Ryujinx.HLE/HOS/Kernel/MemoryState.cs create mode 100644 Ryujinx.HLE/HOS/Kernel/NsTimeConverter.cs create mode 100644 Ryujinx.HLE/HOS/Kernel/SchedulerThread.cs create mode 100644 Ryujinx.HLE/HOS/Kernel/SvcHandler.cs create mode 100644 Ryujinx.HLE/HOS/Kernel/SvcMemory.cs create mode 100644 Ryujinx.HLE/HOS/Kernel/SvcSystem.cs create mode 100644 Ryujinx.HLE/HOS/Kernel/SvcThread.cs create mode 100644 Ryujinx.HLE/HOS/Kernel/SvcThreadSync.cs create mode 100644 Ryujinx.HLE/HOS/Kernel/ThreadQueue.cs create mode 100644 Ryujinx.HLE/HOS/Process.cs create mode 100644 Ryujinx.HLE/HOS/ServiceCtx.cs create mode 100644 Ryujinx.HLE/HOS/Services/Acc/AccErr.cs create mode 100644 Ryujinx.HLE/HOS/Services/Acc/IAccountServiceForApplication.cs create mode 100644 Ryujinx.HLE/HOS/Services/Acc/IManagerForApplication.cs create mode 100644 Ryujinx.HLE/HOS/Services/Acc/IProfile.cs create mode 100644 Ryujinx.HLE/HOS/Services/Am/AmErr.cs create mode 100644 Ryujinx.HLE/HOS/Services/Am/FocusState.cs create mode 100644 Ryujinx.HLE/HOS/Services/Am/IAllSystemAppletProxiesService.cs create mode 100644 Ryujinx.HLE/HOS/Services/Am/IApplicationCreator.cs create mode 100644 Ryujinx.HLE/HOS/Services/Am/IApplicationFunctions.cs create mode 100644 Ryujinx.HLE/HOS/Services/Am/IApplicationProxy.cs create mode 100644 Ryujinx.HLE/HOS/Services/Am/IApplicationProxyService.cs create mode 100644 Ryujinx.HLE/HOS/Services/Am/IAudioController.cs create mode 100644 Ryujinx.HLE/HOS/Services/Am/ICommonStateGetter.cs create mode 100644 Ryujinx.HLE/HOS/Services/Am/IDebugFunctions.cs create mode 100644 Ryujinx.HLE/HOS/Services/Am/IDisplayController.cs create mode 100644 Ryujinx.HLE/HOS/Services/Am/IGlobalStateController.cs create mode 100644 Ryujinx.HLE/HOS/Services/Am/IHomeMenuFunctions.cs create mode 100644 Ryujinx.HLE/HOS/Services/Am/ILibraryAppletAccessor.cs create mode 100644 Ryujinx.HLE/HOS/Services/Am/ILibraryAppletCreator.cs create mode 100644 Ryujinx.HLE/HOS/Services/Am/ISelfController.cs create mode 100644 Ryujinx.HLE/HOS/Services/Am/IStorage.cs create mode 100644 Ryujinx.HLE/HOS/Services/Am/IStorageAccessor.cs create mode 100644 Ryujinx.HLE/HOS/Services/Am/ISystemAppletProxy.cs create mode 100644 Ryujinx.HLE/HOS/Services/Am/IWindowController.cs create mode 100644 Ryujinx.HLE/HOS/Services/Am/MessageInfo.cs create mode 100644 Ryujinx.HLE/HOS/Services/Am/OperationMode.cs create mode 100644 Ryujinx.HLE/HOS/Services/Am/StorageHelper.cs create mode 100644 Ryujinx.HLE/HOS/Services/Apm/IManager.cs create mode 100644 Ryujinx.HLE/HOS/Services/Apm/ISession.cs create mode 100644 Ryujinx.HLE/HOS/Services/Apm/PerformanceConfiguration.cs create mode 100644 Ryujinx.HLE/HOS/Services/Apm/PerformanceMode.cs create mode 100644 Ryujinx.HLE/HOS/Services/Aud/AudErr.cs create mode 100644 Ryujinx.HLE/HOS/Services/Aud/AudioOut/AudioOutData.cs create mode 100644 Ryujinx.HLE/HOS/Services/Aud/AudioOut/IAudioOut.cs create mode 100644 Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/AudioConsts.cs create mode 100644 Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/BehaviorIn.cs create mode 100644 Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/BiquadFilter.cs create mode 100644 Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/IAudioRenderer.cs create mode 100644 Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/MemoryPoolContext.cs create mode 100644 Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/MemoryPoolIn.cs create mode 100644 Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/MemoryPoolOut.cs create mode 100644 Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/MemoryPoolState.cs create mode 100644 Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/PlayState.cs create mode 100644 Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/Resampler.cs create mode 100644 Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/UpdateDataHeader.cs create mode 100644 Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/VoiceChannelResourceIn.cs create mode 100644 Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/VoiceContext.cs create mode 100644 Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/VoiceIn.cs create mode 100644 Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/VoiceOut.cs create mode 100644 Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/WaveBuffer.cs create mode 100644 Ryujinx.HLE/HOS/Services/Aud/AudioRendererParameter.cs create mode 100644 Ryujinx.HLE/HOS/Services/Aud/IAudioDevice.cs create mode 100644 Ryujinx.HLE/HOS/Services/Aud/IAudioOutManager.cs create mode 100644 Ryujinx.HLE/HOS/Services/Aud/IAudioRendererManager.cs create mode 100644 Ryujinx.HLE/HOS/Services/Aud/SampleFormat.cs create mode 100644 Ryujinx.HLE/HOS/Services/Bcat/IBcatService.cs create mode 100644 Ryujinx.HLE/HOS/Services/Bcat/IDeliveryCacheStorageService.cs create mode 100644 Ryujinx.HLE/HOS/Services/Bcat/IServiceCreator.cs create mode 100644 Ryujinx.HLE/HOS/Services/Bsd/BsdError.cs create mode 100644 Ryujinx.HLE/HOS/Services/Bsd/BsdSocket.cs create mode 100644 Ryujinx.HLE/HOS/Services/Bsd/IClient.cs create mode 100644 Ryujinx.HLE/HOS/Services/Caps/IAlbumAccessorService.cs create mode 100644 Ryujinx.HLE/HOS/Services/Caps/IScreenshotService.cs create mode 100644 Ryujinx.HLE/HOS/Services/Friend/IFriendService.cs create mode 100644 Ryujinx.HLE/HOS/Services/Friend/IServiceCreator.cs create mode 100644 Ryujinx.HLE/HOS/Services/FspSrv/FsErr.cs create mode 100644 Ryujinx.HLE/HOS/Services/FspSrv/IDirectory.cs create mode 100644 Ryujinx.HLE/HOS/Services/FspSrv/IFile.cs create mode 100644 Ryujinx.HLE/HOS/Services/FspSrv/IFileSystem.cs create mode 100644 Ryujinx.HLE/HOS/Services/FspSrv/IFileSystemProxy.cs create mode 100644 Ryujinx.HLE/HOS/Services/FspSrv/IStorage.cs create mode 100644 Ryujinx.HLE/HOS/Services/Hid/IActiveVibrationDeviceList.cs create mode 100644 Ryujinx.HLE/HOS/Services/Hid/IAppletResource.cs create mode 100644 Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs create mode 100644 Ryujinx.HLE/HOS/Services/IIpcService.cs create mode 100644 Ryujinx.HLE/HOS/Services/IpcService.cs create mode 100644 Ryujinx.HLE/HOS/Services/Lm/ILogService.cs create mode 100644 Ryujinx.HLE/HOS/Services/Lm/ILogger.cs create mode 100644 Ryujinx.HLE/HOS/Services/Lm/LmLogField.cs create mode 100644 Ryujinx.HLE/HOS/Services/Lm/LmLogLevel.cs create mode 100644 Ryujinx.HLE/HOS/Services/Mm/IRequest.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nfp/DeviceState.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nfp/IUser.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nfp/IUserManager.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nfp/State.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nifm/IGeneralService.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nifm/IRequest.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nifm/IStaticService.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nifm/NifmErr.cs create mode 100644 Ryujinx.HLE/HOS/Services/Ns/IAddOnContentManager.cs create mode 100644 Ryujinx.HLE/HOS/Services/Ns/IServiceGetterInterface.cs create mode 100644 Ryujinx.HLE/HOS/Services/Ns/ISystemUpdateInterface.cs create mode 100644 Ryujinx.HLE/HOS/Services/Ns/IVulnerabilityManagerInterface.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nv/INvDrvServices.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvFd.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvGpuAS/NvGpuASAllocSpace.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvGpuAS/NvGpuASCtx.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvGpuAS/NvGpuASIoctl.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvGpuAS/NvGpuASMapBufferEx.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvGpuAS/NvGpuASRemap.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvGpuAS/NvGpuASUnmapBuffer.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvGpuGpu/NvGpuGpuGetActiveSlotMask.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvGpuGpu/NvGpuGpuGetCharacteristics.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvGpuGpu/NvGpuGpuGetTpcMasks.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvGpuGpu/NvGpuGpuIoctl.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvGpuGpu/NvGpuGpuZcullGetCtxSize.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvGpuGpu/NvGpuGpuZcullGetInfo.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvHelper.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvHostChannel/NvChannel.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvHostChannel/NvChannelName.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvHostChannel/NvHostChannelIoctl.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvHostChannel/NvHostChannelSubmitGpfifo.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvHostCtrl/NvHostCtrlIoctl.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvHostCtrl/NvHostCtrlSyncPtRead.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvHostCtrl/NvHostCtrlSyncPtWait.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvHostCtrl/NvHostCtrlSyncPtWaitEx.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvHostCtrl/NvHostCtrlUserCtx.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvHostCtrl/NvHostEvent.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvHostCtrl/NvHostEventState.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvHostCtrl/NvHostSyncPt.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapAlloc.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapCreate.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapFree.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapFromId.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapGetId.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapHandle.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapHandleParam.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapIoctl.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapParam.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvResult.cs create mode 100644 Ryujinx.HLE/HOS/Services/Pctl/IParentalControlService.cs create mode 100644 Ryujinx.HLE/HOS/Services/Pctl/IParentalControlServiceFactory.cs create mode 100644 Ryujinx.HLE/HOS/Services/Pl/ISharedFontManager.cs create mode 100644 Ryujinx.HLE/HOS/Services/Prepo/IPrepoService.cs create mode 100644 Ryujinx.HLE/HOS/Services/ServiceFactory.cs create mode 100644 Ryujinx.HLE/HOS/Services/Set/ISettingsServer.cs create mode 100644 Ryujinx.HLE/HOS/Services/Set/ISystemSettingsServer.cs create mode 100644 Ryujinx.HLE/HOS/Services/Set/NxSettings.cs create mode 100644 Ryujinx.HLE/HOS/Services/Sfdnsres/IResolver.cs create mode 100644 Ryujinx.HLE/HOS/Services/Sm/IUserInterface.cs create mode 100644 Ryujinx.HLE/HOS/Services/Spl/IRandomInterface.cs create mode 100644 Ryujinx.HLE/HOS/Services/Ssl/ISslService.cs create mode 100644 Ryujinx.HLE/HOS/Services/Time/IStaticService.cs create mode 100644 Ryujinx.HLE/HOS/Services/Time/ISteadyClock.cs create mode 100644 Ryujinx.HLE/HOS/Services/Time/ISystemClock.cs create mode 100644 Ryujinx.HLE/HOS/Services/Time/ITimeZoneService.cs create mode 100644 Ryujinx.HLE/HOS/Services/Time/SystemClockType.cs create mode 100644 Ryujinx.HLE/HOS/Services/Vi/Display.cs create mode 100644 Ryujinx.HLE/HOS/Services/Vi/GbpBuffer.cs create mode 100644 Ryujinx.HLE/HOS/Services/Vi/IApplicationDisplayService.cs create mode 100644 Ryujinx.HLE/HOS/Services/Vi/IApplicationRootService.cs create mode 100644 Ryujinx.HLE/HOS/Services/Vi/IHOSBinderDriver.cs create mode 100644 Ryujinx.HLE/HOS/Services/Vi/IManagerDisplayService.cs create mode 100644 Ryujinx.HLE/HOS/Services/Vi/IManagerRootService.cs create mode 100644 Ryujinx.HLE/HOS/Services/Vi/ISystemDisplayService.cs create mode 100644 Ryujinx.HLE/HOS/Services/Vi/ISystemRootService.cs create mode 100644 Ryujinx.HLE/HOS/Services/Vi/NvFlinger.cs create mode 100644 Ryujinx.HLE/HOS/Services/Vi/Parcel.cs create mode 100644 Ryujinx.HLE/HOS/SystemState/AppletStateMgr.cs create mode 100644 Ryujinx.HLE/HOS/SystemState/ColorSet.cs create mode 100644 Ryujinx.HLE/HOS/SystemState/OpenCloseState.cs create mode 100644 Ryujinx.HLE/HOS/SystemState/SystemLanguage.cs create mode 100644 Ryujinx.HLE/HOS/SystemState/SystemStateMgr.cs create mode 100644 Ryujinx.HLE/HOS/SystemState/UserId.cs create mode 100644 Ryujinx.HLE/HOS/SystemState/UserProfile.cs create mode 100644 Ryujinx.HLE/Loaders/Npdm/ApplicationType.cs delete mode 100644 Ryujinx.HLE/Loaders/Npdm/FSAccessControl.cs delete mode 100644 Ryujinx.HLE/Loaders/Npdm/FSAccessHeader.cs create mode 100644 Ryujinx.HLE/Loaders/Npdm/FsAccessControl.cs create mode 100644 Ryujinx.HLE/Loaders/Npdm/FsAccessHeader.cs create mode 100644 Ryujinx.HLE/Loaders/Npdm/FsPermissionBool.cs create mode 100644 Ryujinx.HLE/Loaders/Npdm/FsPermissionRw.cs create mode 100644 Ryujinx.HLE/Loaders/Npdm/KernelAccessControlIrq.cs create mode 100644 Ryujinx.HLE/Loaders/Npdm/KernelAccessControlMmio.cs create mode 100644 Ryujinx.HLE/Loaders/Npdm/KernelAccessItem.cs delete mode 100644 Ryujinx.HLE/Loaders/Npdm/NpdmException.cs delete mode 100644 Ryujinx.HLE/Loaders/Npdm/NpdmInfo.cs create mode 100644 Ryujinx.HLE/Loaders/Npdm/SvcName.cs delete mode 100644 Ryujinx.HLE/OsHle/Diagnostics/Demangler.cs delete mode 100644 Ryujinx.HLE/OsHle/ErrorCode.cs delete mode 100644 Ryujinx.HLE/OsHle/ErrorModule.cs delete mode 100644 Ryujinx.HLE/OsHle/Exceptions/GuestBrokeExecutionException.cs delete mode 100644 Ryujinx.HLE/OsHle/Exceptions/UndefinedInstructionException.cs delete mode 100644 Ryujinx.HLE/OsHle/Font/SharedFontManager.cs delete mode 100644 Ryujinx.HLE/OsHle/Font/SharedFontType.cs delete mode 100644 Ryujinx.HLE/OsHle/GlobalStateTable.cs delete mode 100644 Ryujinx.HLE/OsHle/Handles/AddressSpaceType.cs delete mode 100644 Ryujinx.HLE/OsHle/Handles/KEvent.cs delete mode 100644 Ryujinx.HLE/OsHle/Handles/KMemoryBlock.cs delete mode 100644 Ryujinx.HLE/OsHle/Handles/KMemoryInfo.cs delete mode 100644 Ryujinx.HLE/OsHle/Handles/KMemoryManager.cs delete mode 100644 Ryujinx.HLE/OsHle/Handles/KProcessHandleTable.cs delete mode 100644 Ryujinx.HLE/OsHle/Handles/KProcessScheduler.cs delete mode 100644 Ryujinx.HLE/OsHle/Handles/KSession.cs delete mode 100644 Ryujinx.HLE/OsHle/Handles/KSharedMemory.cs delete mode 100644 Ryujinx.HLE/OsHle/Handles/KSynchronizationObject.cs delete mode 100644 Ryujinx.HLE/OsHle/Handles/KThread.cs delete mode 100644 Ryujinx.HLE/OsHle/Handles/KTlsPageManager.cs delete mode 100644 Ryujinx.HLE/OsHle/Handles/KTransferMemory.cs delete mode 100644 Ryujinx.HLE/OsHle/Handles/MemoryAttribute.cs delete mode 100644 Ryujinx.HLE/OsHle/Handles/MemoryPermission.cs delete mode 100644 Ryujinx.HLE/OsHle/Handles/MemoryState.cs delete mode 100644 Ryujinx.HLE/OsHle/Handles/SchedulerThread.cs delete mode 100644 Ryujinx.HLE/OsHle/Handles/ThreadQueue.cs delete mode 100644 Ryujinx.HLE/OsHle/Homebrew.cs delete mode 100644 Ryujinx.HLE/OsHle/Horizon.cs delete mode 100644 Ryujinx.HLE/OsHle/IdDictionary.cs delete mode 100644 Ryujinx.HLE/OsHle/Ipc/IpcBuffDesc.cs delete mode 100644 Ryujinx.HLE/OsHle/Ipc/IpcHandleDesc.cs delete mode 100644 Ryujinx.HLE/OsHle/Ipc/IpcHandler.cs delete mode 100644 Ryujinx.HLE/OsHle/Ipc/IpcMagic.cs delete mode 100644 Ryujinx.HLE/OsHle/Ipc/IpcMessage.cs delete mode 100644 Ryujinx.HLE/OsHle/Ipc/IpcMessageType.cs delete mode 100644 Ryujinx.HLE/OsHle/Ipc/IpcPtrBuffDesc.cs delete mode 100644 Ryujinx.HLE/OsHle/Ipc/IpcRecvListBuffDesc.cs delete mode 100644 Ryujinx.HLE/OsHle/Ipc/ServiceProcessRequest.cs delete mode 100644 Ryujinx.HLE/OsHle/Kernel/AddressArbiter.cs delete mode 100644 Ryujinx.HLE/OsHle/Kernel/KernelErr.cs delete mode 100644 Ryujinx.HLE/OsHle/Kernel/NsTimeConverter.cs delete mode 100644 Ryujinx.HLE/OsHle/Kernel/SvcHandler.cs delete mode 100644 Ryujinx.HLE/OsHle/Kernel/SvcMemory.cs delete mode 100644 Ryujinx.HLE/OsHle/Kernel/SvcSystem.cs delete mode 100644 Ryujinx.HLE/OsHle/Kernel/SvcThread.cs delete mode 100644 Ryujinx.HLE/OsHle/Kernel/SvcThreadSync.cs delete mode 100644 Ryujinx.HLE/OsHle/MemoryType.cs delete mode 100644 Ryujinx.HLE/OsHle/Process.cs delete mode 100644 Ryujinx.HLE/OsHle/ServiceCtx.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Acc/AccErr.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Acc/IAccountServiceForApplication.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Acc/IManagerForApplication.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Acc/IProfile.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Am/AmErr.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Am/FocusState.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Am/IAllSystemAppletProxiesService.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Am/IApplicationCreator.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Am/IApplicationFunctions.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Am/IApplicationProxy.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Am/IApplicationProxyService.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Am/IAudioController.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Am/ICommonStateGetter.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Am/IDebugFunctions.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Am/IDisplayController.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Am/IGlobalStateController.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Am/IHomeMenuFunctions.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Am/ILibraryAppletAccessor.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Am/ILibraryAppletCreator.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Am/ISelfController.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Am/IStorage.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Am/IStorageAccessor.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Am/ISystemAppletProxy.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Am/IWindowController.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Am/MessageInfo.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Am/OperationMode.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Am/StorageHelper.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Apm/IManager.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Apm/ISession.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Apm/PerformanceConfiguration.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Apm/PerformanceMode.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Aud/AudErr.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Aud/AudioOut/AudioOutData.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Aud/AudioOut/IAudioOut.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Aud/AudioRenderer/AudioConsts.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Aud/AudioRenderer/BehaviorIn.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Aud/AudioRenderer/BiquadFilter.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Aud/AudioRenderer/IAudioRenderer.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Aud/AudioRenderer/MemoryPoolContext.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Aud/AudioRenderer/MemoryPoolIn.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Aud/AudioRenderer/MemoryPoolOut.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Aud/AudioRenderer/MemoryPoolState.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Aud/AudioRenderer/PlayState.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Aud/AudioRenderer/Resampler.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Aud/AudioRenderer/UpdateDataHeader.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Aud/AudioRenderer/VoiceChannelResourceIn.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Aud/AudioRenderer/VoiceContext.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Aud/AudioRenderer/VoiceIn.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Aud/AudioRenderer/VoiceOut.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Aud/AudioRenderer/WaveBuffer.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Aud/AudioRendererParameter.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Aud/IAudioDevice.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Aud/IAudioOutManager.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Aud/IAudioRendererManager.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Aud/SampleFormat.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Bcat/IBcatService.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Bcat/IDeliveryCacheStorageService.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Bcat/IServiceCreator.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Bsd/BsdError.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Bsd/BsdSocket.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Bsd/IClient.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Caps/IAlbumAccessorService.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Caps/IScreenshotService.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Friend/IFriendService.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Friend/IServiceCreator.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/FspSrv/FsErr.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/FspSrv/IDirectory.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/FspSrv/IFile.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/FspSrv/IFileSystem.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/FspSrv/IFileSystemProxy.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/FspSrv/IStorage.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Hid/IActiveVibrationDeviceList.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Hid/IAppletResource.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Hid/IHidServer.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/IIpcService.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/IpcService.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Lm/ILogService.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Lm/ILogger.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Lm/LmLogField.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Lm/LmLogLevel.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Mm/IRequest.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Nfp/DeviceState.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Nfp/IUser.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Nfp/IUserManager.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Nfp/State.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Nifm/IGeneralService.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Nifm/IRequest.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Nifm/IStaticService.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Ns/IAddOnContentManager.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Ns/IServiceGetterInterface.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Ns/ISystemUpdateInterface.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Ns/IVulnerabilityManagerInterface.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Nv/INvDrvServices.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Nv/NvFd.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Nv/NvGpuAS/NvGpuASAllocSpace.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Nv/NvGpuAS/NvGpuASCtx.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Nv/NvGpuAS/NvGpuASIoctl.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Nv/NvGpuAS/NvGpuASMapBufferEx.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Nv/NvGpuAS/NvGpuASRemap.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Nv/NvGpuAS/NvGpuASUnmapBuffer.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Nv/NvGpuGpu/NvGpuGpuGetActiveSlotMask.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Nv/NvGpuGpu/NvGpuGpuGetCharacteristics.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Nv/NvGpuGpu/NvGpuGpuGetTpcMasks.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Nv/NvGpuGpu/NvGpuGpuIoctl.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Nv/NvGpuGpu/NvGpuGpuZcullGetCtxSize.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Nv/NvGpuGpu/NvGpuGpuZcullGetInfo.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Nv/NvHelper.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Nv/NvHostChannel/NvChannel.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Nv/NvHostChannel/NvChannelName.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Nv/NvHostChannel/NvHostChannelIoctl.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Nv/NvHostChannel/NvHostChannelSubmitGpfifo.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Nv/NvHostCtrl/NvHostCtrlIoctl.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Nv/NvHostCtrl/NvHostCtrlSyncPtRead.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Nv/NvHostCtrl/NvHostCtrlSyncPtWait.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Nv/NvHostCtrl/NvHostCtrlSyncPtWaitEx.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Nv/NvHostCtrl/NvHostCtrlUserCtx.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Nv/NvHostCtrl/NvHostEvent.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Nv/NvHostCtrl/NvHostEventState.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Nv/NvHostCtrl/NvHostSyncPt.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Nv/NvMap/NvMapAlloc.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Nv/NvMap/NvMapCreate.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Nv/NvMap/NvMapFree.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Nv/NvMap/NvMapFromId.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Nv/NvMap/NvMapGetId.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Nv/NvMap/NvMapHandle.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Nv/NvMap/NvMapHandleParam.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Nv/NvMap/NvMapIoctl.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Nv/NvMap/NvMapParam.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Nv/NvResult.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Pctl/IParentalControlService.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Pctl/IParentalControlServiceFactory.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Pl/ISharedFontManager.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Prepo/IPrepoService.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/ServiceFactory.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Set/ISettingsServer.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Set/ISystemSettingsServer.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Set/NxSettings.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Sfdnsres/IResolver.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Sm/IUserInterface.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Spl/IRandomInterface.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Ssl/ISslService.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Time/IStaticService.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Time/ISteadyClock.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Time/ISystemClock.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Time/ITimeZoneService.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Time/SystemClockType.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Vi/Display.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Vi/GbpBuffer.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Vi/IApplicationDisplayService.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Vi/IApplicationRootService.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Vi/IHOSBinderDriver.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Vi/IManagerDisplayService.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Vi/IManagerRootService.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Vi/ISystemDisplayService.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Vi/ISystemRootService.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Vi/NvFlinger.cs delete mode 100644 Ryujinx.HLE/OsHle/Services/Vi/Parcel.cs delete mode 100644 Ryujinx.HLE/OsHle/SystemState/AppletStateMgr.cs delete mode 100644 Ryujinx.HLE/OsHle/SystemState/ColorSet.cs delete mode 100644 Ryujinx.HLE/OsHle/SystemState/OpenCloseState.cs delete mode 100644 Ryujinx.HLE/OsHle/SystemState/SystemLanguage.cs delete mode 100644 Ryujinx.HLE/OsHle/SystemState/SystemStateMgr.cs delete mode 100644 Ryujinx.HLE/OsHle/SystemState/UserId.cs delete mode 100644 Ryujinx.HLE/OsHle/SystemState/UserProfile.cs delete mode 100644 Ryujinx.HLE/OsHle/Utilities/EndianSwap.cs delete mode 100644 Ryujinx.HLE/OsHle/Utilities/IntUtils.cs delete mode 100644 Ryujinx.HLE/OsHle/Utilities/StringUtils.cs delete mode 100644 Ryujinx.HLE/OsHle/Utilities/StructReader.cs delete mode 100644 Ryujinx.HLE/OsHle/Utilities/StructWriter.cs create mode 100644 Ryujinx.HLE/Utilities/EndianSwap.cs create mode 100644 Ryujinx.HLE/Utilities/IntUtils.cs create mode 100644 Ryujinx.HLE/Utilities/StringUtils.cs create mode 100644 Ryujinx.HLE/Utilities/StructReader.cs create mode 100644 Ryujinx.HLE/Utilities/StructWriter.cs diff --git a/ChocolArm64/AThread.cs b/ChocolArm64/AThread.cs index 4fc79d5e..7b8360f8 100644 --- a/ChocolArm64/AThread.cs +++ b/ChocolArm64/AThread.cs @@ -18,8 +18,6 @@ namespace ChocolArm64 public event EventHandler WorkFinished; - public int ThreadId => ThreadState.ThreadId; - private int IsExecuting; public AThread(ATranslator Translator, AMemory Memory, long EntryPoint) diff --git a/ChocolArm64/Memory/AMemory.cs b/ChocolArm64/Memory/AMemory.cs index 1b4ff6fb..566e6b54 100644 --- a/ChocolArm64/Memory/AMemory.cs +++ b/ChocolArm64/Memory/AMemory.cs @@ -41,7 +41,7 @@ namespace ChocolArm64.Memory } } - private Dictionary Monitors; + private Dictionary Monitors; private ConcurrentDictionary ObservedPages; @@ -53,7 +53,7 @@ namespace ChocolArm64.Memory public AMemory(IntPtr Ram) { - Monitors = new Dictionary(); + Monitors = new Dictionary(); ObservedPages = new ConcurrentDictionary(); @@ -75,7 +75,7 @@ namespace ChocolArm64.Memory { ClearExclusive(State); - Monitors.Remove(State.ThreadId); + Monitors.Remove(State); } } @@ -93,11 +93,11 @@ namespace ChocolArm64.Memory } } - if (!Monitors.TryGetValue(ThreadState.ThreadId, out ArmMonitor ThreadMon)) + if (!Monitors.TryGetValue(ThreadState, out ArmMonitor ThreadMon)) { ThreadMon = new ArmMonitor(); - Monitors.Add(ThreadState.ThreadId, ThreadMon); + Monitors.Add(ThreadState, ThreadMon); } ThreadMon.Position = Position; @@ -113,7 +113,7 @@ namespace ChocolArm64.Memory Monitor.Enter(Monitors); - if (!Monitors.TryGetValue(ThreadState.ThreadId, out ArmMonitor ThreadMon)) + if (!Monitors.TryGetValue(ThreadState, out ArmMonitor ThreadMon)) { return false; } @@ -130,7 +130,7 @@ namespace ChocolArm64.Memory public void ClearExclusiveForStore(AThreadState ThreadState) { - if (Monitors.TryGetValue(ThreadState.ThreadId, out ArmMonitor ThreadMon)) + if (Monitors.TryGetValue(ThreadState, out ArmMonitor ThreadMon)) { ThreadMon.ExState = false; } @@ -142,7 +142,7 @@ namespace ChocolArm64.Memory { lock (Monitors) { - if (Monitors.TryGetValue(ThreadState.ThreadId, out ArmMonitor ThreadMon)) + if (Monitors.TryGetValue(ThreadState, out ArmMonitor ThreadMon)) { ThreadMon.ExState = false; } diff --git a/ChocolArm64/State/AThreadState.cs b/ChocolArm64/State/AThreadState.cs index a84e3242..7b69d817 100644 --- a/ChocolArm64/State/AThreadState.cs +++ b/ChocolArm64/State/AThreadState.cs @@ -40,9 +40,6 @@ namespace ChocolArm64.State public bool Zero; public bool Negative; - public int ProcessId; - public int ThreadId; - public bool Running { get; set; } public long TpidrEl0 { get; set; } @@ -100,6 +97,11 @@ namespace ChocolArm64.State TickCounter.Start(); } + internal bool Synchronize() + { + return Running; + } + internal void OnBreak(long Position, int Imm) { Break?.Invoke(this, new AInstExceptionEventArgs(Position, Imm)); diff --git a/ChocolArm64/Translation/AILEmitterCtx.cs b/ChocolArm64/Translation/AILEmitterCtx.cs index 3fa46e96..40e33ba8 100644 --- a/ChocolArm64/Translation/AILEmitterCtx.cs +++ b/ChocolArm64/Translation/AILEmitterCtx.cs @@ -110,6 +110,8 @@ namespace ChocolArm64.Translation if (OpcIndex == 0) { MarkLabel(GetLabel(CurrBlock.Position)); + + EmitSynchronization(); } CurrOp.Emitter(this); @@ -117,6 +119,25 @@ namespace ChocolArm64.Translation ILBlock.Add(new AILBarrier()); } + private void EmitSynchronization() + { + EmitLdarg(ATranslatedSub.StateArgIdx); + + EmitPrivateCall(typeof(AThreadState), nameof(AThreadState.Synchronize)); + + EmitLdc_I4(0); + + AILLabel LblContinue = new AILLabel(); + + Emit(OpCodes.Bne_Un_S, LblContinue); + + EmitLdc_I8(0); + + Emit(OpCodes.Ret); + + MarkLabel(LblContinue); + } + public bool TryOptEmitSubroutineCall() { if (CurrBlock.Next == null) diff --git a/Ryujinx.Audio/IAalOutput.cs b/Ryujinx.Audio/IAalOutput.cs index e903c5c5..1dfac377 100644 --- a/Ryujinx.Audio/IAalOutput.cs +++ b/Ryujinx.Audio/IAalOutput.cs @@ -1,6 +1,8 @@ +using System; + namespace Ryujinx.Audio { - public interface IAalOutput + public interface IAalOutput : IDisposable { int OpenTrack(int SampleRate, int Channels, ReleaseCallback Callback); diff --git a/Ryujinx.Audio/OpenAL/OpenALAudioOut.cs b/Ryujinx.Audio/OpenAL/OpenALAudioOut.cs index 85e2d803..80a070c9 100644 --- a/Ryujinx.Audio/OpenAL/OpenALAudioOut.cs +++ b/Ryujinx.Audio/OpenAL/OpenALAudioOut.cs @@ -8,7 +8,7 @@ using System.Threading; namespace Ryujinx.Audio.OpenAL { - public class OpenALAudioOut : IAalOutput + public class OpenALAudioOut : IAalOutput, IDisposable { private const int MaxTracks = 256; @@ -222,10 +222,17 @@ namespace Ryujinx.Audio.OpenAL Td.CallReleaseCallbackIfNeeded(); } - //If it's not slept it will waste cycles + //If it's not slept it will waste cycles. Thread.Sleep(10); } while (KeepPolling); + + foreach (Track Td in Tracks.Values) + { + Td.Dispose(); + } + + Tracks.Clear(); } public int OpenTrack(int SampleRate, int Channels, ReleaseCallback Callback) @@ -342,5 +349,18 @@ namespace Ryujinx.Audio.OpenAL return PlaybackState.Stopped; } + + public void Dispose() + { + Dispose(true); + } + + protected virtual void Dispose(bool Disposing) + { + if (Disposing) + { + KeepPolling = false; + } + } } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/IGalShader.cs b/Ryujinx.Graphics/Gal/IGalShader.cs index 5174c039..e906e6cd 100644 --- a/Ryujinx.Graphics/Gal/IGalShader.cs +++ b/Ryujinx.Graphics/Gal/IGalShader.cs @@ -1,4 +1,3 @@ -using System; using System.Collections.Generic; namespace Ryujinx.Graphics.Gal diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLFrameBuffer.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLFrameBuffer.cs index 30a3de64..62f82495 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/OGLFrameBuffer.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/OGLFrameBuffer.cs @@ -1,4 +1,3 @@ -using OpenTK; using OpenTK.Graphics.OpenGL; using System; using System.Collections.Generic; diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLRasterizer.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLRasterizer.cs index 08021478..b6e97454 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/OGLRasterizer.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/OGLRasterizer.cs @@ -1,6 +1,5 @@ using OpenTK.Graphics.OpenGL; using System; -using System.Collections.Generic; namespace Ryujinx.Graphics.Gal.OpenGL { diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLShaderProgram.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLShaderProgram.cs index c4e6a881..c87b0d40 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/OGLShaderProgram.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/OGLShaderProgram.cs @@ -1,7 +1,6 @@ using OpenTK.Graphics.OpenGL; using System; using System.Collections.Generic; -using System.Linq; namespace Ryujinx.Graphics.Gal.OpenGL { diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeSpecial.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeSpecial.cs index 591631ff..f1be005f 100644 --- a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeSpecial.cs +++ b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeSpecial.cs @@ -1,6 +1,4 @@ -using System; - -using static Ryujinx.Graphics.Gal.Shader.ShaderDecodeHelper; +using static Ryujinx.Graphics.Gal.Shader.ShaderDecodeHelper; namespace Ryujinx.Graphics.Gal.Shader { diff --git a/Ryujinx.HLE/Exceptions/GuestBrokeExecutionException.cs b/Ryujinx.HLE/Exceptions/GuestBrokeExecutionException.cs new file mode 100644 index 00000000..fe41b02a --- /dev/null +++ b/Ryujinx.HLE/Exceptions/GuestBrokeExecutionException.cs @@ -0,0 +1,11 @@ +using System; + +namespace Ryujinx.HLE.Exceptions +{ + public class GuestBrokeExecutionException : Exception + { + private const string ExMsg = "The guest program broke execution!"; + + public GuestBrokeExecutionException() : base(ExMsg) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/Exceptions/InvalidNpdmException.cs b/Ryujinx.HLE/Exceptions/InvalidNpdmException.cs new file mode 100644 index 00000000..58d04434 --- /dev/null +++ b/Ryujinx.HLE/Exceptions/InvalidNpdmException.cs @@ -0,0 +1,9 @@ +using System; + +namespace Ryujinx.HLE.Exceptions +{ + public class InvalidNpdmException : Exception + { + public InvalidNpdmException(string ExMsg) : base(ExMsg) { } + } +} diff --git a/Ryujinx.HLE/Exceptions/UndefinedInstructionException.cs b/Ryujinx.HLE/Exceptions/UndefinedInstructionException.cs new file mode 100644 index 00000000..24bf9efd --- /dev/null +++ b/Ryujinx.HLE/Exceptions/UndefinedInstructionException.cs @@ -0,0 +1,13 @@ +using System; + +namespace Ryujinx.HLE.Exceptions +{ + public class UndefinedInstructionException : Exception + { + private const string ExMsg = "The instruction at 0x{0:x16} (opcode 0x{1:x8}) is undefined!"; + + public UndefinedInstructionException() : base() { } + + public UndefinedInstructionException(long Position, int OpCode) : base(string.Format(ExMsg, Position, OpCode)) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/Gpu/Texture/TextureHelper.cs b/Ryujinx.HLE/Gpu/Texture/TextureHelper.cs index 1d621c92..10a64f36 100644 --- a/Ryujinx.HLE/Gpu/Texture/TextureHelper.cs +++ b/Ryujinx.HLE/Gpu/Texture/TextureHelper.cs @@ -140,7 +140,7 @@ namespace Ryujinx.HLE.Gpu.Texture } } - throw new NotImplementedException(Texture.Format.ToString()); + throw new NotImplementedException("0x" + Texture.Format.ToString("x2")); } public static int CompressedTextureSize(int TextureWidth, int TextureHeight, int BlockWidth, int BlockHeight, int Bpb) diff --git a/Ryujinx.HLE/Gpu/Texture/TextureReader.cs b/Ryujinx.HLE/Gpu/Texture/TextureReader.cs index 0c6103af..0cf055db 100644 --- a/Ryujinx.HLE/Gpu/Texture/TextureReader.cs +++ b/Ryujinx.HLE/Gpu/Texture/TextureReader.cs @@ -47,7 +47,7 @@ namespace Ryujinx.HLE.Gpu.Texture case GalTextureFormat.Astc2D10x6: return Read16BptCompressedTexture(Memory, Texture, 10, 6); } - throw new NotImplementedException(Texture.Format.ToString()); + throw new NotImplementedException("0x" + Texture.Format.ToString("x2")); } private unsafe static byte[] Read1Bpp(IAMemory Memory, TextureInfo Texture) diff --git a/Ryujinx.HLE/Gpu/Texture/TextureWriter.cs b/Ryujinx.HLE/Gpu/Texture/TextureWriter.cs index 113dc6f6..6c3dda6b 100644 --- a/Ryujinx.HLE/Gpu/Texture/TextureWriter.cs +++ b/Ryujinx.HLE/Gpu/Texture/TextureWriter.cs @@ -1,6 +1,4 @@ using ChocolArm64.Memory; -using Ryujinx.Graphics.Gal; -using System; namespace Ryujinx.HLE.Gpu.Texture { diff --git a/Ryujinx.HLE/HOS/Diagnostics/Demangler.cs b/Ryujinx.HLE/HOS/Diagnostics/Demangler.cs new file mode 100644 index 00000000..aea979c2 --- /dev/null +++ b/Ryujinx.HLE/HOS/Diagnostics/Demangler.cs @@ -0,0 +1,416 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Ryujinx.HLE.HOS.Diagnostics +{ + static class Demangler + { + private static readonly Dictionary BuiltinTypes = new Dictionary + { + { "v", "void" }, + { "w", "wchar_t" }, + { "b", "bool" }, + { "c", "char" }, + { "a", "signed char" }, + { "h", "unsigned char" }, + { "s", "short" }, + { "t", "unsigned short" }, + { "i", "int" }, + { "j", "unsigned int" }, + { "l", "long" }, + { "m", "unsigned long" }, + { "x", "long long" }, + { "y", "unsigned long long" }, + { "n", "__int128" }, + { "o", "unsigned __int128" }, + { "f", "float" }, + { "d", "double" }, + { "e", "long double" }, + { "g", "__float128" }, + { "z", "..." }, + { "Dd", "__iec559_double" }, + { "De", "__iec559_float128" }, + { "Df", "__iec559_float" }, + { "Dh", "__iec559_float16" }, + { "Di", "char32_t" }, + { "Ds", "char16_t" }, + { "Da", "decltype(auto)" }, + { "Dn", "std::nullptr_t" }, + }; + + private static readonly Dictionary SubstitutionExtra = new Dictionary + { + {"Sa", "std::allocator"}, + {"Sb", "std::basic_string"}, + {"Ss", "std::basic_string, ::std::allocator>"}, + {"Si", "std::basic_istream>"}, + {"So", "std::basic_ostream>"}, + {"Sd", "std::basic_iostream>"} + }; + + private static int FromBase36(string encoded) + { + string base36 = "0123456789abcdefghijklmnopqrstuvwxyz"; + char[] reversedEncoded = encoded.ToLower().ToCharArray().Reverse().ToArray(); + int result = 0; + for (int i = 0; i < reversedEncoded.Length; i++) + { + char c = reversedEncoded[i]; + int value = base36.IndexOf(c); + if (value == -1) + return -1; + result += value * (int)Math.Pow(36, i); + } + return result; + } + + private static string GetCompressedValue(string compression, List compressionData, out int pos) + { + string res = null; + bool canHaveUnqualifiedName = false; + pos = -1; + if (compressionData.Count == 0 || !compression.StartsWith("S")) + return null; + + if (compression.Length >= 2 && SubstitutionExtra.TryGetValue(compression.Substring(0, 2), out string substitutionValue)) + { + pos = 1; + res = substitutionValue; + compression = compression.Substring(2); + } + else if (compression.StartsWith("St")) + { + pos = 1; + canHaveUnqualifiedName = true; + res = "std"; + compression = compression.Substring(2); + } + else if (compression.StartsWith("S_")) + { + pos = 1; + res = compressionData[0]; + canHaveUnqualifiedName = true; + compression = compression.Substring(2); + } + else + { + int id = -1; + int underscorePos = compression.IndexOf('_'); + if (underscorePos == -1) + return null; + string partialId = compression.Substring(1, underscorePos - 1); + + id = FromBase36(partialId); + if (id == -1 || compressionData.Count <= (id + 1)) + { + return null; + } + res = compressionData[id + 1]; + pos = partialId.Length + 1; + canHaveUnqualifiedName= true; + compression = compression.Substring(pos); + } + if (res != null) + { + if (canHaveUnqualifiedName) + { + List type = ReadName(compression, compressionData, out int endOfNameType); + if (endOfNameType != -1 && type != null) + { + pos += endOfNameType; + res = res + "::" + type[type.Count - 1]; + } + } + } + return res; + } + + private static List ReadName(string mangled, List compressionData, out int pos, bool isNested = true) + { + List res = new List(); + string charCountString = null; + int charCount = 0; + int i; + + pos = -1; + for (i = 0; i < mangled.Length; i++) + { + char chr = mangled[i]; + if (charCountString == null) + { + if (ReadCVQualifiers(chr) != null) + { + continue; + } + if (chr == 'S') + { + string data = GetCompressedValue(mangled.Substring(i), compressionData, out pos); + if (pos == -1) + { + return null; + } + if (res.Count == 0) + res.Add(data); + else + res.Add(res[res.Count - 1] + "::" + data); + i += pos; + if (i < mangled.Length && mangled[i] == 'E') + { + break; + } + continue; + } + else if (chr == 'E') + { + break; + } + } + if (Char.IsDigit(chr)) + { + charCountString += chr; + } + else + { + if (!int.TryParse(charCountString, out charCount)) + { + return null; + } + string demangledPart = mangled.Substring(i, charCount); + if (res.Count == 0) + res.Add(demangledPart); + else + res.Add(res[res.Count - 1] + "::" + demangledPart); + i = i + charCount - 1; + charCount = 0; + charCountString = null; + if (!isNested) + break; + } + } + if (res.Count == 0) + { + return null; + } + pos = i; + return res; + } + + private static string ReadBuiltinType(string mangledType, out int pos) + { + string res = null; + string possibleBuiltinType; + pos = -1; + possibleBuiltinType = mangledType[0].ToString(); + if (!BuiltinTypes.TryGetValue(possibleBuiltinType, out res)) + { + if (mangledType.Length >= 2) + { + // Try to match the first 2 chars if the first call failed + possibleBuiltinType = mangledType.Substring(0, 2); + BuiltinTypes.TryGetValue(possibleBuiltinType, out res); + } + } + if (res != null) + pos = possibleBuiltinType.Length; + return res; + } + + private static string ReadCVQualifiers(char qualifier) + { + if (qualifier == 'r') + return "restricted"; + else if (qualifier == 'V') + return "volatile"; + else if (qualifier == 'K') + return "const"; + return null; + } + + private static string ReadRefQualifiers(char qualifier) + { + if (qualifier == 'R') + return "&"; + else if (qualifier == 'O') + return "&&"; + return null; + } + + private static string ReadSpecialQualifiers(char qualifier) + { + if (qualifier == 'P') + return "*"; + else if (qualifier == 'C') + return "complex"; + else if (qualifier == 'G') + return "imaginary"; + return null; + } + + private static List ReadParameters(string mangledParams, List compressionData, out int pos) + { + List res = new List(); + List refQualifiers = new List(); + string parsedTypePart = null; + string currentRefQualifiers = null; + string currentBuiltinType = null; + string currentSpecialQualifiers = null; + string currentCompressedValue = null; + int i = 0; + pos = -1; + + for (i = 0; i < mangledParams.Length; i++) + { + if (currentBuiltinType != null) + { + string currentCVQualifier = String.Join(" ", refQualifiers); + // Try to mimic the compression indexing + if (currentRefQualifiers != null) + { + compressionData.Add(currentBuiltinType + currentRefQualifiers); + } + if (refQualifiers.Count != 0) + { + compressionData.Add(currentBuiltinType + " " + currentCVQualifier + currentRefQualifiers); + } + if (currentSpecialQualifiers != null) + { + compressionData.Add(currentBuiltinType + " " + currentCVQualifier + currentRefQualifiers + currentSpecialQualifiers); + } + if (currentRefQualifiers == null && currentCVQualifier == null && currentSpecialQualifiers == null) + { + compressionData.Add(currentBuiltinType); + } + currentBuiltinType = null; + currentCompressedValue = null; + currentCVQualifier = null; + currentRefQualifiers = null; + refQualifiers.Clear(); + currentSpecialQualifiers = null; + } + char chr = mangledParams[i]; + string part = mangledParams.Substring(i); + + // Try to read qualifiers + parsedTypePart = ReadCVQualifiers(chr); + if (parsedTypePart != null) + { + refQualifiers.Add(parsedTypePart); + + // need more data + continue; + } + + parsedTypePart = ReadRefQualifiers(chr); + if (parsedTypePart != null) + { + currentRefQualifiers = parsedTypePart; + + // need more data + continue; + } + + parsedTypePart = ReadSpecialQualifiers(chr); + if (parsedTypePart != null) + { + currentSpecialQualifiers = parsedTypePart; + + // need more data + continue; + } + + // TODO: extended-qualifier? + + if (part.StartsWith("S")) + { + parsedTypePart = GetCompressedValue(part, compressionData, out pos); + if (pos != -1 && parsedTypePart != null) + { + currentCompressedValue = parsedTypePart; + i += pos; + res.Add(currentCompressedValue + " " + String.Join(" ", refQualifiers) + currentRefQualifiers + currentSpecialQualifiers); + currentBuiltinType = null; + currentCompressedValue = null; + currentRefQualifiers = null; + refQualifiers.Clear(); + currentSpecialQualifiers = null; + continue; + } + pos = -1; + return null; + } + else if (part.StartsWith("N")) + { + part = part.Substring(1); + List name = ReadName(part, compressionData, out pos); + if (pos != -1 && name != null) + { + i += pos + 1; + res.Add(name[name.Count - 1] + " " + String.Join(" ", refQualifiers) + currentRefQualifiers + currentSpecialQualifiers); + currentBuiltinType = null; + currentCompressedValue = null; + currentRefQualifiers = null; + refQualifiers.Clear(); + currentSpecialQualifiers = null; + continue; + } + } + + // Try builting + parsedTypePart = ReadBuiltinType(part, out pos); + if (pos == -1) + { + return null; + } + currentBuiltinType = parsedTypePart; + res.Add(currentBuiltinType + " " + String.Join(" ", refQualifiers) + currentRefQualifiers + currentSpecialQualifiers); + i = i + pos -1; + } + pos = i; + return res; + } + + private static string ParseFunctionName(string mangled) + { + List compressionData = new List(); + int pos = 0; + string res; + bool isNested = mangled.StartsWith("N"); + + // If it's start with "N" it must be a nested function name + if (isNested) + mangled = mangled.Substring(1); + compressionData = ReadName(mangled, compressionData, out pos, isNested); + if (pos == -1) + return null; + res = compressionData[compressionData.Count - 1]; + compressionData.Remove(res); + mangled = mangled.Substring(pos + 1); + + // more data? maybe not a data name so... + if (mangled != String.Empty) + { + List parameters = ReadParameters(mangled, compressionData, out pos); + // parameters parsing error, we return the original data to avoid information loss. + if (pos == -1) + return null; + parameters = parameters.Select(outer => outer.Trim()).ToList(); + res += "(" + String.Join(", ", parameters) + ")"; + } + return res; + } + + public static string Parse(string originalMangled) + { + if (originalMangled.StartsWith("_Z")) + { + // We assume that we have a name (TOOD: support special names) + string res = ParseFunctionName(originalMangled.Substring(2)); + if (res == null) + return originalMangled; + return res; + } + return originalMangled; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/ErrorCode.cs b/Ryujinx.HLE/HOS/ErrorCode.cs new file mode 100644 index 00000000..767664f8 --- /dev/null +++ b/Ryujinx.HLE/HOS/ErrorCode.cs @@ -0,0 +1,10 @@ +namespace Ryujinx.HLE.HOS +{ + static class ErrorCode + { + public static uint MakeError(ErrorModule Module, int Code) + { + return (uint)Module | ((uint)Code << 9); + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/ErrorModule.cs b/Ryujinx.HLE/HOS/ErrorModule.cs new file mode 100644 index 00000000..5c6c9b05 --- /dev/null +++ b/Ryujinx.HLE/HOS/ErrorModule.cs @@ -0,0 +1,101 @@ +namespace Ryujinx.HLE.HOS +{ + enum ErrorModule + { + Kernel = 1, + Fs = 2, + Os = 3, // (Memory, Thread, Mutex, NVIDIA) + Htcs = 4, + Ncm = 5, + Dd = 6, + Debug_Monitor = 7, + Lr = 8, + Loader = 9, + IPC_Command_Interface = 10, + IPC = 11, + Pm = 15, + Ns = 16, + Socket = 17, + Htc = 18, + Ncm_Content = 20, + Sm = 21, + RO_Userland = 22, + SdMmc = 24, + Ovln = 25, + Spl = 26, + Ethc = 100, + I2C = 101, + Gpio = 102, + Uart = 103, + Settings = 105, + Wlan = 107, + Xcd = 108, + Nifm = 110, + Hwopus = 111, + Bluetooth = 113, + Vi = 114, + Nfp = 115, + Time = 116, + Fgm = 117, + Oe = 118, + Pcie = 120, + Friends = 121, + Bcat = 122, + SSL = 123, + Account = 124, + News = 125, + Mii = 126, + Nfc = 127, + Am = 128, + Play_Report = 129, + Ahid = 130, + Qlaunch = 132, + Pcv = 133, + Omm = 134, + Bpc = 135, + Psm = 136, + Nim = 137, + Psc = 138, + Tc = 139, + Usb = 140, + Nsd = 141, + Pctl = 142, + Btm = 143, + Ec = 144, + ETicket = 145, + Ngc = 146, + Error_Report = 147, + Apm = 148, + Profiler = 150, + Error_Upload = 151, + Audio = 153, + Npns = 154, + Npns_Http_Stream = 155, + Arp = 157, + Swkbd = 158, + Boot = 159, + Nfc_Mifare = 161, + Userland_Assert = 162, + Fatal = 163, + Nim_Shop = 164, + Spsm = 165, + Bgtc = 167, + Userland_Crash = 168, + SRepo = 180, + Dauth = 181, + Hid = 202, + Ldn = 203, + Irsensor = 205, + Capture = 206, + Manu = 208, + Atk = 209, + Web = 210, + Grc = 212, + Migration = 216, + Migration_Ldc_Server = 217, + General_Web_Applet = 800, + Wifi_Web_Auth_Applet = 809, + Whitelisted_Applet = 810, + ShopN = 811 + } +} diff --git a/Ryujinx.HLE/HOS/Font/SharedFontManager.cs b/Ryujinx.HLE/HOS/Font/SharedFontManager.cs new file mode 100644 index 00000000..0be5e896 --- /dev/null +++ b/Ryujinx.HLE/HOS/Font/SharedFontManager.cs @@ -0,0 +1,122 @@ +using Ryujinx.HLE.Memory; +using Ryujinx.HLE.Resource; +using Ryujinx.HLE.Utilities; +using System.Collections.Generic; +using System.IO; + +namespace Ryujinx.HLE.HOS.Font +{ + class SharedFontManager + { + private DeviceMemory Memory; + + private long PhysicalAddress; + + private string FontsPath; + + private struct FontInfo + { + public int Offset; + public int Size; + + public FontInfo(int Offset, int Size) + { + this.Offset = Offset; + this.Size = Size; + } + } + + private Dictionary FontData; + + public SharedFontManager(Switch Device, long PhysicalAddress) + { + this.PhysicalAddress = PhysicalAddress; + + Memory = Device.Memory; + + FontsPath = Path.Combine(Device.FileSystem.GetSystemPath(), "fonts"); + } + + public void EnsureInitialized() + { + if (FontData == null) + { + Memory.FillWithZeros(PhysicalAddress, Horizon.FontSize); + + uint FontOffset = 0; + + FontInfo CreateFont(string Name) + { + string FontFilePath = Path.Combine(FontsPath, Name + ".ttf"); + + if (File.Exists(FontFilePath)) + { + byte[] Data = File.ReadAllBytes(FontFilePath); + + FontInfo Info = new FontInfo((int)FontOffset, Data.Length); + + WriteMagicAndSize(PhysicalAddress + FontOffset, Data.Length); + + FontOffset += 8; + + uint Start = FontOffset; + + for (; FontOffset - Start < Data.Length; FontOffset++) + { + Memory.WriteByte(PhysicalAddress + FontOffset, Data[FontOffset - Start]); + } + + return Info; + } + else + { + throw new InvalidSystemResourceException($"Font \"{Name}.ttf\" not found. Please provide it in \"{FontsPath}\"."); + } + } + + FontData = new Dictionary() + { + { SharedFontType.JapanUsEurope, CreateFont("FontStandard") }, + { SharedFontType.SimplifiedChinese, CreateFont("FontChineseSimplified") }, + { SharedFontType.SimplifiedChineseEx, CreateFont("FontExtendedChineseSimplified") }, + { SharedFontType.TraditionalChinese, CreateFont("FontChineseTraditional") }, + { SharedFontType.Korean, CreateFont("FontKorean") }, + { SharedFontType.NintendoEx, CreateFont("FontNintendoExtended") } + }; + + if (FontOffset > Horizon.FontSize) + { + throw new InvalidSystemResourceException( + $"The sum of all fonts size exceed the shared memory size. " + + $"Please make sure that the fonts don't exceed {Horizon.FontSize} bytes in total. " + + $"(actual size: {FontOffset} bytes)."); + } + } + } + + private void WriteMagicAndSize(long Position, int Size) + { + const int DecMagic = 0x18029a7f; + const int Key = 0x49621806; + + int EncryptedSize = EndianSwap.Swap32(Size ^ Key); + + Memory.WriteInt32(Position + 0, DecMagic); + Memory.WriteInt32(Position + 4, EncryptedSize); + } + + public int GetFontSize(SharedFontType FontType) + { + EnsureInitialized(); + + return FontData[FontType].Size; + } + + public int GetSharedMemoryAddressOffset(SharedFontType FontType) + { + EnsureInitialized(); + + return FontData[FontType].Offset + 8; + } + } +} diff --git a/Ryujinx.HLE/HOS/Font/SharedFontType.cs b/Ryujinx.HLE/HOS/Font/SharedFontType.cs new file mode 100644 index 00000000..53dca626 --- /dev/null +++ b/Ryujinx.HLE/HOS/Font/SharedFontType.cs @@ -0,0 +1,13 @@ +namespace Ryujinx.HLE.HOS.Font +{ + public enum SharedFontType + { + JapanUsEurope = 0, + SimplifiedChinese = 1, + SimplifiedChineseEx = 2, + TraditionalChinese = 3, + Korean = 4, + NintendoEx = 5, + Count + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/GlobalStateTable.cs b/Ryujinx.HLE/HOS/GlobalStateTable.cs new file mode 100644 index 00000000..faf47b2e --- /dev/null +++ b/Ryujinx.HLE/HOS/GlobalStateTable.cs @@ -0,0 +1,69 @@ +using System.Collections.Concurrent; +using System.Collections.Generic; + +namespace Ryujinx.HLE.HOS +{ + class GlobalStateTable + { + private ConcurrentDictionary DictByProcess; + + public GlobalStateTable() + { + DictByProcess = new ConcurrentDictionary(); + } + + public bool Add(Process Process, int Id, object Data) + { + IdDictionary Dict = DictByProcess.GetOrAdd(Process, (Key) => new IdDictionary()); + + return Dict.Add(Id, Data); + } + + public int Add(Process Process, object Data) + { + IdDictionary Dict = DictByProcess.GetOrAdd(Process, (Key) => new IdDictionary()); + + return Dict.Add(Data); + } + + public object GetData(Process Process, int Id) + { + if (DictByProcess.TryGetValue(Process, out IdDictionary Dict)) + { + return Dict.GetData(Id); + } + + return null; + } + + public T GetData(Process Process, int Id) + { + if (DictByProcess.TryGetValue(Process, out IdDictionary Dict)) + { + return Dict.GetData(Id); + } + + return default(T); + } + + public object Delete(Process Process, int Id) + { + if (DictByProcess.TryGetValue(Process, out IdDictionary Dict)) + { + return Dict.Delete(Id); + } + + return null; + } + + public ICollection DeleteProcess(Process Process) + { + if (DictByProcess.TryRemove(Process, out IdDictionary Dict)) + { + return Dict.Clear(); + } + + return null; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Homebrew.cs b/Ryujinx.HLE/HOS/Homebrew.cs new file mode 100644 index 00000000..1f862a4a --- /dev/null +++ b/Ryujinx.HLE/HOS/Homebrew.cs @@ -0,0 +1,77 @@ +using ChocolArm64.Memory; +using System.Text; + +namespace Ryujinx.HLE.HOS +{ + static class Homebrew + { + public const string TemporaryNroSuffix = ".ryu_tmp.nro"; + + //http://switchbrew.org/index.php?title=Homebrew_ABI + public static void WriteHbAbiData(AMemory Memory, long Position, int MainThreadHandle, string SwitchPath) + { + //MainThreadHandle. + WriteConfigEntry(Memory, ref Position, 1, 0, MainThreadHandle); + + //NextLoadPath. + WriteConfigEntry(Memory, ref Position, 2, 0, Position + 0x200, Position + 0x400); + + //Argv. + long ArgvPosition = Position + 0xC00; + + Memory.WriteBytes(ArgvPosition, Encoding.ASCII.GetBytes(SwitchPath + "\0")); + + WriteConfigEntry(Memory, ref Position, 5, 0, 0, ArgvPosition); + + //AppletType. + WriteConfigEntry(Memory, ref Position, 7); + + //EndOfList. + WriteConfigEntry(Memory, ref Position, 0); + } + + private static void WriteConfigEntry( + AMemory Memory, + ref long Position, + int Key, + int Flags = 0, + long Value0 = 0, + long Value1 = 0) + { + Memory.WriteInt32(Position + 0x00, Key); + Memory.WriteInt32(Position + 0x04, Flags); + Memory.WriteInt64(Position + 0x08, Value0); + Memory.WriteInt64(Position + 0x10, Value1); + + Position += 0x18; + } + + public static string ReadHbAbiNextLoadPath(AMemory Memory, long Position) + { + string FileName = null; + + while (true) + { + long Key = Memory.ReadInt64(Position); + + if (Key == 2) + { + long Value0 = Memory.ReadInt64(Position + 0x08); + long Value1 = Memory.ReadInt64(Position + 0x10); + + FileName = AMemoryHelper.ReadAsciiString(Memory, Value0, Value1 - Value0); + + break; + } + else if (Key == 0) + { + break; + } + + Position += 0x18; + } + + return FileName; + } + } +} diff --git a/Ryujinx.HLE/HOS/Horizon.cs b/Ryujinx.HLE/HOS/Horizon.cs new file mode 100644 index 00000000..a5579675 --- /dev/null +++ b/Ryujinx.HLE/HOS/Horizon.cs @@ -0,0 +1,227 @@ +using Ryujinx.HLE.HOS.Font; +using Ryujinx.HLE.HOS.Kernel; +using Ryujinx.HLE.HOS.SystemState; +using Ryujinx.HLE.Loaders.Executables; +using Ryujinx.HLE.Loaders.Npdm; +using Ryujinx.HLE.Logging; +using System; +using System.Collections.Concurrent; +using System.IO; + +namespace Ryujinx.HLE.HOS +{ + public class Horizon : IDisposable + { + internal const int HidSize = 0x40000; + internal const int FontSize = 0x1100000; + + private Switch Device; + + private KProcessScheduler Scheduler; + + private ConcurrentDictionary Processes; + + public SystemStateMgr State { get; private set; } + + internal KSharedMemory HidSharedMem { get; private set; } + internal KSharedMemory FontSharedMem { get; private set; } + + internal SharedFontManager Font { get; private set; } + + internal KEvent VsyncEvent { get; private set; } + + public Horizon(Switch Device) + { + this.Device = Device; + + Scheduler = new KProcessScheduler(Device.Log); + + Processes = new ConcurrentDictionary(); + + State = new SystemStateMgr(); + + if (!Device.Memory.Allocator.TryAllocate(HidSize, out long HidPA) || + !Device.Memory.Allocator.TryAllocate(FontSize, out long FontPA)) + { + throw new InvalidOperationException(); + } + + HidSharedMem = new KSharedMemory(HidPA, HidSize); + FontSharedMem = new KSharedMemory(FontPA, FontSize); + + Font = new SharedFontManager(Device, FontSharedMem.PA); + + VsyncEvent = new KEvent(); + } + + public void LoadCart(string ExeFsDir, string RomFsFile = null) + { + if (RomFsFile != null) + { + Device.FileSystem.LoadRomFs(RomFsFile); + } + + string NpdmFileName = Path.Combine(ExeFsDir, "main.npdm"); + + Npdm MetaData = null; + + if (File.Exists(NpdmFileName)) + { + Device.Log.PrintInfo(LogClass.Loader, $"Loading main.npdm..."); + + using (FileStream Input = new FileStream(NpdmFileName, FileMode.Open)) + { + MetaData = new Npdm(Input); + } + } + else + { + Device.Log.PrintWarning(LogClass.Loader, $"NPDM file not found, using default values!"); + } + + Process MainProcess = MakeProcess(MetaData); + + void LoadNso(string FileName) + { + foreach (string File in Directory.GetFiles(ExeFsDir, FileName)) + { + if (Path.GetExtension(File) != string.Empty) + { + continue; + } + + Device.Log.PrintInfo(LogClass.Loader, $"Loading {Path.GetFileNameWithoutExtension(File)}..."); + + using (FileStream Input = new FileStream(File, FileMode.Open)) + { + string Name = Path.GetFileNameWithoutExtension(File); + + Nso Program = new Nso(Input, Name); + + MainProcess.LoadProgram(Program); + } + } + } + + if (!MainProcess.MetaData.Is64Bits) + { + throw new NotImplementedException("32-bit titles are unsupported!"); + } + + LoadNso("rtld"); + + MainProcess.SetEmptyArgs(); + + LoadNso("main"); + LoadNso("subsdk*"); + LoadNso("sdk"); + + MainProcess.Run(); + } + + public void LoadProgram(string FilePath) + { + bool IsNro = Path.GetExtension(FilePath).ToLower() == ".nro"; + + string Name = Path.GetFileNameWithoutExtension(FilePath); + string SwitchFilePath = Device.FileSystem.SystemPathToSwitchPath(FilePath); + + if (IsNro && (SwitchFilePath == null || !SwitchFilePath.StartsWith("sdmc:/"))) + { + string SwitchPath = $"sdmc:/switch/{Name}{Homebrew.TemporaryNroSuffix}"; + string TempPath = Device.FileSystem.SwitchPathToSystemPath(SwitchPath); + + string SwitchDir = Path.GetDirectoryName(TempPath); + + if (!Directory.Exists(SwitchDir)) + { + Directory.CreateDirectory(SwitchDir); + } + + File.Copy(FilePath, TempPath, true); + + FilePath = TempPath; + } + + Process MainProcess = MakeProcess(); + + using (FileStream Input = new FileStream(FilePath, FileMode.Open)) + { + MainProcess.LoadProgram(IsNro + ? (IExecutable)new Nro(Input, FilePath) + : (IExecutable)new Nso(Input, FilePath)); + } + + MainProcess.SetEmptyArgs(); + MainProcess.Run(IsNro); + } + + public void SignalVsync() => VsyncEvent.WaitEvent.Set(); + + private Process MakeProcess(Npdm MetaData = null) + { + Process Process; + + lock (Processes) + { + int ProcessId = 0; + + while (Processes.ContainsKey(ProcessId)) + { + ProcessId++; + } + + Process = new Process(Device, Scheduler, ProcessId, MetaData); + + Processes.TryAdd(ProcessId, Process); + } + + InitializeProcess(Process); + + return Process; + } + + private void InitializeProcess(Process Process) + { + Process.AppletState.SetFocus(true); + } + + internal void ExitProcess(int ProcessId) + { + if (Processes.TryRemove(ProcessId, out Process Process)) + { + Process.Dispose(); + + if (Processes.Count == 0) + { + Unload(); + + Device.Unload(); + } + } + } + + private void Unload() + { + VsyncEvent.Dispose(); + + Scheduler.Dispose(); + } + + public void Dispose() + { + Dispose(true); + } + + protected virtual void Dispose(bool Disposing) + { + if (Disposing) + { + foreach (Process Process in Processes.Values) + { + Process.Dispose(); + } + } + } + } +} diff --git a/Ryujinx.HLE/HOS/IdDictionary.cs b/Ryujinx.HLE/HOS/IdDictionary.cs new file mode 100644 index 00000000..03d15498 --- /dev/null +++ b/Ryujinx.HLE/HOS/IdDictionary.cs @@ -0,0 +1,73 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; + +namespace Ryujinx.HLE.HOS +{ + class IdDictionary + { + private ConcurrentDictionary Objs; + + public IdDictionary() + { + Objs = new ConcurrentDictionary(); + } + + public bool Add(int Id, object Data) + { + return Objs.TryAdd(Id, Data); + } + + public int Add(object Data) + { + for (int Id = 1; Id < int.MaxValue; Id++) + { + if (Objs.TryAdd(Id, Data)) + { + return Id; + } + } + + throw new InvalidOperationException(); + } + + public object GetData(int Id) + { + if (Objs.TryGetValue(Id, out object Data)) + { + return Data; + } + + return null; + } + + public T GetData(int Id) + { + if (Objs.TryGetValue(Id, out object Data) && Data is T) + { + return (T)Data; + } + + return default(T); + } + + public object Delete(int Id) + { + if (Objs.TryRemove(Id, out object Obj)) + { + return Obj; + } + + return null; + } + + public ICollection Clear() + { + ICollection Values = Objs.Values; + + Objs.Clear(); + + return Values; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Ipc/IpcBuffDesc.cs b/Ryujinx.HLE/HOS/Ipc/IpcBuffDesc.cs new file mode 100644 index 00000000..346d696e --- /dev/null +++ b/Ryujinx.HLE/HOS/Ipc/IpcBuffDesc.cs @@ -0,0 +1,27 @@ +using System.IO; + +namespace Ryujinx.HLE.HOS.Ipc +{ + struct IpcBuffDesc + { + public long Position { get; private set; } + public long Size { get; private set; } + public int Flags { get; private set; } + + public IpcBuffDesc(BinaryReader Reader) + { + long Word0 = Reader.ReadUInt32(); + long Word1 = Reader.ReadUInt32(); + long Word2 = Reader.ReadUInt32(); + + Position = Word1; + Position |= (Word2 << 4) & 0x0f00000000; + Position |= (Word2 << 34) & 0x7000000000; + + Size = Word0; + Size |= (Word2 << 8) & 0xf00000000; + + Flags = (int)Word2 & 3; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Ipc/IpcHandleDesc.cs b/Ryujinx.HLE/HOS/Ipc/IpcHandleDesc.cs new file mode 100644 index 00000000..081b5695 --- /dev/null +++ b/Ryujinx.HLE/HOS/Ipc/IpcHandleDesc.cs @@ -0,0 +1,92 @@ +using System; +using System.IO; + +namespace Ryujinx.HLE.HOS.Ipc +{ + class IpcHandleDesc + { + public bool HasPId { get; private set; } + + public long PId { get; private set; } + + public int[] ToCopy { get; private set; } + public int[] ToMove { get; private set; } + + public IpcHandleDesc(BinaryReader Reader) + { + int Word = Reader.ReadInt32(); + + HasPId = (Word & 1) != 0; + + ToCopy = new int[(Word >> 1) & 0xf]; + ToMove = new int[(Word >> 5) & 0xf]; + + PId = HasPId ? Reader.ReadInt64() : 0; + + for (int Index = 0; Index < ToCopy.Length; Index++) + { + ToCopy[Index] = Reader.ReadInt32(); + } + + for (int Index = 0; Index < ToMove.Length; Index++) + { + ToMove[Index] = Reader.ReadInt32(); + } + } + + public IpcHandleDesc(int[] Copy, int[] Move) + { + ToCopy = Copy ?? throw new ArgumentNullException(nameof(Copy)); + ToMove = Move ?? throw new ArgumentNullException(nameof(Move)); + } + + public IpcHandleDesc(int[] Copy, int[] Move, long PId) : this(Copy, Move) + { + this.PId = PId; + + HasPId = true; + } + + public static IpcHandleDesc MakeCopy(params int[] Handles) + { + return new IpcHandleDesc(Handles, new int[0]); + } + + public static IpcHandleDesc MakeMove(params int[] Handles) + { + return new IpcHandleDesc(new int[0], Handles); + } + + public byte[] GetBytes() + { + using (MemoryStream MS = new MemoryStream()) + { + BinaryWriter Writer = new BinaryWriter(MS); + + int Word = HasPId ? 1 : 0; + + Word |= (ToCopy.Length & 0xf) << 1; + Word |= (ToMove.Length & 0xf) << 5; + + Writer.Write(Word); + + if (HasPId) + { + Writer.Write((long)PId); + } + + foreach (int Handle in ToCopy) + { + Writer.Write(Handle); + } + + foreach (int Handle in ToMove) + { + Writer.Write(Handle); + } + + return MS.ToArray(); + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Ipc/IpcHandler.cs b/Ryujinx.HLE/HOS/Ipc/IpcHandler.cs new file mode 100644 index 00000000..08a4cdb5 --- /dev/null +++ b/Ryujinx.HLE/HOS/Ipc/IpcHandler.cs @@ -0,0 +1,140 @@ +using ChocolArm64.Memory; +using Ryujinx.HLE.HOS.Kernel; +using System; +using System.IO; + +namespace Ryujinx.HLE.HOS.Ipc +{ + static class IpcHandler + { + public static long IpcCall( + Switch Ns, + Process Process, + AMemory Memory, + KSession Session, + IpcMessage Request, + long CmdPtr) + { + IpcMessage Response = new IpcMessage(); + + using (MemoryStream Raw = new MemoryStream(Request.RawData)) + { + BinaryReader ReqReader = new BinaryReader(Raw); + + if (Request.Type == IpcMessageType.Request || + Request.Type == IpcMessageType.RequestWithContext) + { + Response.Type = IpcMessageType.Response; + + using (MemoryStream ResMS = new MemoryStream()) + { + BinaryWriter ResWriter = new BinaryWriter(ResMS); + + ServiceCtx Context = new ServiceCtx( + Ns, + Process, + Memory, + Session, + Request, + Response, + ReqReader, + ResWriter); + + Session.Service.CallMethod(Context); + + Response.RawData = ResMS.ToArray(); + } + } + else if (Request.Type == IpcMessageType.Control || + Request.Type == IpcMessageType.ControlWithContext) + { + long Magic = ReqReader.ReadInt64(); + long CmdId = ReqReader.ReadInt64(); + + switch (CmdId) + { + case 0: + { + Request = FillResponse(Response, 0, Session.Service.ConvertToDomain()); + + break; + } + + case 3: + { + Request = FillResponse(Response, 0, 0x500); + + break; + } + + //TODO: Whats the difference between IpcDuplicateSession/Ex? + case 2: + case 4: + { + int Unknown = ReqReader.ReadInt32(); + + int Handle = Process.HandleTable.OpenHandle(Session); + + Response.HandleDesc = IpcHandleDesc.MakeMove(Handle); + + Request = FillResponse(Response, 0); + + break; + } + + default: throw new NotImplementedException(CmdId.ToString()); + } + } + else if (Request.Type == IpcMessageType.CloseSession) + { + //TODO + } + else + { + throw new NotImplementedException(Request.Type.ToString()); + } + + Memory.WriteBytes(CmdPtr, Response.GetBytes(CmdPtr)); + } + + return 0; + } + + private static IpcMessage FillResponse(IpcMessage Response, long Result, params int[] Values) + { + using (MemoryStream MS = new MemoryStream()) + { + BinaryWriter Writer = new BinaryWriter(MS); + + foreach (int Value in Values) + { + Writer.Write(Value); + } + + return FillResponse(Response, Result, MS.ToArray()); + } + } + + private static IpcMessage FillResponse(IpcMessage Response, long Result, byte[] Data = null) + { + Response.Type = IpcMessageType.Response; + + using (MemoryStream MS = new MemoryStream()) + { + BinaryWriter Writer = new BinaryWriter(MS); + + Writer.Write(IpcMagic.Sfco); + Writer.Write(Result); + + if (Data != null) + { + Writer.Write(Data); + } + + Response.RawData = MS.ToArray(); + } + + return Response; + } + } +} diff --git a/Ryujinx.HLE/HOS/Ipc/IpcMagic.cs b/Ryujinx.HLE/HOS/Ipc/IpcMagic.cs new file mode 100644 index 00000000..72770b90 --- /dev/null +++ b/Ryujinx.HLE/HOS/Ipc/IpcMagic.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Ipc +{ + abstract class IpcMagic + { + public const long Sfci = 'S' << 0 | 'F' << 8 | 'C' << 16 | 'I' << 24; + public const long Sfco = 'S' << 0 | 'F' << 8 | 'C' << 16 | 'O' << 24; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Ipc/IpcMessage.cs b/Ryujinx.HLE/HOS/Ipc/IpcMessage.cs new file mode 100644 index 00000000..c8153fdb --- /dev/null +++ b/Ryujinx.HLE/HOS/Ipc/IpcMessage.cs @@ -0,0 +1,215 @@ +using System.Collections.Generic; +using System.IO; + +namespace Ryujinx.HLE.HOS.Ipc +{ + class IpcMessage + { + public IpcMessageType Type { get; set; } + + public IpcHandleDesc HandleDesc { get; set; } + + public List PtrBuff { get; private set; } + public List SendBuff { get; private set; } + public List ReceiveBuff { get; private set; } + public List ExchangeBuff { get; private set; } + public List RecvListBuff { get; private set; } + + public List ObjectIds { get; private set; } + + public byte[] RawData { get; set; } + + public IpcMessage() + { + PtrBuff = new List(); + SendBuff = new List(); + ReceiveBuff = new List(); + ExchangeBuff = new List(); + RecvListBuff = new List(); + + ObjectIds = new List(); + } + + public IpcMessage(byte[] Data, long CmdPtr) : this() + { + using (MemoryStream MS = new MemoryStream(Data)) + { + BinaryReader Reader = new BinaryReader(MS); + + Initialize(Reader, CmdPtr); + } + } + + private void Initialize(BinaryReader Reader, long CmdPtr) + { + int Word0 = Reader.ReadInt32(); + int Word1 = Reader.ReadInt32(); + + Type = (IpcMessageType)(Word0 & 0xffff); + + int PtrBuffCount = (Word0 >> 16) & 0xf; + int SendBuffCount = (Word0 >> 20) & 0xf; + int RecvBuffCount = (Word0 >> 24) & 0xf; + int XchgBuffCount = (Word0 >> 28) & 0xf; + + int RawDataSize = (Word1 >> 0) & 0x3ff; + int RecvListFlags = (Word1 >> 10) & 0xf; + bool HndDescEnable = ((Word1 >> 31) & 0x1) != 0; + + if (HndDescEnable) + { + HandleDesc = new IpcHandleDesc(Reader); + } + + for (int Index = 0; Index < PtrBuffCount; Index++) + { + PtrBuff.Add(new IpcPtrBuffDesc(Reader)); + } + + void ReadBuff(List Buff, int Count) + { + for (int Index = 0; Index < Count; Index++) + { + Buff.Add(new IpcBuffDesc(Reader)); + } + } + + ReadBuff(SendBuff, SendBuffCount); + ReadBuff(ReceiveBuff, RecvBuffCount); + ReadBuff(ExchangeBuff, XchgBuffCount); + + RawDataSize *= 4; + + long RecvListPos = Reader.BaseStream.Position + RawDataSize; + + long Pad0 = GetPadSize16(Reader.BaseStream.Position + CmdPtr); + + Reader.BaseStream.Seek(Pad0, SeekOrigin.Current); + + int RecvListCount = RecvListFlags - 2; + + if (RecvListCount == 0) + { + RecvListCount = 1; + } + else if (RecvListCount < 0) + { + RecvListCount = 0; + } + + RawData = Reader.ReadBytes(RawDataSize); + + Reader.BaseStream.Seek(RecvListPos, SeekOrigin.Begin); + + for (int Index = 0; Index < RecvListCount; Index++) + { + RecvListBuff.Add(new IpcRecvListBuffDesc(Reader)); + } + } + + public byte[] GetBytes(long CmdPtr) + { + using (MemoryStream MS = new MemoryStream()) + { + BinaryWriter Writer = new BinaryWriter(MS); + + int Word0; + int Word1; + + Word0 = (int)Type; + Word0 |= (PtrBuff.Count & 0xf) << 16; + Word0 |= (SendBuff.Count & 0xf) << 20; + Word0 |= (ReceiveBuff.Count & 0xf) << 24; + Word0 |= (ExchangeBuff.Count & 0xf) << 28; + + byte[] HandleData = new byte[0]; + + if (HandleDesc != null) + { + HandleData = HandleDesc.GetBytes(); + } + + int DataLength = RawData?.Length ?? 0; + + int Pad0 = (int)GetPadSize16(CmdPtr + 8 + HandleData.Length); + + //Apparently, padding after Raw Data is 16 bytes, however when there is + //padding before Raw Data too, we need to subtract the size of this padding. + //This is the weirdest padding I've seen so far... + int Pad1 = 0x10 - Pad0; + + DataLength = (DataLength + Pad0 + Pad1) / 4; + + Word1 = DataLength & 0x3ff; + + if (HandleDesc != null) + { + Word1 |= 1 << 31; + } + + Writer.Write(Word0); + Writer.Write(Word1); + Writer.Write(HandleData); + + MS.Seek(Pad0, SeekOrigin.Current); + + if (RawData != null) + { + Writer.Write(RawData); + } + + Writer.Write(new byte[Pad1]); + + return MS.ToArray(); + } + } + + private long GetPadSize16(long Position) + { + if ((Position & 0xf) != 0) + { + return 0x10 - (Position & 0xf); + } + + return 0; + } + + public (long Position, long Size) GetBufferType0x21() + { + if (PtrBuff.Count != 0 && + PtrBuff[0].Position != 0 && + PtrBuff[0].Size != 0) + { + return (PtrBuff[0].Position, PtrBuff[0].Size); + } + + if (SendBuff.Count != 0 && + SendBuff[0].Position != 0 && + SendBuff[0].Size != 0) + { + return (SendBuff[0].Position, SendBuff[0].Size); + } + + return (0, 0); + } + + public (long Position, long Size) GetBufferType0x22() + { + if (RecvListBuff.Count != 0 && + RecvListBuff[0].Position != 0 && + RecvListBuff[0].Size != 0) + { + return (RecvListBuff[0].Position, RecvListBuff[0].Size); + } + + if (ReceiveBuff.Count != 0 && + ReceiveBuff[0].Position != 0 && + ReceiveBuff[0].Size != 0) + { + return (ReceiveBuff[0].Position, ReceiveBuff[0].Size); + } + + return (0, 0); + } + } +} diff --git a/Ryujinx.HLE/HOS/Ipc/IpcMessageType.cs b/Ryujinx.HLE/HOS/Ipc/IpcMessageType.cs new file mode 100644 index 00000000..e258accc --- /dev/null +++ b/Ryujinx.HLE/HOS/Ipc/IpcMessageType.cs @@ -0,0 +1,12 @@ +namespace Ryujinx.HLE.HOS.Ipc +{ + enum IpcMessageType + { + Response = 0, + CloseSession = 2, + Request = 4, + Control = 5, + RequestWithContext = 6, + ControlWithContext = 7 + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Ipc/IpcPtrBuffDesc.cs b/Ryujinx.HLE/HOS/Ipc/IpcPtrBuffDesc.cs new file mode 100644 index 00000000..21f5d3bc --- /dev/null +++ b/Ryujinx.HLE/HOS/Ipc/IpcPtrBuffDesc.cs @@ -0,0 +1,26 @@ +using System.IO; + +namespace Ryujinx.HLE.HOS.Ipc +{ + struct IpcPtrBuffDesc + { + public long Position { get; private set; } + public int Index { get; private set; } + public long Size { get; private set; } + + public IpcPtrBuffDesc(BinaryReader Reader) + { + long Word0 = Reader.ReadUInt32(); + long Word1 = Reader.ReadUInt32(); + + Position = Word1; + Position |= (Word0 << 20) & 0x0f00000000; + Position |= (Word0 << 30) & 0x7000000000; + + Index = ((int)Word0 >> 0) & 0x03f; + Index |= ((int)Word0 >> 3) & 0x1c0; + + Size = (ushort)(Word0 >> 16); + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Ipc/IpcRecvListBuffDesc.cs b/Ryujinx.HLE/HOS/Ipc/IpcRecvListBuffDesc.cs new file mode 100644 index 00000000..1d0a8c80 --- /dev/null +++ b/Ryujinx.HLE/HOS/Ipc/IpcRecvListBuffDesc.cs @@ -0,0 +1,19 @@ +using System.IO; + +namespace Ryujinx.HLE.HOS.Ipc +{ + struct IpcRecvListBuffDesc + { + public long Position { get; private set; } + public long Size { get; private set; } + + public IpcRecvListBuffDesc(BinaryReader Reader) + { + long Value = Reader.ReadInt64(); + + Position = Value & 0xffffffffffff; + + Size = (ushort)(Value >> 48); + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Ipc/ServiceProcessRequest.cs b/Ryujinx.HLE/HOS/Ipc/ServiceProcessRequest.cs new file mode 100644 index 00000000..da4a7e75 --- /dev/null +++ b/Ryujinx.HLE/HOS/Ipc/ServiceProcessRequest.cs @@ -0,0 +1,4 @@ +namespace Ryujinx.HLE.HOS.Ipc +{ + delegate long ServiceProcessRequest(ServiceCtx Context); +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Kernel/AddressArbiter.cs b/Ryujinx.HLE/HOS/Kernel/AddressArbiter.cs new file mode 100644 index 00000000..d7df0a72 --- /dev/null +++ b/Ryujinx.HLE/HOS/Kernel/AddressArbiter.cs @@ -0,0 +1,111 @@ +using ChocolArm64.Memory; +using ChocolArm64.State; + +using static Ryujinx.HLE.HOS.ErrorCode; + +namespace Ryujinx.HLE.HOS.Kernel +{ + static class AddressArbiter + { + static ulong WaitForAddress(Process Process, AThreadState ThreadState, long Address, ulong Timeout) + { + KThread CurrentThread = Process.GetThread(ThreadState.Tpidr); + + Process.Scheduler.SetReschedule(CurrentThread.ProcessorId); + + CurrentThread.ArbiterWaitAddress = Address; + CurrentThread.ArbiterSignaled = false; + + Process.Scheduler.EnterWait(CurrentThread, NsTimeConverter.GetTimeMs(Timeout)); + + if (!CurrentThread.ArbiterSignaled) + { + return MakeError(ErrorModule.Kernel, KernelErr.Timeout); + } + + return 0; + } + + public static ulong WaitForAddressIfLessThan(Process Process, + AThreadState ThreadState, + AMemory Memory, + long Address, + int Value, + ulong Timeout, + bool ShouldDecrement) + { + Memory.SetExclusive(ThreadState, Address); + + int CurrentValue = Memory.ReadInt32(Address); + + while (true) + { + if (Memory.TestExclusive(ThreadState, Address)) + { + if (CurrentValue < Value) + { + if (ShouldDecrement) + { + Memory.WriteInt32(Address, CurrentValue - 1); + } + + Memory.ClearExclusiveForStore(ThreadState); + } + else + { + Memory.ClearExclusiveForStore(ThreadState); + + return MakeError(ErrorModule.Kernel, KernelErr.InvalidState); + } + + break; + } + + Memory.SetExclusive(ThreadState, Address); + + CurrentValue = Memory.ReadInt32(Address); + } + + if (Timeout == 0) + { + return MakeError(ErrorModule.Kernel, KernelErr.Timeout); + } + + return WaitForAddress(Process, ThreadState, Address, Timeout); + } + + public static ulong WaitForAddressIfEqual(Process Process, + AThreadState ThreadState, + AMemory Memory, + long Address, + int Value, + ulong Timeout) + { + if (Memory.ReadInt32(Address) != Value) + { + return MakeError(ErrorModule.Kernel, KernelErr.InvalidState); + } + + if (Timeout == 0) + { + return MakeError(ErrorModule.Kernel, KernelErr.Timeout); + } + + return WaitForAddress(Process, ThreadState, Address, Timeout); + } + } + + enum ArbitrationType : int + { + WaitIfLessThan, + DecrementAndWaitIfLessThan, + WaitIfEqual + } + + enum SignalType : int + { + Signal, + IncrementAndSignalIfEqual, + ModifyByWaitingCountAndSignalIfEqual + } +} diff --git a/Ryujinx.HLE/HOS/Kernel/AddressSpaceType.cs b/Ryujinx.HLE/HOS/Kernel/AddressSpaceType.cs new file mode 100644 index 00000000..c97caf42 --- /dev/null +++ b/Ryujinx.HLE/HOS/Kernel/AddressSpaceType.cs @@ -0,0 +1,10 @@ +namespace Ryujinx.HLE.HOS.Kernel +{ + enum AddressSpaceType + { + Addr32Bits = 0, + Addr36Bits = 1, + Addr36BitsNoMap = 2, + Addr39Bits = 3 + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Kernel/KEvent.cs b/Ryujinx.HLE/HOS/Kernel/KEvent.cs new file mode 100644 index 00000000..eaaafaba --- /dev/null +++ b/Ryujinx.HLE/HOS/Kernel/KEvent.cs @@ -0,0 +1,4 @@ +namespace Ryujinx.HLE.HOS.Kernel +{ + class KEvent : KSynchronizationObject { } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Kernel/KMemoryBlock.cs b/Ryujinx.HLE/HOS/Kernel/KMemoryBlock.cs new file mode 100644 index 00000000..6100741b --- /dev/null +++ b/Ryujinx.HLE/HOS/Kernel/KMemoryBlock.cs @@ -0,0 +1,43 @@ +namespace Ryujinx.HLE.HOS.Kernel +{ + class KMemoryBlock + { + public long BasePosition { get; set; } + public long PagesCount { get; set; } + + public MemoryState State { get; set; } + public MemoryPermission Permission { get; set; } + public MemoryAttribute Attribute { get; set; } + + public int IpcRefCount { get; set; } + public int DeviceRefCount { get; set; } + + public KMemoryBlock( + long BasePosition, + long PagesCount, + MemoryState State, + MemoryPermission Permission, + MemoryAttribute Attribute) + { + this.BasePosition = BasePosition; + this.PagesCount = PagesCount; + this.State = State; + this.Attribute = Attribute; + this.Permission = Permission; + } + + public KMemoryInfo GetInfo() + { + long Size = PagesCount * KMemoryManager.PageSize; + + return new KMemoryInfo( + BasePosition, + Size, + State, + Permission, + Attribute, + IpcRefCount, + DeviceRefCount); + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Kernel/KMemoryInfo.cs b/Ryujinx.HLE/HOS/Kernel/KMemoryInfo.cs new file mode 100644 index 00000000..9b73b32b --- /dev/null +++ b/Ryujinx.HLE/HOS/Kernel/KMemoryInfo.cs @@ -0,0 +1,33 @@ +namespace Ryujinx.HLE.HOS.Kernel +{ + class KMemoryInfo + { + public long Position { get; private set; } + public long Size { get; private set; } + + public MemoryState State { get; private set; } + public MemoryPermission Permission { get; private set; } + public MemoryAttribute Attribute { get; private set; } + + public int IpcRefCount { get; private set; } + public int DeviceRefCount { get; private set; } + + public KMemoryInfo( + long Position, + long Size, + MemoryState State, + MemoryPermission Permission, + MemoryAttribute Attribute, + int IpcRefCount, + int DeviceRefCount) + { + this.Position = Position; + this.Size = Size; + this.State = State; + this.Attribute = Attribute; + this.Permission = Permission; + this.IpcRefCount = IpcRefCount; + this.DeviceRefCount = DeviceRefCount; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Kernel/KMemoryManager.cs b/Ryujinx.HLE/HOS/Kernel/KMemoryManager.cs new file mode 100644 index 00000000..0432aa88 --- /dev/null +++ b/Ryujinx.HLE/HOS/Kernel/KMemoryManager.cs @@ -0,0 +1,1081 @@ +using ChocolArm64.Memory; +using Ryujinx.HLE.Memory; +using System; +using System.Collections.Generic; + +using static Ryujinx.HLE.HOS.ErrorCode; + +namespace Ryujinx.HLE.HOS.Kernel +{ + class KMemoryManager + { + public const int PageSize = 0x1000; + + private LinkedList Blocks; + + private AMemory CpuMemory; + + private ArenaAllocator Allocator; + + public long AddrSpaceStart { get; private set; } + public long AddrSpaceEnd { get; private set; } + + public long CodeRegionStart { get; private set; } + public long CodeRegionEnd { get; private set; } + + public long MapRegionStart { get; private set; } + public long MapRegionEnd { get; private set; } + + public long HeapRegionStart { get; private set; } + public long HeapRegionEnd { get; private set; } + + public long NewMapRegionStart { get; private set; } + public long NewMapRegionEnd { get; private set; } + + public long TlsIoRegionStart { get; private set; } + public long TlsIoRegionEnd { get; private set; } + + public long PersonalMmHeapUsage { get; private set; } + + private long CurrentHeapAddr; + + public KMemoryManager(Process Process) + { + CpuMemory = Process.Memory; + Allocator = Process.Device.Memory.Allocator; + + long CodeRegionSize; + long MapRegionSize; + long HeapRegionSize; + long NewMapRegionSize; + long TlsIoRegionSize; + int AddrSpaceWidth; + + AddressSpaceType AddrType = AddressSpaceType.Addr39Bits; + + if (Process.MetaData != null) + { + AddrType = (AddressSpaceType)Process.MetaData.AddressSpaceWidth; + } + + switch (AddrType) + { + case AddressSpaceType.Addr32Bits: + CodeRegionStart = 0x200000; + CodeRegionSize = 0x3fe00000; + MapRegionSize = 0x40000000; + HeapRegionSize = 0x40000000; + NewMapRegionSize = 0; + TlsIoRegionSize = 0; + AddrSpaceWidth = 32; + break; + + case AddressSpaceType.Addr36Bits: + CodeRegionStart = 0x8000000; + CodeRegionSize = 0x78000000; + MapRegionSize = 0x180000000; + HeapRegionSize = 0x180000000; + NewMapRegionSize = 0; + TlsIoRegionSize = 0; + AddrSpaceWidth = 36; + break; + + case AddressSpaceType.Addr36BitsNoMap: + CodeRegionStart = 0x200000; + CodeRegionSize = 0x3fe00000; + MapRegionSize = 0; + HeapRegionSize = 0x80000000; + NewMapRegionSize = 0; + TlsIoRegionSize = 0; + AddrSpaceWidth = 36; + break; + + case AddressSpaceType.Addr39Bits: + CodeRegionStart = 0; + CodeRegionSize = 0x80000000; + MapRegionSize = 0x1000000000; + HeapRegionSize = 0x180000000; + NewMapRegionSize = 0x80000000; + TlsIoRegionSize = 0x1000000000; + AddrSpaceWidth = 39; + break; + + default: throw new InvalidOperationException(); + } + + AddrSpaceStart = 0; + AddrSpaceEnd = 1L << AddrSpaceWidth; + + CodeRegionEnd = CodeRegionStart + CodeRegionSize; + MapRegionStart = CodeRegionEnd; + MapRegionEnd = CodeRegionEnd + MapRegionSize; + HeapRegionStart = MapRegionEnd; + HeapRegionEnd = MapRegionEnd + HeapRegionSize; + NewMapRegionStart = HeapRegionEnd; + NewMapRegionEnd = HeapRegionEnd + NewMapRegionSize; + TlsIoRegionStart = NewMapRegionEnd; + TlsIoRegionEnd = NewMapRegionEnd + TlsIoRegionSize; + + CurrentHeapAddr = HeapRegionStart; + + if (NewMapRegionSize == 0) + { + NewMapRegionStart = AddrSpaceStart; + NewMapRegionEnd = AddrSpaceEnd; + } + + Blocks = new LinkedList(); + + long AddrSpacePagesCount = (AddrSpaceEnd - AddrSpaceStart) / PageSize; + + InsertBlock(AddrSpaceStart, AddrSpacePagesCount, MemoryState.Unmapped); + } + + public void HleMapProcessCode(long Position, long Size) + { + long PagesCount = Size / PageSize; + + if (!Allocator.TryAllocate(Size, out long PA)) + { + throw new InvalidOperationException(); + } + + lock (Blocks) + { + InsertBlock(Position, PagesCount, MemoryState.CodeStatic, MemoryPermission.ReadAndExecute); + + CpuMemory.Map(Position, PA, Size); + } + } + + public void HleMapCustom(long Position, long Size, MemoryState State, MemoryPermission Permission) + { + long PagesCount = Size / PageSize; + + if (!Allocator.TryAllocate(Size, out long PA)) + { + throw new InvalidOperationException(); + } + + lock (Blocks) + { + InsertBlock(Position, PagesCount, State, Permission); + + CpuMemory.Map(Position, PA, Size); + } + } + + public long HleMapTlsPage() + { + bool HasTlsIoRegion = TlsIoRegionStart != TlsIoRegionEnd; + + long Position = HasTlsIoRegion ? TlsIoRegionStart : CodeRegionStart; + + lock (Blocks) + { + while (Position < (HasTlsIoRegion ? TlsIoRegionEnd : CodeRegionEnd)) + { + if (FindBlock(Position).State == MemoryState.Unmapped) + { + InsertBlock(Position, 1, MemoryState.ThreadLocal, MemoryPermission.ReadAndWrite); + + if (!Allocator.TryAllocate(PageSize, out long PA)) + { + throw new InvalidOperationException(); + } + + CpuMemory.Map(Position, PA, PageSize); + + return Position; + } + + Position += PageSize; + } + + throw new InvalidOperationException(); + } + } + + public long TrySetHeapSize(long Size, out long Position) + { + Position = 0; + + if ((ulong)Size > (ulong)(HeapRegionEnd - HeapRegionStart)) + { + return MakeError(ErrorModule.Kernel, KernelErr.OutOfMemory); + } + + bool Success = false; + + long CurrentHeapSize = GetHeapSize(); + + if ((ulong)CurrentHeapSize <= (ulong)Size) + { + //Expand. + long DiffSize = Size - CurrentHeapSize; + + lock (Blocks) + { + if (Success = IsUnmapped(CurrentHeapAddr, DiffSize)) + { + if (!Allocator.TryAllocate(DiffSize, out long PA)) + { + return MakeError(ErrorModule.Kernel, KernelErr.OutOfMemory); + } + + long PagesCount = DiffSize / PageSize; + + InsertBlock(CurrentHeapAddr, PagesCount, MemoryState.Heap, MemoryPermission.ReadAndWrite); + + CpuMemory.Map(CurrentHeapAddr, PA, DiffSize); + } + } + } + else + { + //Shrink. + long FreeAddr = HeapRegionStart + Size; + long DiffSize = CurrentHeapSize - Size; + + lock (Blocks) + { + Success = CheckRange( + FreeAddr, + DiffSize, + MemoryState.Mask, + MemoryState.Heap, + MemoryPermission.Mask, + MemoryPermission.ReadAndWrite, + MemoryAttribute.Mask, + MemoryAttribute.None, + MemoryAttribute.IpcAndDeviceMapped, + out _, + out _, + out _); + + if (Success) + { + long PagesCount = DiffSize / PageSize; + + InsertBlock(FreeAddr, PagesCount, MemoryState.Unmapped); + + CpuMemory.Unmap(FreeAddr, DiffSize); + + FreePages(FreeAddr, PagesCount); + } + } + } + + CurrentHeapAddr = HeapRegionStart + Size; + + if (Success) + { + Position = HeapRegionStart; + + return 0; + } + + return MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); + } + + public long GetHeapSize() + { + return CurrentHeapAddr - HeapRegionStart; + } + + public long SetMemoryAttribute( + long Position, + long Size, + MemoryAttribute AttributeMask, + MemoryAttribute AttributeValue) + { + lock (Blocks) + { + if (CheckRange( + Position, + Size, + MemoryState.AttributeChangeAllowed, + MemoryState.AttributeChangeAllowed, + MemoryPermission.None, + MemoryPermission.None, + MemoryAttribute.BorrowedAndIpcMapped, + MemoryAttribute.None, + MemoryAttribute.DeviceMappedAndUncached, + out MemoryState State, + out MemoryPermission Permission, + out MemoryAttribute Attribute)) + { + long PagesCount = Size / PageSize; + + Attribute &= ~AttributeMask; + Attribute |= AttributeMask & AttributeValue; + + InsertBlock(Position, PagesCount, State, Permission, Attribute); + + return 0; + } + } + + return MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); + } + + public KMemoryInfo QueryMemory(long Position) + { + if ((ulong)Position >= (ulong)AddrSpaceStart && + (ulong)Position < (ulong)AddrSpaceEnd) + { + lock (Blocks) + { + return FindBlock(Position).GetInfo(); + } + } + else + { + return new KMemoryInfo( + AddrSpaceEnd, + -AddrSpaceEnd, + MemoryState.Reserved, + MemoryPermission.None, + MemoryAttribute.None, + 0, + 0); + } + } + + public long Map(long Src, long Dst, long Size) + { + bool Success; + + lock (Blocks) + { + Success = CheckRange( + Src, + Size, + MemoryState.MapAllowed, + MemoryState.MapAllowed, + MemoryPermission.Mask, + MemoryPermission.ReadAndWrite, + MemoryAttribute.Mask, + MemoryAttribute.None, + MemoryAttribute.IpcAndDeviceMapped, + out MemoryState SrcState, + out _, + out _); + + Success &= IsUnmapped(Dst, Size); + + if (Success) + { + long PagesCount = Size / PageSize; + + InsertBlock(Src, PagesCount, SrcState, MemoryPermission.None, MemoryAttribute.Borrowed); + + InsertBlock(Dst, PagesCount, MemoryState.MappedMemory, MemoryPermission.ReadAndWrite); + + long PA = CpuMemory.GetPhysicalAddress(Src); + + CpuMemory.Map(Dst, PA, Size); + } + } + + return Success ? 0 : MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); + } + + public long Unmap(long Src, long Dst, long Size) + { + bool Success; + + lock (Blocks) + { + Success = CheckRange( + Src, + Size, + MemoryState.MapAllowed, + MemoryState.MapAllowed, + MemoryPermission.Mask, + MemoryPermission.None, + MemoryAttribute.Mask, + MemoryAttribute.Borrowed, + MemoryAttribute.IpcAndDeviceMapped, + out MemoryState SrcState, + out _, + out _); + + Success &= CheckRange( + Dst, + Size, + MemoryState.Mask, + MemoryState.MappedMemory, + MemoryPermission.None, + MemoryPermission.None, + MemoryAttribute.Mask, + MemoryAttribute.None, + MemoryAttribute.IpcAndDeviceMapped, + out _, + out _, + out _); + + if (Success) + { + long PagesCount = Size / PageSize; + + InsertBlock(Src, PagesCount, SrcState, MemoryPermission.ReadAndWrite); + + InsertBlock(Dst, PagesCount, MemoryState.Unmapped); + + CpuMemory.Unmap(Dst, Size); + } + } + + return Success ? 0 : MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); + } + + public long MapSharedMemory(KSharedMemory SharedMemory, MemoryPermission Permission, long Position) + { + lock (Blocks) + { + if (IsUnmapped(Position, SharedMemory.Size)) + { + long PagesCount = SharedMemory.Size / PageSize; + + InsertBlock(Position, PagesCount, MemoryState.SharedMemory, Permission); + + CpuMemory.Map(Position, SharedMemory.PA, SharedMemory.Size); + + return 0; + } + } + + return MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); + } + + public long UnmapSharedMemory(long Position, long Size) + { + lock (Blocks) + { + if (CheckRange( + Position, + Size, + MemoryState.Mask, + MemoryState.SharedMemory, + MemoryPermission.None, + MemoryPermission.None, + MemoryAttribute.Mask, + MemoryAttribute.None, + MemoryAttribute.IpcAndDeviceMapped, + out MemoryState State, + out _, + out _)) + { + long PagesCount = Size / PageSize; + + InsertBlock(Position, PagesCount, MemoryState.Unmapped); + + CpuMemory.Unmap(Position, Size); + + return 0; + } + } + + return MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); + } + + public long ReserveTransferMemory(long Position, long Size, MemoryPermission Permission) + { + lock (Blocks) + { + if (CheckRange( + Position, + Size, + MemoryState.TransferMemoryAllowed | MemoryState.IsPoolAllocated, + MemoryState.TransferMemoryAllowed | MemoryState.IsPoolAllocated, + MemoryPermission.Mask, + MemoryPermission.ReadAndWrite, + MemoryAttribute.Mask, + MemoryAttribute.None, + MemoryAttribute.IpcAndDeviceMapped, + out MemoryState State, + out _, + out MemoryAttribute Attribute)) + { + long PagesCount = Size / PageSize; + + Attribute |= MemoryAttribute.Borrowed; + + InsertBlock(Position, PagesCount, State, Permission, Attribute); + + return 0; + } + } + + return MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); + } + + public long ResetTransferMemory(long Position, long Size) + { + lock (Blocks) + { + if (CheckRange( + Position, + Size, + MemoryState.TransferMemoryAllowed | MemoryState.IsPoolAllocated, + MemoryState.TransferMemoryAllowed | MemoryState.IsPoolAllocated, + MemoryPermission.None, + MemoryPermission.None, + MemoryAttribute.Mask, + MemoryAttribute.Borrowed, + MemoryAttribute.IpcAndDeviceMapped, + out MemoryState State, + out _, + out _)) + { + long PagesCount = Size / PageSize; + + InsertBlock(Position, PagesCount, State, MemoryPermission.ReadAndWrite); + + return 0; + } + } + + return MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); + } + + public long SetProcessMemoryPermission(long Position, long Size, MemoryPermission Permission) + { + lock (Blocks) + { + if (CheckRange( + Position, + Size, + MemoryState.ProcessPermissionChangeAllowed, + MemoryState.ProcessPermissionChangeAllowed, + MemoryPermission.None, + MemoryPermission.None, + MemoryAttribute.Mask, + MemoryAttribute.None, + MemoryAttribute.IpcAndDeviceMapped, + out MemoryState State, + out _, + out _)) + { + if (State == MemoryState.CodeStatic) + { + State = MemoryState.CodeMutable; + } + else if (State == MemoryState.ModCodeStatic) + { + State = MemoryState.ModCodeMutable; + } + else + { + throw new InvalidOperationException(); + } + + long PagesCount = Size / PageSize; + + InsertBlock(Position, PagesCount, State, Permission); + + return 0; + } + } + + return MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); + } + + public long MapPhysicalMemory(long Position, long Size) + { + long End = Position + Size; + + lock (Blocks) + { + long MappedSize = 0; + + KMemoryInfo Info; + + LinkedListNode BaseNode = FindBlockNode(Position); + + LinkedListNode Node = BaseNode; + + do + { + Info = Node.Value.GetInfo(); + + if (Info.State != MemoryState.Unmapped) + { + MappedSize += GetSizeInRange(Info, Position, End); + } + + Node = Node.Next; + } + while ((ulong)(Info.Position + Info.Size) < (ulong)End && Node != null); + + if (MappedSize == Size) + { + return 0; + } + + long RemainingSize = Size - MappedSize; + + if (!Allocator.TryAllocate(RemainingSize, out long PA)) + { + return MakeError(ErrorModule.Kernel, KernelErr.OutOfMemory); + } + + Node = BaseNode; + + do + { + Info = Node.Value.GetInfo(); + + if (Info.State == MemoryState.Unmapped) + { + long CurrSize = GetSizeInRange(Info, Position, End); + + CpuMemory.Map(Info.Position, PA, CurrSize); + + PA += CurrSize; + } + + Node = Node.Next; + } + while ((ulong)(Info.Position + Info.Size) < (ulong)End && Node != null); + + PersonalMmHeapUsage += RemainingSize; + + long PagesCount = Size / PageSize; + + InsertBlock( + Position, + PagesCount, + MemoryState.Unmapped, + MemoryPermission.None, + MemoryAttribute.None, + MemoryState.Heap, + MemoryPermission.ReadAndWrite, + MemoryAttribute.None); + } + + return 0; + } + + public long UnmapPhysicalMemory(long Position, long Size) + { + long End = Position + Size; + + lock (Blocks) + { + long HeapMappedSize = 0; + + long CurrPosition = Position; + + KMemoryInfo Info; + + LinkedListNode Node = FindBlockNode(CurrPosition); + + do + { + Info = Node.Value.GetInfo(); + + if (Info.State == MemoryState.Heap) + { + if (Info.Attribute != MemoryAttribute.None) + { + return MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); + } + + HeapMappedSize += GetSizeInRange(Info, Position, End); + } + else if (Info.State != MemoryState.Unmapped) + { + return MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); + } + + Node = Node.Next; + } + while ((ulong)(Info.Position + Info.Size) < (ulong)End && Node != null); + + if (HeapMappedSize == 0) + { + return 0; + } + + PersonalMmHeapUsage -= HeapMappedSize; + + long PagesCount = Size / PageSize; + + InsertBlock(Position, PagesCount, MemoryState.Unmapped); + + CpuMemory.Unmap(Position, Size); + + FreePages(Position, PagesCount); + + return 0; + } + } + + private long GetSizeInRange(KMemoryInfo Info, long Start, long End) + { + long CurrEnd = Info.Size + Info.Position; + long CurrSize = Info.Size; + + if ((ulong)Info.Position < (ulong)Start) + { + CurrSize -= Start - Info.Position; + } + + if ((ulong)CurrEnd > (ulong)End) + { + CurrSize -= CurrEnd - End; + } + + return CurrSize; + } + + private void FreePages(long Position, long PagesCount) + { + for (long Page = 0; Page < PagesCount; Page++) + { + long VA = Position + Page * PageSize; + + long PA = CpuMemory.GetPhysicalAddress(VA); + + Allocator.Free(PA, PageSize); + } + } + + private bool IsUnmapped(long Position, long Size) + { + return CheckRange( + Position, + Size, + MemoryState.Mask, + MemoryState.Unmapped, + MemoryPermission.Mask, + MemoryPermission.None, + MemoryAttribute.Mask, + MemoryAttribute.None, + MemoryAttribute.IpcAndDeviceMapped, + out _, + out _, + out _); + } + + private bool CheckRange( + long Position, + long Size, + MemoryState StateMask, + MemoryState StateExpected, + MemoryPermission PermissionMask, + MemoryPermission PermissionExpected, + MemoryAttribute AttributeMask, + MemoryAttribute AttributeExpected, + MemoryAttribute AttributeIgnoreMask, + out MemoryState OutState, + out MemoryPermission OutPermission, + out MemoryAttribute OutAttribute) + { + KMemoryInfo BlkInfo = FindBlock(Position).GetInfo(); + + ulong Start = (ulong)Position; + ulong End = (ulong)Size + Start; + + if (End <= (ulong)(BlkInfo.Position + BlkInfo.Size)) + { + if ((BlkInfo.Attribute & AttributeMask) == AttributeExpected && + (BlkInfo.State & StateMask) == StateExpected && + (BlkInfo.Permission & PermissionMask) == PermissionExpected) + { + OutState = BlkInfo.State; + OutPermission = BlkInfo.Permission; + OutAttribute = BlkInfo.Attribute & ~AttributeIgnoreMask; + + return true; + } + } + + OutState = MemoryState.Unmapped; + OutPermission = MemoryPermission.None; + OutAttribute = MemoryAttribute.None; + + return false; + } + + private void InsertBlock( + long BasePosition, + long PagesCount, + MemoryState OldState, + MemoryPermission OldPermission, + MemoryAttribute OldAttribute, + MemoryState NewState, + MemoryPermission NewPermission, + MemoryAttribute NewAttribute) + { + //Insert new block on the list only on areas where the state + //of the block matches the state specified on the Old* state + //arguments, otherwise leave it as is. + OldAttribute |= MemoryAttribute.IpcAndDeviceMapped; + + ulong Start = (ulong)BasePosition; + ulong End = (ulong)PagesCount * PageSize + Start; + + LinkedListNode Node = Blocks.First; + + while (Node != null) + { + LinkedListNode NewNode = Node; + LinkedListNode NextNode = Node.Next; + + KMemoryBlock CurrBlock = Node.Value; + + ulong CurrStart = (ulong)CurrBlock.BasePosition; + ulong CurrEnd = (ulong)CurrBlock.PagesCount * PageSize + CurrStart; + + if (Start < CurrEnd && CurrStart < End) + { + MemoryAttribute CurrBlockAttr = CurrBlock.Attribute | MemoryAttribute.IpcAndDeviceMapped; + + if (CurrBlock.State != OldState || + CurrBlock.Permission != OldPermission || + CurrBlockAttr != OldAttribute) + { + Node = NextNode; + + continue; + } + + if (CurrStart >= Start && CurrEnd <= End) + { + CurrBlock.State = NewState; + CurrBlock.Permission = NewPermission; + CurrBlock.Attribute &= ~MemoryAttribute.IpcAndDeviceMapped; + CurrBlock.Attribute |= NewAttribute; + } + else if (CurrStart >= Start) + { + CurrBlock.BasePosition = (long)End; + + CurrBlock.PagesCount = (long)((CurrEnd - End) / PageSize); + + long NewPagesCount = (long)((End - CurrStart) / PageSize); + + NewNode = Blocks.AddBefore(Node, new KMemoryBlock( + (long)CurrStart, + NewPagesCount, + NewState, + NewPermission, + NewAttribute)); + } + else if (CurrEnd <= End) + { + CurrBlock.PagesCount = (long)((Start - CurrStart) / PageSize); + + long NewPagesCount = (long)((CurrEnd - Start) / PageSize); + + NewNode = Blocks.AddAfter(Node, new KMemoryBlock( + BasePosition, + NewPagesCount, + NewState, + NewPermission, + NewAttribute)); + } + else + { + CurrBlock.PagesCount = (long)((Start - CurrStart) / PageSize); + + long NextPagesCount = (long)((CurrEnd - End) / PageSize); + + NewNode = Blocks.AddAfter(Node, new KMemoryBlock( + BasePosition, + PagesCount, + NewState, + NewPermission, + NewAttribute)); + + Blocks.AddAfter(NewNode, new KMemoryBlock( + (long)End, + NextPagesCount, + CurrBlock.State, + CurrBlock.Permission, + CurrBlock.Attribute)); + + NextNode = null; + } + + MergeEqualStateNeighbours(NewNode); + } + + Node = NextNode; + } + } + + private void InsertBlock( + long BasePosition, + long PagesCount, + MemoryState State, + MemoryPermission Permission = MemoryPermission.None, + MemoryAttribute Attribute = MemoryAttribute.None) + { + //Inserts new block at the list, replacing and spliting + //existing blocks as needed. + KMemoryBlock Block = new KMemoryBlock(BasePosition, PagesCount, State, Permission, Attribute); + + ulong Start = (ulong)BasePosition; + ulong End = (ulong)PagesCount * PageSize + Start; + + LinkedListNode NewNode = null; + + LinkedListNode Node = Blocks.First; + + while (Node != null) + { + KMemoryBlock CurrBlock = Node.Value; + + LinkedListNode NextNode = Node.Next; + + ulong CurrStart = (ulong)CurrBlock.BasePosition; + ulong CurrEnd = (ulong)CurrBlock.PagesCount * PageSize + CurrStart; + + if (Start < CurrEnd && CurrStart < End) + { + if (Start >= CurrStart && End <= CurrEnd) + { + Block.Attribute |= CurrBlock.Attribute & MemoryAttribute.IpcAndDeviceMapped; + } + + if (Start > CurrStart && End < CurrEnd) + { + CurrBlock.PagesCount = (long)((Start - CurrStart) / PageSize); + + long NextPagesCount = (long)((CurrEnd - End) / PageSize); + + NewNode = Blocks.AddAfter(Node, Block); + + Blocks.AddAfter(NewNode, new KMemoryBlock( + (long)End, + NextPagesCount, + CurrBlock.State, + CurrBlock.Permission, + CurrBlock.Attribute)); + + break; + } + else if (Start <= CurrStart && End < CurrEnd) + { + CurrBlock.BasePosition = (long)End; + + CurrBlock.PagesCount = (long)((CurrEnd - End) / PageSize); + + if (NewNode == null) + { + NewNode = Blocks.AddBefore(Node, Block); + } + } + else if (Start > CurrStart && End >= CurrEnd) + { + CurrBlock.PagesCount = (long)((Start - CurrStart) / PageSize); + + if (NewNode == null) + { + NewNode = Blocks.AddAfter(Node, Block); + } + } + else + { + if (NewNode == null) + { + NewNode = Blocks.AddBefore(Node, Block); + } + + Blocks.Remove(Node); + } + } + + Node = NextNode; + } + + if (NewNode == null) + { + NewNode = Blocks.AddFirst(Block); + } + + MergeEqualStateNeighbours(NewNode); + } + + private void MergeEqualStateNeighbours(LinkedListNode Node) + { + KMemoryBlock Block = Node.Value; + + ulong Start = (ulong)Block.BasePosition; + ulong End = (ulong)Block.PagesCount * PageSize + Start; + + if (Node.Previous != null) + { + KMemoryBlock Previous = Node.Previous.Value; + + if (BlockStateEquals(Block, Previous)) + { + Blocks.Remove(Node.Previous); + + Block.BasePosition = Previous.BasePosition; + + Start = (ulong)Block.BasePosition; + } + } + + if (Node.Next != null) + { + KMemoryBlock Next = Node.Next.Value; + + if (BlockStateEquals(Block, Next)) + { + Blocks.Remove(Node.Next); + + End = (ulong)(Next.BasePosition + Next.PagesCount * PageSize); + } + } + + Block.PagesCount = (long)((End - Start) / PageSize); + } + + private static bool BlockStateEquals(KMemoryBlock LHS, KMemoryBlock RHS) + { + return LHS.State == RHS.State && + LHS.Permission == RHS.Permission && + LHS.Attribute == RHS.Attribute && + LHS.DeviceRefCount == RHS.DeviceRefCount && + LHS.IpcRefCount == RHS.IpcRefCount; + } + + private KMemoryBlock FindBlock(long Position) + { + return FindBlockNode(Position)?.Value; + } + + private LinkedListNode FindBlockNode(long Position) + { + ulong Addr = (ulong)Position; + + lock (Blocks) + { + LinkedListNode Node = Blocks.First; + + while (Node != null) + { + KMemoryBlock Block = Node.Value; + + ulong Start = (ulong)Block.BasePosition; + ulong End = (ulong)Block.PagesCount * PageSize + Start; + + if (Start <= Addr && End - 1 >= Addr) + { + return Node; + } + + Node = Node.Next; + } + } + + return null; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Kernel/KProcessHandleTable.cs b/Ryujinx.HLE/HOS/Kernel/KProcessHandleTable.cs new file mode 100644 index 00000000..db0eaa44 --- /dev/null +++ b/Ryujinx.HLE/HOS/Kernel/KProcessHandleTable.cs @@ -0,0 +1,34 @@ +using System.Collections.Generic; + +namespace Ryujinx.HLE.HOS.Kernel +{ + class KProcessHandleTable + { + private IdDictionary Handles; + + public KProcessHandleTable() + { + Handles = new IdDictionary(); + } + + public int OpenHandle(object Obj) + { + return Handles.Add(Obj); + } + + public T GetData(int Handle) + { + return Handles.GetData(Handle); + } + + public object CloseHandle(int Handle) + { + return Handles.Delete(Handle); + } + + public ICollection Clear() + { + return Handles.Clear(); + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Kernel/KProcessScheduler.cs b/Ryujinx.HLE/HOS/Kernel/KProcessScheduler.cs new file mode 100644 index 00000000..2120f16c --- /dev/null +++ b/Ryujinx.HLE/HOS/Kernel/KProcessScheduler.cs @@ -0,0 +1,370 @@ +using Ryujinx.HLE.Logging; +using System; +using System.Collections.Concurrent; +using System.Threading; + +namespace Ryujinx.HLE.HOS.Kernel +{ + class KProcessScheduler : IDisposable + { + private ConcurrentDictionary AllThreads; + + private ThreadQueue WaitingToRun; + + private KThread[] CoreThreads; + + private bool[] CoreReschedule; + + private object SchedLock; + + private Logger Log; + + public KProcessScheduler(Logger Log) + { + this.Log = Log; + + AllThreads = new ConcurrentDictionary(); + + WaitingToRun = new ThreadQueue(); + + CoreThreads = new KThread[4]; + + CoreReschedule = new bool[4]; + + SchedLock = new object(); + } + + public void StartThread(KThread Thread) + { + lock (SchedLock) + { + SchedulerThread SchedThread = new SchedulerThread(Thread); + + if (!AllThreads.TryAdd(Thread, SchedThread)) + { + return; + } + + if (TryAddToCore(Thread)) + { + Thread.Thread.Execute(); + + PrintDbgThreadInfo(Thread, "running."); + } + else + { + WaitingToRun.Push(SchedThread); + + PrintDbgThreadInfo(Thread, "waiting to run."); + } + } + } + + public void RemoveThread(KThread Thread) + { + PrintDbgThreadInfo(Thread, "exited."); + + lock (SchedLock) + { + if (AllThreads.TryRemove(Thread, out SchedulerThread SchedThread)) + { + WaitingToRun.Remove(SchedThread); + + SchedThread.Dispose(); + } + + int ActualCore = Thread.ActualCore; + + SchedulerThread NewThread = WaitingToRun.Pop(ActualCore); + + if (NewThread == null) + { + Log.PrintDebug(LogClass.KernelScheduler, $"Nothing to run on core {ActualCore}!"); + + CoreThreads[ActualCore] = null; + + return; + } + + NewThread.Thread.ActualCore = ActualCore; + + RunThread(NewThread); + } + } + + public void SetThreadActivity(KThread Thread, bool Active) + { + SchedulerThread SchedThread = AllThreads[Thread]; + + SchedThread.IsActive = Active; + + if (Active) + { + SchedThread.WaitActivity.Set(); + } + else + { + SchedThread.WaitActivity.Reset(); + } + } + + public void EnterWait(KThread Thread, int TimeoutMs = Timeout.Infinite) + { + SchedulerThread SchedThread = AllThreads[Thread]; + + Suspend(Thread); + + SchedThread.WaitSync.WaitOne(TimeoutMs); + + TryResumingExecution(SchedThread); + } + + public void WakeUp(KThread Thread) + { + AllThreads[Thread].WaitSync.Set(); + } + + public void ForceWakeUp(KThread Thread) + { + if (AllThreads.TryGetValue(Thread, out SchedulerThread SchedThread)) + { + SchedThread.WaitSync.Set(); + SchedThread.WaitActivity.Set(); + SchedThread.WaitSched.Set(); + } + } + + public void ChangeCore(KThread Thread, int IdealCore, int CoreMask) + { + lock (SchedLock) + { + if (IdealCore != -3) + { + Thread.IdealCore = IdealCore; + } + + Thread.CoreMask = CoreMask; + + if (AllThreads.ContainsKey(Thread)) + { + SetReschedule(Thread.ActualCore); + + SchedulerThread SchedThread = AllThreads[Thread]; + + //Note: Aways if the thread is on the queue first, and try + //adding to a new core later, to ensure that a thread that + //is already running won't be added to another core. + if (WaitingToRun.HasThread(SchedThread) && TryAddToCore(Thread)) + { + WaitingToRun.Remove(SchedThread); + + RunThread(SchedThread); + } + } + } + } + + public void Suspend(KThread Thread) + { + lock (SchedLock) + { + PrintDbgThreadInfo(Thread, "suspended."); + + int ActualCore = Thread.ActualCore; + + CoreReschedule[ActualCore] = false; + + SchedulerThread SchedThread = WaitingToRun.Pop(ActualCore); + + if (SchedThread != null) + { + SchedThread.Thread.ActualCore = ActualCore; + + CoreThreads[ActualCore] = SchedThread.Thread; + + RunThread(SchedThread); + } + else + { + Log.PrintDebug(LogClass.KernelScheduler, $"Nothing to run on core {Thread.ActualCore}!"); + + CoreThreads[ActualCore] = null; + } + } + } + + public void SetReschedule(int Core) + { + lock (SchedLock) + { + CoreReschedule[Core] = true; + } + } + + public void Reschedule(KThread Thread) + { + bool NeedsReschedule; + + lock (SchedLock) + { + int ActualCore = Thread.ActualCore; + + NeedsReschedule = CoreReschedule[ActualCore]; + + CoreReschedule[ActualCore] = false; + } + + if (NeedsReschedule) + { + Yield(Thread, Thread.ActualPriority - 1); + } + } + + public void Yield(KThread Thread) + { + Yield(Thread, Thread.ActualPriority); + } + + private void Yield(KThread Thread, int MinPriority) + { + PrintDbgThreadInfo(Thread, "yielded execution."); + + lock (SchedLock) + { + int ActualCore = Thread.ActualCore; + + SchedulerThread NewThread = WaitingToRun.Pop(ActualCore, MinPriority); + + if (NewThread != null) + { + NewThread.Thread.ActualCore = ActualCore; + + CoreThreads[ActualCore] = NewThread.Thread; + + RunThread(NewThread); + } + else + { + CoreThreads[ActualCore] = null; + } + } + + Resume(Thread); + } + + public void Resume(KThread Thread) + { + TryResumingExecution(AllThreads[Thread]); + } + + private void TryResumingExecution(SchedulerThread SchedThread) + { + KThread Thread = SchedThread.Thread; + + PrintDbgThreadInfo(Thread, "trying to resume..."); + + SchedThread.WaitActivity.WaitOne(); + + lock (SchedLock) + { + if (TryAddToCore(Thread)) + { + PrintDbgThreadInfo(Thread, "resuming execution..."); + + return; + } + + WaitingToRun.Push(SchedThread); + + SetReschedule(Thread.ProcessorId); + + PrintDbgThreadInfo(Thread, "entering wait state..."); + } + + SchedThread.WaitSched.WaitOne(); + + PrintDbgThreadInfo(Thread, "resuming execution..."); + } + + private void RunThread(SchedulerThread SchedThread) + { + if (!SchedThread.Thread.Thread.Execute()) + { + PrintDbgThreadInfo(SchedThread.Thread, "waked."); + + SchedThread.WaitSched.Set(); + } + else + { + PrintDbgThreadInfo(SchedThread.Thread, "running."); + } + } + + public void Resort(KThread Thread) + { + if (AllThreads.TryGetValue(Thread, out SchedulerThread SchedThread)) + { + WaitingToRun.Resort(SchedThread); + } + } + + private bool TryAddToCore(KThread Thread) + { + //First, try running it on Ideal Core. + int IdealCore = Thread.IdealCore; + + if (IdealCore != -1 && CoreThreads[IdealCore] == null) + { + Thread.ActualCore = IdealCore; + + CoreThreads[IdealCore] = Thread; + + return true; + } + + //If that fails, then try running on any core allowed by Core Mask. + int CoreMask = Thread.CoreMask; + + for (int Core = 0; Core < CoreThreads.Length; Core++, CoreMask >>= 1) + { + if ((CoreMask & 1) != 0 && CoreThreads[Core] == null) + { + Thread.ActualCore = Core; + + CoreThreads[Core] = Thread; + + return true; + } + } + + return false; + } + + private void PrintDbgThreadInfo(KThread Thread, string Message) + { + Log.PrintDebug(LogClass.KernelScheduler, "(" + + "ThreadId = " + Thread.ThreadId + ", " + + "CoreMask = 0x" + Thread.CoreMask.ToString("x1") + ", " + + "ActualCore = " + Thread.ActualCore + ", " + + "IdealCore = " + Thread.IdealCore + ", " + + "ActualPriority = " + Thread.ActualPriority + ", " + + "WantedPriority = " + Thread.WantedPriority + ") " + Message); + } + + public void Dispose() + { + Dispose(true); + } + + protected virtual void Dispose(bool Disposing) + { + if (Disposing) + { + foreach (SchedulerThread SchedThread in AllThreads.Values) + { + SchedThread.Dispose(); + } + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Kernel/KSession.cs b/Ryujinx.HLE/HOS/Kernel/KSession.cs new file mode 100644 index 00000000..4b21d3a6 --- /dev/null +++ b/Ryujinx.HLE/HOS/Kernel/KSession.cs @@ -0,0 +1,31 @@ +using Ryujinx.HLE.HOS.Services; +using System; + +namespace Ryujinx.HLE.HOS.Kernel +{ + class KSession : IDisposable + { + public IpcService Service { get; private set; } + + public string ServiceName { get; private set; } + + public KSession(IpcService Service, string ServiceName) + { + this.Service = Service; + this.ServiceName = ServiceName; + } + + public void Dispose() + { + Dispose(true); + } + + protected virtual void Dispose(bool Disposing) + { + if (Disposing && Service is IDisposable DisposableService) + { + DisposableService.Dispose(); + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Kernel/KSharedMemory.cs b/Ryujinx.HLE/HOS/Kernel/KSharedMemory.cs new file mode 100644 index 00000000..cdd31667 --- /dev/null +++ b/Ryujinx.HLE/HOS/Kernel/KSharedMemory.cs @@ -0,0 +1,14 @@ +namespace Ryujinx.HLE.HOS.Kernel +{ + class KSharedMemory + { + public long PA { get; private set; } + public long Size { get; private set; } + + public KSharedMemory(long PA, long Size) + { + this.PA = PA; + this.Size = Size; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Kernel/KSynchronizationObject.cs b/Ryujinx.HLE/HOS/Kernel/KSynchronizationObject.cs new file mode 100644 index 00000000..b83b0004 --- /dev/null +++ b/Ryujinx.HLE/HOS/Kernel/KSynchronizationObject.cs @@ -0,0 +1,28 @@ +using System; +using System.Threading; + +namespace Ryujinx.HLE.HOS.Kernel +{ + class KSynchronizationObject : IDisposable + { + public ManualResetEvent WaitEvent { get; private set; } + + public KSynchronizationObject() + { + WaitEvent = new ManualResetEvent(false); + } + + public void Dispose() + { + Dispose(true); + } + + protected virtual void Dispose(bool Disposing) + { + if (Disposing) + { + WaitEvent.Dispose(); + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Kernel/KThread.cs b/Ryujinx.HLE/HOS/Kernel/KThread.cs new file mode 100644 index 00000000..171fefc5 --- /dev/null +++ b/Ryujinx.HLE/HOS/Kernel/KThread.cs @@ -0,0 +1,98 @@ +using ChocolArm64; +using System.Collections.Generic; + +namespace Ryujinx.HLE.HOS.Kernel +{ + class KThread : KSynchronizationObject + { + public AThread Thread { get; private set; } + + public int CoreMask { get; set; } + + public long MutexAddress { get; set; } + public long CondVarAddress { get; set; } + public long ArbiterWaitAddress { get; set; } + + public bool CondVarSignaled { get; set; } + public bool ArbiterSignaled { get; set; } + + private Process Process; + + public List MutexWaiters { get; private set; } + + public KThread MutexOwner { get; set; } + + public int ActualPriority { get; private set; } + public int WantedPriority { get; private set; } + + public int ActualCore { get; set; } + public int ProcessorId { get; set; } + public int IdealCore { get; set; } + + public int WaitHandle { get; set; } + + public long LastPc { get; set; } + + public int ThreadId { get; private set; } + + public KThread( + AThread Thread, + Process Process, + int ProcessorId, + int Priority, + int ThreadId) + { + this.Thread = Thread; + this.Process = Process; + this.ProcessorId = ProcessorId; + this.IdealCore = ProcessorId; + this.ThreadId = ThreadId; + + MutexWaiters = new List(); + + CoreMask = 1 << ProcessorId; + + ActualPriority = WantedPriority = Priority; + } + + public void SetPriority(int Priority) + { + WantedPriority = Priority; + + UpdatePriority(); + } + + public void UpdatePriority() + { + bool PriorityChanged; + + lock (Process.ThreadSyncLock) + { + int OldPriority = ActualPriority; + + int CurrPriority = WantedPriority; + + foreach (KThread Thread in MutexWaiters) + { + int WantedPriority = Thread.WantedPriority; + + if (CurrPriority > WantedPriority) + { + CurrPriority = WantedPriority; + } + } + + PriorityChanged = CurrPriority != OldPriority; + + ActualPriority = CurrPriority; + } + + if (PriorityChanged) + { + Process.Scheduler.Resort(this); + + MutexOwner?.UpdatePriority(); + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Kernel/KTlsPageManager.cs b/Ryujinx.HLE/HOS/Kernel/KTlsPageManager.cs new file mode 100644 index 00000000..1fb2ce6a --- /dev/null +++ b/Ryujinx.HLE/HOS/Kernel/KTlsPageManager.cs @@ -0,0 +1,60 @@ +using System; + +namespace Ryujinx.HLE.HOS.Kernel +{ + class KTlsPageManager + { + private const int TlsEntrySize = 0x200; + + private long PagePosition; + + private int UsedSlots; + + private bool[] Slots; + + public bool IsEmpty => UsedSlots == 0; + public bool IsFull => UsedSlots == Slots.Length; + + public KTlsPageManager(long PagePosition) + { + this.PagePosition = PagePosition; + + Slots = new bool[KMemoryManager.PageSize / TlsEntrySize]; + } + + public bool TryGetFreeTlsAddr(out long Position) + { + Position = PagePosition; + + for (int Index = 0; Index < Slots.Length; Index++) + { + if (!Slots[Index]) + { + Slots[Index] = true; + + UsedSlots++; + + return true; + } + + Position += TlsEntrySize; + } + + Position = 0; + + return false; + } + + public void FreeTlsSlot(int Slot) + { + if ((uint)Slot > Slots.Length) + { + throw new ArgumentOutOfRangeException(nameof(Slot)); + } + + Slots[Slot] = false; + + UsedSlots--; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Kernel/KTransferMemory.cs b/Ryujinx.HLE/HOS/Kernel/KTransferMemory.cs new file mode 100644 index 00000000..6ebffa7e --- /dev/null +++ b/Ryujinx.HLE/HOS/Kernel/KTransferMemory.cs @@ -0,0 +1,14 @@ +namespace Ryujinx.HLE.HOS.Kernel +{ + class KTransferMemory + { + public long Position { get; private set; } + public long Size { get; private set; } + + public KTransferMemory(long Position, long Size) + { + this.Position = Position; + this.Size = Size; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Kernel/KernelErr.cs b/Ryujinx.HLE/HOS/Kernel/KernelErr.cs new file mode 100644 index 00000000..e76ae11e --- /dev/null +++ b/Ryujinx.HLE/HOS/Kernel/KernelErr.cs @@ -0,0 +1,22 @@ +namespace Ryujinx.HLE.HOS.Kernel +{ + static class KernelErr + { + public const int InvalidSize = 101; + public const int InvalidAddress = 102; + public const int OutOfMemory = 104; + public const int NoAccessPerm = 106; + public const int InvalidPermission = 108; + public const int InvalidMemRange = 110; + public const int InvalidPriority = 112; + public const int InvalidCoreId = 113; + public const int InvalidHandle = 114; + public const int InvalidMaskValue = 116; + public const int Timeout = 117; + public const int Canceled = 118; + public const int CountOutOfRange = 119; + public const int InvalidEnumValue = 120; + public const int InvalidThread = 122; + public const int InvalidState = 125; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Kernel/MemoryAttribute.cs b/Ryujinx.HLE/HOS/Kernel/MemoryAttribute.cs new file mode 100644 index 00000000..8f3197cb --- /dev/null +++ b/Ryujinx.HLE/HOS/Kernel/MemoryAttribute.cs @@ -0,0 +1,22 @@ +using System; + +namespace Ryujinx.HLE.HOS.Kernel +{ + [Flags] + enum MemoryAttribute : byte + { + None = 0, + Mask = 0xff, + + Borrowed = 1 << 0, + IpcMapped = 1 << 1, + DeviceMapped = 1 << 2, + Uncached = 1 << 3, + + IpcAndDeviceMapped = IpcMapped | DeviceMapped, + + BorrowedAndIpcMapped = Borrowed | IpcMapped, + + DeviceMappedAndUncached = DeviceMapped | Uncached + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Kernel/MemoryPermission.cs b/Ryujinx.HLE/HOS/Kernel/MemoryPermission.cs new file mode 100644 index 00000000..63539c2e --- /dev/null +++ b/Ryujinx.HLE/HOS/Kernel/MemoryPermission.cs @@ -0,0 +1,18 @@ +using System; + +namespace Ryujinx.HLE.HOS.Kernel +{ + [Flags] + enum MemoryPermission : byte + { + None = 0, + Mask = 0xff, + + Read = 1 << 0, + Write = 1 << 1, + Execute = 1 << 2, + + ReadAndWrite = Read | Write, + ReadAndExecute = Read | Execute + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Kernel/MemoryState.cs b/Ryujinx.HLE/HOS/Kernel/MemoryState.cs new file mode 100644 index 00000000..2c37723c --- /dev/null +++ b/Ryujinx.HLE/HOS/Kernel/MemoryState.cs @@ -0,0 +1,49 @@ +using System; + +namespace Ryujinx.HLE.HOS.Kernel +{ + [Flags] + enum MemoryState : uint + { + Unmapped = 0x00000000, + Io = 0x00002001, + Normal = 0x00042002, + CodeStatic = 0x00DC7E03, + CodeMutable = 0x03FEBD04, + Heap = 0x037EBD05, + SharedMemory = 0x00402006, + ModCodeStatic = 0x00DD7E08, + ModCodeMutable = 0x03FFBD09, + IpcBuffer0 = 0x005C3C0A, + MappedMemory = 0x005C3C0B, + ThreadLocal = 0x0040200C, + TransferMemoryIsolated = 0x015C3C0D, + TransferMemory = 0x005C380E, + ProcessMemory = 0x0040380F, + Reserved = 0x00000010, + IpcBuffer1 = 0x005C3811, + IpcBuffer3 = 0x004C2812, + KernelStack = 0x00002013, + CodeReadOnly = 0x00402214, + CodeWritable = 0x00402015, + Mask = 0xffffffff, + + PermissionChangeAllowed = 1 << 8, + ForceReadWritableByDebugSyscalls = 1 << 9, + IpcSendAllowedType0 = 1 << 10, + IpcSendAllowedType3 = 1 << 11, + IpcSendAllowedType1 = 1 << 12, + ProcessPermissionChangeAllowed = 1 << 14, + MapAllowed = 1 << 15, + UnmapProcessCodeMemoryAllowed = 1 << 16, + TransferMemoryAllowed = 1 << 17, + QueryPhysicalAddressAllowed = 1 << 18, + MapDeviceAllowed = 1 << 19, + MapDeviceAlignedAllowed = 1 << 20, + IpcBufferAllowed = 1 << 21, + IsPoolAllocated = 1 << 22, + MapProcessAllowed = 1 << 23, + AttributeChangeAllowed = 1 << 24, + CodeMemoryAllowed = 1 << 25 + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Kernel/NsTimeConverter.cs b/Ryujinx.HLE/HOS/Kernel/NsTimeConverter.cs new file mode 100644 index 00000000..b8008f75 --- /dev/null +++ b/Ryujinx.HLE/HOS/Kernel/NsTimeConverter.cs @@ -0,0 +1,19 @@ +namespace Ryujinx.HLE.HOS.Kernel +{ + static class NsTimeConverter + { + public static int GetTimeMs(ulong Ns) + { + ulong Ms = Ns / 1_000_000; + + if (Ms < int.MaxValue) + { + return (int)Ms; + } + else + { + return int.MaxValue; + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Kernel/SchedulerThread.cs b/Ryujinx.HLE/HOS/Kernel/SchedulerThread.cs new file mode 100644 index 00000000..bab7b03e --- /dev/null +++ b/Ryujinx.HLE/HOS/Kernel/SchedulerThread.cs @@ -0,0 +1,48 @@ +using System; +using System.Threading; + +namespace Ryujinx.HLE.HOS.Kernel +{ + class SchedulerThread : IDisposable + { + public KThread Thread { get; private set; } + + public SchedulerThread Next { get; set; } + + public bool IsActive { get; set; } + + public AutoResetEvent WaitSync { get; private set; } + public ManualResetEvent WaitActivity { get; private set; } + public AutoResetEvent WaitSched { get; private set; } + + public SchedulerThread(KThread Thread) + { + this.Thread = Thread; + + IsActive = true; + + WaitSync = new AutoResetEvent(false); + + WaitActivity = new ManualResetEvent(true); + + WaitSched = new AutoResetEvent(false); + } + + public void Dispose() + { + Dispose(true); + } + + protected virtual void Dispose(bool Disposing) + { + if (Disposing) + { + WaitSync.Dispose(); + + WaitActivity.Dispose(); + + WaitSched.Dispose(); + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Kernel/SvcHandler.cs b/Ryujinx.HLE/HOS/Kernel/SvcHandler.cs new file mode 100644 index 00000000..fcb72c14 --- /dev/null +++ b/Ryujinx.HLE/HOS/Kernel/SvcHandler.cs @@ -0,0 +1,123 @@ +using ChocolArm64.Events; +using ChocolArm64.Memory; +using ChocolArm64.State; +using Ryujinx.HLE.Logging; +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Threading; + +namespace Ryujinx.HLE.HOS.Kernel +{ + partial class SvcHandler + { + private delegate void SvcFunc(AThreadState ThreadState); + + private Dictionary SvcFuncs; + + private Switch Device; + private Process Process; + private AMemory Memory; + + private ConcurrentDictionary SyncWaits; + + private const uint SelfThreadHandle = 0xffff8000; + private const uint SelfProcessHandle = 0xffff8001; + + private static Random Rng; + + public SvcHandler(Switch Device, Process Process) + { + SvcFuncs = new Dictionary() + { + { 0x01, SvcSetHeapSize }, + { 0x03, SvcSetMemoryAttribute }, + { 0x04, SvcMapMemory }, + { 0x05, SvcUnmapMemory }, + { 0x06, SvcQueryMemory }, + { 0x07, SvcExitProcess }, + { 0x08, SvcCreateThread }, + { 0x09, SvcStartThread }, + { 0x0a, SvcExitThread }, + { 0x0b, SvcSleepThread }, + { 0x0c, SvcGetThreadPriority }, + { 0x0d, SvcSetThreadPriority }, + { 0x0e, SvcGetThreadCoreMask }, + { 0x0f, SvcSetThreadCoreMask }, + { 0x10, SvcGetCurrentProcessorNumber }, + { 0x12, SvcClearEvent }, + { 0x13, SvcMapSharedMemory }, + { 0x14, SvcUnmapSharedMemory }, + { 0x15, SvcCreateTransferMemory }, + { 0x16, SvcCloseHandle }, + { 0x17, SvcResetSignal }, + { 0x18, SvcWaitSynchronization }, + { 0x19, SvcCancelSynchronization }, + { 0x1a, SvcArbitrateLock }, + { 0x1b, SvcArbitrateUnlock }, + { 0x1c, SvcWaitProcessWideKeyAtomic }, + { 0x1d, SvcSignalProcessWideKey }, + { 0x1e, SvcGetSystemTick }, + { 0x1f, SvcConnectToNamedPort }, + { 0x21, SvcSendSyncRequest }, + { 0x22, SvcSendSyncRequestWithUserBuffer }, + { 0x25, SvcGetThreadId }, + { 0x26, SvcBreak }, + { 0x27, SvcOutputDebugString }, + { 0x29, SvcGetInfo }, + { 0x2c, SvcMapPhysicalMemory }, + { 0x2d, SvcUnmapPhysicalMemory }, + { 0x32, SvcSetThreadActivity }, + { 0x33, SvcGetThreadContext3 }, + { 0x34, SvcWaitForAddress } + }; + + this.Device = Device; + this.Process = Process; + this.Memory = Process.Memory; + + SyncWaits = new ConcurrentDictionary(); + } + + static SvcHandler() + { + Rng = new Random(); + } + + public void SvcCall(object sender, AInstExceptionEventArgs e) + { + AThreadState ThreadState = (AThreadState)sender; + + Process.GetThread(ThreadState.Tpidr).LastPc = e.Position; + + if (SvcFuncs.TryGetValue(e.Id, out SvcFunc Func)) + { + Device.Log.PrintDebug(LogClass.KernelSvc, $"{Func.Method.Name} called."); + + Func(ThreadState); + + Process.Scheduler.Reschedule(Process.GetThread(ThreadState.Tpidr)); + + Device.Log.PrintDebug(LogClass.KernelSvc, $"{Func.Method.Name} ended."); + } + else + { + Process.PrintStackTrace(ThreadState); + + throw new NotImplementedException($"0x{e.Id:x4}"); + } + } + + private KThread GetThread(long Tpidr, int Handle) + { + if ((uint)Handle == SelfThreadHandle) + { + return Process.GetThread(Tpidr); + } + else + { + return Process.HandleTable.GetData(Handle); + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Kernel/SvcMemory.cs b/Ryujinx.HLE/HOS/Kernel/SvcMemory.cs new file mode 100644 index 00000000..b9bca74a --- /dev/null +++ b/Ryujinx.HLE/HOS/Kernel/SvcMemory.cs @@ -0,0 +1,577 @@ +using ChocolArm64.State; +using Ryujinx.HLE.Logging; + +using static Ryujinx.HLE.HOS.ErrorCode; + +namespace Ryujinx.HLE.HOS.Kernel +{ + partial class SvcHandler + { + private void SvcSetHeapSize(AThreadState ThreadState) + { + long Size = (long)ThreadState.X1; + + if ((Size & 0x1fffff) != 0 || Size != (uint)Size) + { + Device.Log.PrintWarning(LogClass.KernelSvc, $"Heap size 0x{Size:x16} is not aligned!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidSize); + + return; + } + + long Result = Process.MemoryManager.TrySetHeapSize(Size, out long Position); + + ThreadState.X0 = (ulong)Result; + + if (Result == 0) + { + ThreadState.X1 = (ulong)Position; + } + else + { + Device.Log.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!"); + } + } + + private void SvcSetMemoryAttribute(AThreadState ThreadState) + { + long Position = (long)ThreadState.X0; + long Size = (long)ThreadState.X1; + + if (!PageAligned(Position)) + { + Device.Log.PrintWarning(LogClass.KernelSvc, $"Address 0x{Position:x16} is not page aligned!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress); + + return; + } + + if (!PageAligned(Size) || Size == 0) + { + Device.Log.PrintWarning(LogClass.KernelSvc, $"Size 0x{Size:x16} is not page aligned or is zero!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidSize); + + return; + } + + MemoryAttribute AttributeMask = (MemoryAttribute)ThreadState.X2; + MemoryAttribute AttributeValue = (MemoryAttribute)ThreadState.X3; + + MemoryAttribute Attributes = AttributeMask | AttributeValue; + + if (Attributes != AttributeMask || + (Attributes | MemoryAttribute.Uncached) != MemoryAttribute.Uncached) + { + Device.Log.PrintWarning(LogClass.KernelSvc, "Invalid memory attributes!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidMaskValue); + + return; + } + + long Result = Process.MemoryManager.SetMemoryAttribute( + Position, + Size, + AttributeMask, + AttributeValue); + + if (Result != 0) + { + Device.Log.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!"); + } + else + { + Memory.StopObservingRegion(Position, Size); + } + + ThreadState.X0 = (ulong)Result; + } + + private void SvcMapMemory(AThreadState ThreadState) + { + long Dst = (long)ThreadState.X0; + long Src = (long)ThreadState.X1; + long Size = (long)ThreadState.X2; + + if (!PageAligned(Src | Dst)) + { + Device.Log.PrintWarning(LogClass.KernelSvc, "Addresses are not page aligned!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress); + + return; + } + + if (!PageAligned(Size) || Size == 0) + { + Device.Log.PrintWarning(LogClass.KernelSvc, $"Size 0x{Size:x16} is not page aligned or is zero!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidSize); + + return; + } + + if ((ulong)(Src + Size) <= (ulong)Src || (ulong)(Dst + Size) <= (ulong)Dst) + { + Device.Log.PrintWarning(LogClass.KernelSvc, "Addresses outside of range!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); + + return; + } + + if (!InsideAddrSpace(Src, Size)) + { + Device.Log.PrintWarning(LogClass.KernelSvc, $"Src address 0x{Src:x16} out of range!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); + + return; + } + + if (!InsideNewMapRegion(Dst, Size)) + { + Device.Log.PrintWarning(LogClass.KernelSvc, $"Dst address 0x{Dst:x16} out of range!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidMemRange); + + return; + } + + long Result = Process.MemoryManager.Map(Src, Dst, Size); + + if (Result != 0) + { + Device.Log.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!"); + } + + ThreadState.X0 = (ulong)Result; + } + + private void SvcUnmapMemory(AThreadState ThreadState) + { + long Dst = (long)ThreadState.X0; + long Src = (long)ThreadState.X1; + long Size = (long)ThreadState.X2; + + if (!PageAligned(Src | Dst)) + { + Device.Log.PrintWarning(LogClass.KernelSvc, "Addresses are not page aligned!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress); + + return; + } + + if (!PageAligned(Size) || Size == 0) + { + Device.Log.PrintWarning(LogClass.KernelSvc, $"Size 0x{Size:x16} is not page aligned or is zero!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidSize); + + return; + } + + if ((ulong)(Src + Size) <= (ulong)Src || (ulong)(Dst + Size) <= (ulong)Dst) + { + Device.Log.PrintWarning(LogClass.KernelSvc, "Addresses outside of range!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); + + return; + } + + if (!InsideAddrSpace(Src, Size)) + { + Device.Log.PrintWarning(LogClass.KernelSvc, $"Src address 0x{Src:x16} out of range!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); + + return; + } + + if (!InsideNewMapRegion(Dst, Size)) + { + Device.Log.PrintWarning(LogClass.KernelSvc, $"Dst address 0x{Dst:x16} out of range!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidMemRange); + + return; + } + + long Result = Process.MemoryManager.Unmap(Src, Dst, Size); + + if (Result != 0) + { + Device.Log.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!"); + } + + ThreadState.X0 = (ulong)Result; + } + + private void SvcQueryMemory(AThreadState ThreadState) + { + long InfoPtr = (long)ThreadState.X0; + long Position = (long)ThreadState.X2; + + KMemoryInfo BlkInfo = Process.MemoryManager.QueryMemory(Position); + + Memory.WriteInt64(InfoPtr + 0x00, BlkInfo.Position); + Memory.WriteInt64(InfoPtr + 0x08, BlkInfo.Size); + Memory.WriteInt32(InfoPtr + 0x10, (int)BlkInfo.State & 0xff); + Memory.WriteInt32(InfoPtr + 0x14, (int)BlkInfo.Attribute); + Memory.WriteInt32(InfoPtr + 0x18, (int)BlkInfo.Permission); + Memory.WriteInt32(InfoPtr + 0x1c, BlkInfo.IpcRefCount); + Memory.WriteInt32(InfoPtr + 0x20, BlkInfo.DeviceRefCount); + Memory.WriteInt32(InfoPtr + 0x24, 0); + + ThreadState.X0 = 0; + ThreadState.X1 = 0; + } + + private void SvcMapSharedMemory(AThreadState ThreadState) + { + int Handle = (int)ThreadState.X0; + long Position = (long)ThreadState.X1; + long Size = (long)ThreadState.X2; + + if (!PageAligned(Position)) + { + Device.Log.PrintWarning(LogClass.KernelSvc, $"Address 0x{Position:x16} is not page aligned!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress); + + return; + } + + if (!PageAligned(Size) || Size == 0) + { + Device.Log.PrintWarning(LogClass.KernelSvc, $"Size 0x{Size:x16} is not page aligned or is zero!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidSize); + + return; + } + + if ((ulong)(Position + Size) <= (ulong)Position) + { + Device.Log.PrintWarning(LogClass.KernelSvc, $"Invalid region address 0x{Position:x16} / size 0x{Size:x16}!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); + + return; + } + + MemoryPermission Permission = (MemoryPermission)ThreadState.X3; + + if ((Permission | MemoryPermission.Write) != MemoryPermission.ReadAndWrite) + { + Device.Log.PrintWarning(LogClass.KernelSvc, $"Invalid permission {Permission}!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidPermission); + + return; + } + + KSharedMemory SharedMemory = Process.HandleTable.GetData(Handle); + + if (SharedMemory == null) + { + Device.Log.PrintWarning(LogClass.KernelSvc, $"Invalid shared memory handle 0x{Handle:x8}!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle); + + return; + } + + if (!InsideAddrSpace(Position, Size) || InsideMapRegion(Position, Size) || InsideHeapRegion(Position, Size)) + { + Device.Log.PrintWarning(LogClass.KernelSvc, $"Address 0x{Position:x16} out of range!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); + + return; + } + + if (SharedMemory.Size != Size) + { + Device.Log.PrintWarning(LogClass.KernelSvc, $"Size 0x{Size:x16} does not match shared memory size 0x{SharedMemory.Size:16}!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidSize); + + return; + } + + long Result = Process.MemoryManager.MapSharedMemory(SharedMemory, Permission, Position); + + if (Result != 0) + { + Device.Log.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!"); + } + + ThreadState.X0 = (ulong)Result; + } + + private void SvcUnmapSharedMemory(AThreadState ThreadState) + { + int Handle = (int)ThreadState.X0; + long Position = (long)ThreadState.X1; + long Size = (long)ThreadState.X2; + + if (!PageAligned(Position)) + { + Device.Log.PrintWarning(LogClass.KernelSvc, $"Address 0x{Position:x16} is not page aligned!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress); + + return; + } + + if (!PageAligned(Size) || Size == 0) + { + Device.Log.PrintWarning(LogClass.KernelSvc, $"Size 0x{Size:x16} is not page aligned or is zero!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidSize); + + return; + } + + if ((ulong)(Position + Size) <= (ulong)Position) + { + Device.Log.PrintWarning(LogClass.KernelSvc, $"Invalid region address 0x{Position:x16} / size 0x{Size:x16}!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); + + return; + } + + KSharedMemory SharedMemory = Process.HandleTable.GetData(Handle); + + if (SharedMemory == null) + { + Device.Log.PrintWarning(LogClass.KernelSvc, $"Invalid shared memory handle 0x{Handle:x8}!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle); + + return; + } + + if (!InsideAddrSpace(Position, Size) || InsideMapRegion(Position, Size) || InsideHeapRegion(Position, Size)) + { + Device.Log.PrintWarning(LogClass.KernelSvc, $"Address 0x{Position:x16} out of range!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); + + return; + } + + long Result = Process.MemoryManager.UnmapSharedMemory(Position, Size); + + if (Result != 0) + { + Device.Log.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!"); + } + + ThreadState.X0 = (ulong)Result; + } + + private void SvcCreateTransferMemory(AThreadState ThreadState) + { + long Position = (long)ThreadState.X1; + long Size = (long)ThreadState.X2; + + if (!PageAligned(Position)) + { + Device.Log.PrintWarning(LogClass.KernelSvc, $"Address 0x{Position:x16} is not page aligned!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress); + + return; + } + + if (!PageAligned(Size) || Size == 0) + { + Device.Log.PrintWarning(LogClass.KernelSvc, $"Size 0x{Size:x16} is not page aligned or is zero!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress); + + return; + } + + if ((ulong)(Position + Size) <= (ulong)Position) + { + Device.Log.PrintWarning(LogClass.KernelSvc, $"Invalid region address 0x{Position:x16} / size 0x{Size:x16}!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); + + return; + } + + MemoryPermission Permission = (MemoryPermission)ThreadState.X3; + + if (Permission > MemoryPermission.ReadAndWrite || Permission == MemoryPermission.Write) + { + Device.Log.PrintWarning(LogClass.KernelSvc, $"Invalid permission {Permission}!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidPermission); + + return; + } + + Process.MemoryManager.ReserveTransferMemory(Position, Size, Permission); + + KTransferMemory TransferMemory = new KTransferMemory(Position, Size); + + int Handle = Process.HandleTable.OpenHandle(TransferMemory); + + ThreadState.X0 = 0; + ThreadState.X1 = (ulong)Handle; + } + + private void SvcMapPhysicalMemory(AThreadState ThreadState) + { + long Position = (long)ThreadState.X0; + long Size = (long)ThreadState.X1; + + if (!PageAligned(Position)) + { + Device.Log.PrintWarning(LogClass.KernelSvc, $"Address 0x{Position:x16} is not page aligned!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress); + + return; + } + + if (!PageAligned(Size) || Size == 0) + { + Device.Log.PrintWarning(LogClass.KernelSvc, $"Size 0x{Size:x16} is not page aligned or is zero!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidSize); + + return; + } + + if ((ulong)(Position + Size) <= (ulong)Position) + { + Device.Log.PrintWarning(LogClass.KernelSvc, $"Invalid region address 0x{Position:x16} / size 0x{Size:x16}!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); + + return; + } + + if (!InsideAddrSpace(Position, Size)) + { + Device.Log.PrintWarning(LogClass.KernelSvc, $"Invalid address {Position:x16}!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); + + return; + } + + long Result = Process.MemoryManager.MapPhysicalMemory(Position, Size); + + if (Result != 0) + { + Device.Log.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!"); + } + + ThreadState.X0 = (ulong)Result; + } + + private void SvcUnmapPhysicalMemory(AThreadState ThreadState) + { + long Position = (long)ThreadState.X0; + long Size = (long)ThreadState.X1; + + if (!PageAligned(Position)) + { + Device.Log.PrintWarning(LogClass.KernelSvc, $"Address 0x{Position:x16} is not page aligned!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress); + + return; + } + + if (!PageAligned(Size) || Size == 0) + { + Device.Log.PrintWarning(LogClass.KernelSvc, $"Size 0x{Size:x16} is not page aligned or is zero!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidSize); + + return; + } + + if ((ulong)(Position + Size) <= (ulong)Position) + { + Device.Log.PrintWarning(LogClass.KernelSvc, $"Invalid region address 0x{Position:x16} / size 0x{Size:x16}!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); + + return; + } + + if (!InsideAddrSpace(Position, Size)) + { + Device.Log.PrintWarning(LogClass.KernelSvc, $"Invalid address {Position:x16}!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); + + return; + } + + long Result = Process.MemoryManager.UnmapPhysicalMemory(Position, Size); + + if (Result != 0) + { + Device.Log.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!"); + } + + ThreadState.X0 = (ulong)Result; + } + + private static bool PageAligned(long Position) + { + return (Position & (KMemoryManager.PageSize - 1)) == 0; + } + + private bool InsideAddrSpace(long Position, long Size) + { + ulong Start = (ulong)Position; + ulong End = (ulong)Size + Start; + + return Start >= (ulong)Process.MemoryManager.AddrSpaceStart && + End < (ulong)Process.MemoryManager.AddrSpaceEnd; + } + + private bool InsideMapRegion(long Position, long Size) + { + ulong Start = (ulong)Position; + ulong End = (ulong)Size + Start; + + return Start >= (ulong)Process.MemoryManager.MapRegionStart && + End < (ulong)Process.MemoryManager.MapRegionEnd; + } + + private bool InsideHeapRegion(long Position, long Size) + { + ulong Start = (ulong)Position; + ulong End = (ulong)Size + Start; + + return Start >= (ulong)Process.MemoryManager.HeapRegionStart && + End < (ulong)Process.MemoryManager.HeapRegionEnd; + } + + private bool InsideNewMapRegion(long Position, long Size) + { + ulong Start = (ulong)Position; + ulong End = (ulong)Size + Start; + + return Start >= (ulong)Process.MemoryManager.NewMapRegionStart && + End < (ulong)Process.MemoryManager.NewMapRegionEnd; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Kernel/SvcSystem.cs b/Ryujinx.HLE/HOS/Kernel/SvcSystem.cs new file mode 100644 index 00000000..7cc1c858 --- /dev/null +++ b/Ryujinx.HLE/HOS/Kernel/SvcSystem.cs @@ -0,0 +1,373 @@ +using ChocolArm64.Memory; +using ChocolArm64.State; +using Ryujinx.HLE.Exceptions; +using Ryujinx.HLE.HOS.Ipc; +using Ryujinx.HLE.HOS.Services; +using Ryujinx.HLE.Logging; +using System; +using System.Threading; + +using static Ryujinx.HLE.HOS.ErrorCode; + +namespace Ryujinx.HLE.HOS.Kernel +{ + partial class SvcHandler + { + private const int AllowedCpuIdBitmask = 0b1111; + + private const bool EnableProcessDebugging = false; + + private void SvcExitProcess(AThreadState ThreadState) + { + Device.System.ExitProcess(Process.ProcessId); + } + + private void SvcClearEvent(AThreadState ThreadState) + { + int Handle = (int)ThreadState.X0; + + //TODO: Implement events. + + ThreadState.X0 = 0; + } + + private void SvcCloseHandle(AThreadState ThreadState) + { + int Handle = (int)ThreadState.X0; + + object Obj = Process.HandleTable.CloseHandle(Handle); + + if (Obj == null) + { + Device.Log.PrintWarning(LogClass.KernelSvc, $"Invalid handle 0x{Handle:x8}!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle); + + return; + } + + if (Obj is KSession Session) + { + Session.Dispose(); + } + else if (Obj is KTransferMemory TransferMemory) + { + Process.MemoryManager.ResetTransferMemory( + TransferMemory.Position, + TransferMemory.Size); + } + + ThreadState.X0 = 0; + } + + private void SvcResetSignal(AThreadState ThreadState) + { + int Handle = (int)ThreadState.X0; + + KEvent Event = Process.HandleTable.GetData(Handle); + + if (Event != null) + { + Event.WaitEvent.Reset(); + + ThreadState.X0 = 0; + } + else + { + Device.Log.PrintWarning(LogClass.KernelSvc, $"Invalid event handle 0x{Handle:x8}!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle); + } + } + + private void SvcWaitSynchronization(AThreadState ThreadState) + { + long HandlesPtr = (long)ThreadState.X1; + int HandlesCount = (int)ThreadState.X2; + ulong Timeout = ThreadState.X3; + + Device.Log.PrintDebug(LogClass.KernelSvc, + "HandlesPtr = 0x" + HandlesPtr .ToString("x16") + ", " + + "HandlesCount = 0x" + HandlesCount.ToString("x8") + ", " + + "Timeout = 0x" + Timeout .ToString("x16")); + + if ((uint)HandlesCount > 0x40) + { + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.CountOutOfRange); + + return; + } + + KThread CurrThread = Process.GetThread(ThreadState.Tpidr); + + WaitHandle[] Handles = new WaitHandle[HandlesCount + 1]; + + for (int Index = 0; Index < HandlesCount; Index++) + { + int Handle = Memory.ReadInt32(HandlesPtr + Index * 4); + + KSynchronizationObject SyncObj = Process.HandleTable.GetData(Handle); + + if (SyncObj == null) + { + Device.Log.PrintWarning(LogClass.KernelSvc, $"Invalid handle 0x{Handle:x8}!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle); + + return; + } + + Handles[Index] = SyncObj.WaitEvent; + } + + using (AutoResetEvent WaitEvent = new AutoResetEvent(false)) + { + if (!SyncWaits.TryAdd(CurrThread, WaitEvent)) + { + throw new InvalidOperationException(); + } + + Handles[HandlesCount] = WaitEvent; + + Process.Scheduler.Suspend(CurrThread); + + int HandleIndex; + + ulong Result = 0; + + if (Timeout != ulong.MaxValue) + { + HandleIndex = WaitHandle.WaitAny(Handles, NsTimeConverter.GetTimeMs(Timeout)); + } + else + { + HandleIndex = WaitHandle.WaitAny(Handles); + } + + if (HandleIndex == WaitHandle.WaitTimeout) + { + Result = MakeError(ErrorModule.Kernel, KernelErr.Timeout); + } + else if (HandleIndex == HandlesCount) + { + Result = MakeError(ErrorModule.Kernel, KernelErr.Canceled); + } + + SyncWaits.TryRemove(CurrThread, out _); + + Process.Scheduler.Resume(CurrThread); + + ThreadState.X0 = Result; + + if (Result == 0) + { + ThreadState.X1 = (ulong)HandleIndex; + } + } + } + + private void SvcCancelSynchronization(AThreadState ThreadState) + { + int ThreadHandle = (int)ThreadState.X0; + + KThread Thread = GetThread(ThreadState.Tpidr, ThreadHandle); + + if (Thread == null) + { + Device.Log.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{ThreadHandle:x8}!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle); + + return; + } + + if (SyncWaits.TryRemove(Thread, out AutoResetEvent WaitEvent)) + { + WaitEvent.Set(); + } + + ThreadState.X0 = 0; + } + + private void SvcGetSystemTick(AThreadState ThreadState) + { + ThreadState.X0 = ThreadState.CntpctEl0; + } + + private void SvcConnectToNamedPort(AThreadState ThreadState) + { + long StackPtr = (long)ThreadState.X0; + long NamePtr = (long)ThreadState.X1; + + string Name = AMemoryHelper.ReadAsciiString(Memory, NamePtr, 8); + + //TODO: Validate that app has perms to access the service, and that the service + //actually exists, return error codes otherwise. + KSession Session = new KSession(ServiceFactory.MakeService(Name), Name); + + ulong Handle = (ulong)Process.HandleTable.OpenHandle(Session); + + ThreadState.X0 = 0; + ThreadState.X1 = Handle; + } + + private void SvcSendSyncRequest(AThreadState ThreadState) + { + SendSyncRequest(ThreadState, ThreadState.Tpidr, 0x100, (int)ThreadState.X0); + } + + private void SvcSendSyncRequestWithUserBuffer(AThreadState ThreadState) + { + SendSyncRequest( + ThreadState, + (long)ThreadState.X0, + (long)ThreadState.X1, + (int)ThreadState.X2); + } + + private void SendSyncRequest(AThreadState ThreadState, long CmdPtr, long Size, int Handle) + { + KThread CurrThread = Process.GetThread(ThreadState.Tpidr); + + byte[] CmdData = Memory.ReadBytes(CmdPtr, Size); + + KSession Session = Process.HandleTable.GetData(Handle); + + if (Session != null) + { + Process.Scheduler.Suspend(CurrThread); + + IpcMessage Cmd = new IpcMessage(CmdData, CmdPtr); + + long Result = IpcHandler.IpcCall(Device, Process, Memory, Session, Cmd, CmdPtr); + + Thread.Yield(); + + Process.Scheduler.Resume(CurrThread); + + ThreadState.X0 = (ulong)Result; + } + else + { + Device.Log.PrintWarning(LogClass.KernelSvc, $"Invalid session handle 0x{Handle:x8}!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle); + } + } + + private void SvcBreak(AThreadState ThreadState) + { + long Reason = (long)ThreadState.X0; + long Unknown = (long)ThreadState.X1; + long Info = (long)ThreadState.X2; + + Process.PrintStackTrace(ThreadState); + + throw new GuestBrokeExecutionException(); + } + + private void SvcOutputDebugString(AThreadState ThreadState) + { + long Position = (long)ThreadState.X0; + long Size = (long)ThreadState.X1; + + string Str = AMemoryHelper.ReadAsciiString(Memory, Position, Size); + + Device.Log.PrintWarning(LogClass.KernelSvc, Str); + + ThreadState.X0 = 0; + } + + private void SvcGetInfo(AThreadState ThreadState) + { + long StackPtr = (long)ThreadState.X0; + int InfoType = (int)ThreadState.X1; + long Handle = (long)ThreadState.X2; + int InfoId = (int)ThreadState.X3; + + //Fail for info not available on older Kernel versions. + if (InfoType == 18 || + InfoType == 19 || + InfoType == 20) + { + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidEnumValue); + + return; + } + + switch (InfoType) + { + case 0: + ThreadState.X1 = AllowedCpuIdBitmask; + break; + + case 2: + ThreadState.X1 = (ulong)Process.MemoryManager.MapRegionStart; + break; + + case 3: + ThreadState.X1 = (ulong)Process.MemoryManager.MapRegionEnd - + (ulong)Process.MemoryManager.MapRegionStart; + break; + + case 4: + ThreadState.X1 = (ulong)Process.MemoryManager.HeapRegionStart; + break; + + case 5: + ThreadState.X1 = (ulong)Process.MemoryManager.HeapRegionEnd - + (ulong)Process.MemoryManager.HeapRegionStart; + break; + + case 6: + ThreadState.X1 = (ulong)Process.Device.Memory.Allocator.TotalAvailableSize; + break; + + case 7: + ThreadState.X1 = (ulong)Process.Device.Memory.Allocator.TotalUsedSize; + break; + + case 8: + ThreadState.X1 = EnableProcessDebugging ? 1 : 0; + break; + + case 11: + ThreadState.X1 = (ulong)Rng.Next() + ((ulong)Rng.Next() << 32); + break; + + case 12: + ThreadState.X1 = (ulong)Process.MemoryManager.AddrSpaceStart; + break; + + case 13: + ThreadState.X1 = (ulong)Process.MemoryManager.AddrSpaceEnd - + (ulong)Process.MemoryManager.AddrSpaceStart; + break; + + case 14: + ThreadState.X1 = (ulong)Process.MemoryManager.NewMapRegionStart; + break; + + case 15: + ThreadState.X1 = (ulong)Process.MemoryManager.NewMapRegionEnd - + (ulong)Process.MemoryManager.NewMapRegionStart; + break; + + case 16: + ThreadState.X1 = (ulong)(Process.MetaData?.SystemResourceSize ?? 0); + break; + + case 17: + ThreadState.X1 = (ulong)Process.MemoryManager.PersonalMmHeapUsage; + break; + + default: + Process.PrintStackTrace(ThreadState); + + throw new NotImplementedException($"SvcGetInfo: {InfoType} 0x{Handle:x8} {InfoId}"); + } + + ThreadState.X0 = 0; + } + } +} diff --git a/Ryujinx.HLE/HOS/Kernel/SvcThread.cs b/Ryujinx.HLE/HOS/Kernel/SvcThread.cs new file mode 100644 index 00000000..69e75ec0 --- /dev/null +++ b/Ryujinx.HLE/HOS/Kernel/SvcThread.cs @@ -0,0 +1,385 @@ +using ChocolArm64.State; +using Ryujinx.HLE.Logging; +using System.Threading; + +using static Ryujinx.HLE.HOS.ErrorCode; + +namespace Ryujinx.HLE.HOS.Kernel +{ + partial class SvcHandler + { + private void SvcCreateThread(AThreadState ThreadState) + { + long EntryPoint = (long)ThreadState.X1; + long ArgsPtr = (long)ThreadState.X2; + long StackTop = (long)ThreadState.X3; + int Priority = (int)ThreadState.X4; + int ProcessorId = (int)ThreadState.X5; + + if ((uint)Priority > 0x3f) + { + Device.Log.PrintWarning(LogClass.KernelSvc, $"Invalid priority 0x{Priority:x8}!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidPriority); + + return; + } + + if (ProcessorId == -2) + { + //TODO: Get this value from the NPDM file. + ProcessorId = 0; + } + else if ((uint)ProcessorId > 3) + { + Device.Log.PrintWarning(LogClass.KernelSvc, $"Invalid core id 0x{ProcessorId:x8}!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidCoreId); + + return; + } + + int Handle = Process.MakeThread( + EntryPoint, + StackTop, + ArgsPtr, + Priority, + ProcessorId); + + ThreadState.X0 = 0; + ThreadState.X1 = (ulong)Handle; + } + + private void SvcStartThread(AThreadState ThreadState) + { + int Handle = (int)ThreadState.X0; + + KThread NewThread = Process.HandleTable.GetData(Handle); + + if (NewThread != null) + { + Process.Scheduler.StartThread(NewThread); + Process.Scheduler.SetReschedule(NewThread.ProcessorId); + + ThreadState.X0 = 0; + } + else + { + Device.Log.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{Handle:x8}!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle); + } + } + + private void SvcExitThread(AThreadState ThreadState) + { + KThread CurrThread = Process.GetThread(ThreadState.Tpidr); + + CurrThread.Thread.StopExecution(); + } + + private void SvcSleepThread(AThreadState ThreadState) + { + ulong TimeoutNs = ThreadState.X0; + + Device.Log.PrintDebug(LogClass.KernelSvc, "Timeout = 0x" + TimeoutNs.ToString("x16")); + + KThread CurrThread = Process.GetThread(ThreadState.Tpidr); + + if (TimeoutNs == 0 || TimeoutNs == ulong.MaxValue) + { + Process.Scheduler.Yield(CurrThread); + } + else + { + Process.Scheduler.Suspend(CurrThread); + + Thread.Sleep(NsTimeConverter.GetTimeMs(TimeoutNs)); + + Process.Scheduler.Resume(CurrThread); + } + } + + private void SvcGetThreadPriority(AThreadState ThreadState) + { + int Handle = (int)ThreadState.X1; + + KThread Thread = GetThread(ThreadState.Tpidr, Handle); + + if (Thread != null) + { + ThreadState.X0 = 0; + ThreadState.X1 = (ulong)Thread.ActualPriority; + } + else + { + Device.Log.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{Handle:x8}!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle); + } + } + + private void SvcSetThreadPriority(AThreadState ThreadState) + { + int Handle = (int)ThreadState.X0; + int Priority = (int)ThreadState.X1; + + Device.Log.PrintDebug(LogClass.KernelSvc, + "Handle = 0x" + Handle .ToString("x8") + ", " + + "Priority = 0x" + Priority.ToString("x8")); + + KThread Thread = GetThread(ThreadState.Tpidr, Handle); + + if (Thread != null) + { + Thread.SetPriority(Priority); + + ThreadState.X0 = 0; + } + else + { + Device.Log.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{Handle:x8}!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle); + } + } + + private void SvcGetThreadCoreMask(AThreadState ThreadState) + { + int Handle = (int)ThreadState.X2; + + Device.Log.PrintDebug(LogClass.KernelSvc, "Handle = 0x" + Handle.ToString("x8")); + + KThread Thread = GetThread(ThreadState.Tpidr, Handle); + + if (Thread != null) + { + ThreadState.X0 = 0; + ThreadState.X1 = (ulong)Thread.IdealCore; + ThreadState.X2 = (ulong)Thread.CoreMask; + } + else + { + Device.Log.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{Handle:x8}!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle); + } + } + + private void SvcSetThreadCoreMask(AThreadState ThreadState) + { + int Handle = (int)ThreadState.X0; + int IdealCore = (int)ThreadState.X1; + long CoreMask = (long)ThreadState.X2; + + Device.Log.PrintDebug(LogClass.KernelSvc, + "Handle = 0x" + Handle .ToString("x8") + ", " + + "IdealCore = 0x" + IdealCore.ToString("x8") + ", " + + "CoreMask = 0x" + CoreMask .ToString("x16")); + + KThread Thread = GetThread(ThreadState.Tpidr, Handle); + + if (IdealCore == -2) + { + //TODO: Get this value from the NPDM file. + IdealCore = 0; + + CoreMask = 1 << IdealCore; + } + else + { + if ((uint)IdealCore > 3) + { + if ((IdealCore | 2) != -1) + { + Device.Log.PrintWarning(LogClass.KernelSvc, $"Invalid core id 0x{IdealCore:x8}!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidCoreId); + + return; + } + } + else if ((CoreMask & (1 << IdealCore)) == 0) + { + Device.Log.PrintWarning(LogClass.KernelSvc, $"Invalid core mask 0x{CoreMask:x8}!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidMaskValue); + + return; + } + } + + if (Thread == null) + { + Device.Log.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{Handle:x8}!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle); + + return; + } + + //-1 is used as "don't care", so the IdealCore value is ignored. + //-2 is used as "use NPDM default core id" (handled above). + //-3 is used as "don't update", the old IdealCore value is kept. + if (IdealCore == -3 && (CoreMask & (1 << Thread.IdealCore)) == 0) + { + Device.Log.PrintWarning(LogClass.KernelSvc, $"Invalid core mask 0x{CoreMask:x8}!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidMaskValue); + + return; + } + + Process.Scheduler.ChangeCore(Thread, IdealCore, (int)CoreMask); + + ThreadState.X0 = 0; + } + + private void SvcGetCurrentProcessorNumber(AThreadState ThreadState) + { + ThreadState.X0 = (ulong)Process.GetThread(ThreadState.Tpidr).ActualCore; + } + + private void SvcGetThreadId(AThreadState ThreadState) + { + int Handle = (int)ThreadState.X1; + + KThread Thread = GetThread(ThreadState.Tpidr, Handle); + + if (Thread != null) + { + ThreadState.X0 = 0; + ThreadState.X1 = (ulong)Thread.ThreadId; + } + else + { + Device.Log.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{Handle:x8}!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle); + } + } + + private void SvcSetThreadActivity(AThreadState ThreadState) + { + int Handle = (int)ThreadState.X0; + bool Active = (int)ThreadState.X1 == 0; + + KThread Thread = Process.HandleTable.GetData(Handle); + + if (Thread != null) + { + Process.Scheduler.SetThreadActivity(Thread, Active); + + ThreadState.X0 = 0; + } + else + { + Device.Log.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{Handle:x8}!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle); + } + } + + private void SvcGetThreadContext3(AThreadState ThreadState) + { + long Position = (long)ThreadState.X0; + int Handle = (int)ThreadState.X1; + + KThread Thread = Process.HandleTable.GetData(Handle); + + if (Thread == null) + { + Device.Log.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{Handle:x8}!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle); + + return; + } + + if (Process.GetThread(ThreadState.Tpidr) == Thread) + { + Device.Log.PrintWarning(LogClass.KernelSvc, $"Thread handle 0x{Handle:x8} is current thread!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidThread); + + return; + } + + Memory.WriteUInt64(Position + 0x0, ThreadState.X0); + Memory.WriteUInt64(Position + 0x8, ThreadState.X1); + Memory.WriteUInt64(Position + 0x10, ThreadState.X2); + Memory.WriteUInt64(Position + 0x18, ThreadState.X3); + Memory.WriteUInt64(Position + 0x20, ThreadState.X4); + Memory.WriteUInt64(Position + 0x28, ThreadState.X5); + Memory.WriteUInt64(Position + 0x30, ThreadState.X6); + Memory.WriteUInt64(Position + 0x38, ThreadState.X7); + Memory.WriteUInt64(Position + 0x40, ThreadState.X8); + Memory.WriteUInt64(Position + 0x48, ThreadState.X9); + Memory.WriteUInt64(Position + 0x50, ThreadState.X10); + Memory.WriteUInt64(Position + 0x58, ThreadState.X11); + Memory.WriteUInt64(Position + 0x60, ThreadState.X12); + Memory.WriteUInt64(Position + 0x68, ThreadState.X13); + Memory.WriteUInt64(Position + 0x70, ThreadState.X14); + Memory.WriteUInt64(Position + 0x78, ThreadState.X15); + Memory.WriteUInt64(Position + 0x80, ThreadState.X16); + Memory.WriteUInt64(Position + 0x88, ThreadState.X17); + Memory.WriteUInt64(Position + 0x90, ThreadState.X18); + Memory.WriteUInt64(Position + 0x98, ThreadState.X19); + Memory.WriteUInt64(Position + 0xa0, ThreadState.X20); + Memory.WriteUInt64(Position + 0xa8, ThreadState.X21); + Memory.WriteUInt64(Position + 0xb0, ThreadState.X22); + Memory.WriteUInt64(Position + 0xb8, ThreadState.X23); + Memory.WriteUInt64(Position + 0xc0, ThreadState.X24); + Memory.WriteUInt64(Position + 0xc8, ThreadState.X25); + Memory.WriteUInt64(Position + 0xd0, ThreadState.X26); + Memory.WriteUInt64(Position + 0xd8, ThreadState.X27); + Memory.WriteUInt64(Position + 0xe0, ThreadState.X28); + Memory.WriteUInt64(Position + 0xe8, ThreadState.X29); + Memory.WriteUInt64(Position + 0xf0, ThreadState.X30); + Memory.WriteUInt64(Position + 0xf8, ThreadState.X31); + + Memory.WriteInt64(Position + 0x100, Thread.LastPc); + + Memory.WriteUInt64(Position + 0x108, (ulong)ThreadState.Psr); + + Memory.WriteVector128(Position + 0x110, ThreadState.V0); + Memory.WriteVector128(Position + 0x120, ThreadState.V1); + Memory.WriteVector128(Position + 0x130, ThreadState.V2); + Memory.WriteVector128(Position + 0x140, ThreadState.V3); + Memory.WriteVector128(Position + 0x150, ThreadState.V4); + Memory.WriteVector128(Position + 0x160, ThreadState.V5); + Memory.WriteVector128(Position + 0x170, ThreadState.V6); + Memory.WriteVector128(Position + 0x180, ThreadState.V7); + Memory.WriteVector128(Position + 0x190, ThreadState.V8); + Memory.WriteVector128(Position + 0x1a0, ThreadState.V9); + Memory.WriteVector128(Position + 0x1b0, ThreadState.V10); + Memory.WriteVector128(Position + 0x1c0, ThreadState.V11); + Memory.WriteVector128(Position + 0x1d0, ThreadState.V12); + Memory.WriteVector128(Position + 0x1e0, ThreadState.V13); + Memory.WriteVector128(Position + 0x1f0, ThreadState.V14); + Memory.WriteVector128(Position + 0x200, ThreadState.V15); + Memory.WriteVector128(Position + 0x210, ThreadState.V16); + Memory.WriteVector128(Position + 0x220, ThreadState.V17); + Memory.WriteVector128(Position + 0x230, ThreadState.V18); + Memory.WriteVector128(Position + 0x240, ThreadState.V19); + Memory.WriteVector128(Position + 0x250, ThreadState.V20); + Memory.WriteVector128(Position + 0x260, ThreadState.V21); + Memory.WriteVector128(Position + 0x270, ThreadState.V22); + Memory.WriteVector128(Position + 0x280, ThreadState.V23); + Memory.WriteVector128(Position + 0x290, ThreadState.V24); + Memory.WriteVector128(Position + 0x2a0, ThreadState.V25); + Memory.WriteVector128(Position + 0x2b0, ThreadState.V26); + Memory.WriteVector128(Position + 0x2c0, ThreadState.V27); + Memory.WriteVector128(Position + 0x2d0, ThreadState.V28); + Memory.WriteVector128(Position + 0x2e0, ThreadState.V29); + Memory.WriteVector128(Position + 0x2f0, ThreadState.V30); + Memory.WriteVector128(Position + 0x300, ThreadState.V31); + + Memory.WriteInt32(Position + 0x310, ThreadState.Fpcr); + Memory.WriteInt32(Position + 0x314, ThreadState.Fpsr); + Memory.WriteInt64(Position + 0x318, ThreadState.Tpidr); + + ThreadState.X0 = 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Kernel/SvcThreadSync.cs b/Ryujinx.HLE/HOS/Kernel/SvcThreadSync.cs new file mode 100644 index 00000000..7097d0f7 --- /dev/null +++ b/Ryujinx.HLE/HOS/Kernel/SvcThreadSync.cs @@ -0,0 +1,523 @@ +using ChocolArm64.State; +using Ryujinx.HLE.Logging; +using System; + +using static Ryujinx.HLE.HOS.ErrorCode; + +namespace Ryujinx.HLE.HOS.Kernel +{ + partial class SvcHandler + { + private const int MutexHasListenersMask = 0x40000000; + + private void SvcArbitrateLock(AThreadState ThreadState) + { + int OwnerThreadHandle = (int)ThreadState.X0; + long MutexAddress = (long)ThreadState.X1; + int WaitThreadHandle = (int)ThreadState.X2; + + Device.Log.PrintDebug(LogClass.KernelSvc, + "OwnerThreadHandle = 0x" + OwnerThreadHandle.ToString("x8") + ", " + + "MutexAddress = 0x" + MutexAddress .ToString("x16") + ", " + + "WaitThreadHandle = 0x" + WaitThreadHandle .ToString("x8")); + + if (IsPointingInsideKernel(MutexAddress)) + { + Device.Log.PrintWarning(LogClass.KernelSvc, $"Invalid mutex address 0x{MutexAddress:x16}!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); + + return; + } + + if (IsAddressNotWordAligned(MutexAddress)) + { + Device.Log.PrintWarning(LogClass.KernelSvc, $"Unaligned mutex address 0x{MutexAddress:x16}!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress); + + return; + } + + KThread OwnerThread = Process.HandleTable.GetData(OwnerThreadHandle); + + if (OwnerThread == null) + { + Device.Log.PrintWarning(LogClass.KernelSvc, $"Invalid owner thread handle 0x{OwnerThreadHandle:x8}!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle); + + return; + } + + KThread WaitThread = Process.HandleTable.GetData(WaitThreadHandle); + + if (WaitThread == null) + { + Device.Log.PrintWarning(LogClass.KernelSvc, $"Invalid requesting thread handle 0x{WaitThreadHandle:x8}!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle); + + return; + } + + KThread CurrThread = Process.GetThread(ThreadState.Tpidr); + + MutexLock(CurrThread, WaitThread, OwnerThreadHandle, WaitThreadHandle, MutexAddress); + + ThreadState.X0 = 0; + } + + private void SvcArbitrateUnlock(AThreadState ThreadState) + { + long MutexAddress = (long)ThreadState.X0; + + Device.Log.PrintDebug(LogClass.KernelSvc, "MutexAddress = 0x" + MutexAddress.ToString("x16")); + + if (IsPointingInsideKernel(MutexAddress)) + { + Device.Log.PrintWarning(LogClass.KernelSvc, $"Invalid mutex address 0x{MutexAddress:x16}!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); + + return; + } + + if (IsAddressNotWordAligned(MutexAddress)) + { + Device.Log.PrintWarning(LogClass.KernelSvc, $"Unaligned mutex address 0x{MutexAddress:x16}!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress); + + return; + } + + MutexUnlock(Process.GetThread(ThreadState.Tpidr), MutexAddress); + + ThreadState.X0 = 0; + } + + private void SvcWaitProcessWideKeyAtomic(AThreadState ThreadState) + { + long MutexAddress = (long)ThreadState.X0; + long CondVarAddress = (long)ThreadState.X1; + int ThreadHandle = (int)ThreadState.X2; + ulong Timeout = ThreadState.X3; + + Device.Log.PrintDebug(LogClass.KernelSvc, + "MutexAddress = 0x" + MutexAddress .ToString("x16") + ", " + + "CondVarAddress = 0x" + CondVarAddress.ToString("x16") + ", " + + "ThreadHandle = 0x" + ThreadHandle .ToString("x8") + ", " + + "Timeout = 0x" + Timeout .ToString("x16")); + + if (IsPointingInsideKernel(MutexAddress)) + { + Device.Log.PrintWarning(LogClass.KernelSvc, $"Invalid mutex address 0x{MutexAddress:x16}!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); + + return; + } + + if (IsAddressNotWordAligned(MutexAddress)) + { + Device.Log.PrintWarning(LogClass.KernelSvc, $"Unaligned mutex address 0x{MutexAddress:x16}!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress); + + return; + } + + KThread Thread = Process.HandleTable.GetData(ThreadHandle); + + if (Thread == null) + { + Device.Log.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{ThreadHandle:x8}!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle); + + return; + } + + KThread WaitThread = Process.GetThread(ThreadState.Tpidr); + + if (!CondVarWait(WaitThread, ThreadHandle, MutexAddress, CondVarAddress, Timeout)) + { + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.Timeout); + + return; + } + + ThreadState.X0 = 0; + } + + private void SvcSignalProcessWideKey(AThreadState ThreadState) + { + long CondVarAddress = (long)ThreadState.X0; + int Count = (int)ThreadState.X1; + + Device.Log.PrintDebug(LogClass.KernelSvc, + "CondVarAddress = 0x" + CondVarAddress.ToString("x16") + ", " + + "Count = 0x" + Count .ToString("x8")); + + KThread CurrThread = Process.GetThread(ThreadState.Tpidr); + + CondVarSignal(ThreadState, CurrThread, CondVarAddress, Count); + + ThreadState.X0 = 0; + } + + private void MutexLock( + KThread CurrThread, + KThread WaitThread, + int OwnerThreadHandle, + int WaitThreadHandle, + long MutexAddress) + { + lock (Process.ThreadSyncLock) + { + int MutexValue = Memory.ReadInt32(MutexAddress); + + Device.Log.PrintDebug(LogClass.KernelSvc, "MutexValue = 0x" + MutexValue.ToString("x8")); + + if (MutexValue != (OwnerThreadHandle | MutexHasListenersMask)) + { + return; + } + + CurrThread.WaitHandle = WaitThreadHandle; + CurrThread.MutexAddress = MutexAddress; + + InsertWaitingMutexThreadUnsafe(OwnerThreadHandle, WaitThread); + } + + Device.Log.PrintDebug(LogClass.KernelSvc, "Entering wait state..."); + + Process.Scheduler.EnterWait(CurrThread); + } + + private void SvcWaitForAddress(AThreadState ThreadState) + { + long Address = (long)ThreadState.X0; + ArbitrationType Type = (ArbitrationType)ThreadState.X1; + int Value = (int)ThreadState.X2; + ulong Timeout = ThreadState.X3; + + Device.Log.PrintDebug(LogClass.KernelSvc, + "Address = 0x" + Address.ToString("x16") + ", " + + "ArbitrationType = 0x" + Type .ToString() + ", " + + "Value = 0x" + Value .ToString("x8") + ", " + + "Timeout = 0x" + Timeout.ToString("x16")); + + if (IsPointingInsideKernel(Address)) + { + Device.Log.PrintWarning(LogClass.KernelSvc, $"Invalid address 0x{Address:x16}!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); + + return; + } + + if (IsAddressNotWordAligned(Address)) + { + Device.Log.PrintWarning(LogClass.KernelSvc, $"Unaligned address 0x{Address:x16}!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress); + + return; + } + + switch (Type) + { + case ArbitrationType.WaitIfLessThan: + ThreadState.X0 = AddressArbiter.WaitForAddressIfLessThan(Process, ThreadState, Memory, Address, Value, Timeout, false); + break; + + case ArbitrationType.DecrementAndWaitIfLessThan: + ThreadState.X0 = AddressArbiter.WaitForAddressIfLessThan(Process, ThreadState, Memory, Address, Value, Timeout, true); + break; + + case ArbitrationType.WaitIfEqual: + ThreadState.X0 = AddressArbiter.WaitForAddressIfEqual(Process, ThreadState, Memory, Address, Value, Timeout); + break; + + default: + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidEnumValue); + break; + } + } + + private void MutexUnlock(KThread CurrThread, long MutexAddress) + { + lock (Process.ThreadSyncLock) + { + //This is the new thread that will now own the mutex. + //If no threads are waiting for the lock, then it should be null. + (KThread OwnerThread, int Count) = PopMutexThreadUnsafe(CurrThread, MutexAddress); + + if (OwnerThread == CurrThread) + { + throw new InvalidOperationException(); + } + + if (OwnerThread != null) + { + //Remove all waiting mutex from the old owner, + //and insert then on the new owner. + UpdateMutexOwnerUnsafe(CurrThread, OwnerThread, MutexAddress); + + CurrThread.UpdatePriority(); + + int HasListeners = Count >= 2 ? MutexHasListenersMask : 0; + + Memory.WriteInt32ToSharedAddr(MutexAddress, HasListeners | OwnerThread.WaitHandle); + + OwnerThread.WaitHandle = 0; + OwnerThread.MutexAddress = 0; + OwnerThread.CondVarAddress = 0; + OwnerThread.MutexOwner = null; + + OwnerThread.UpdatePriority(); + + Process.Scheduler.WakeUp(OwnerThread); + + Device.Log.PrintDebug(LogClass.KernelSvc, "Gave mutex to thread id " + OwnerThread.ThreadId + "!"); + } + else + { + Memory.WriteInt32ToSharedAddr(MutexAddress, 0); + + Device.Log.PrintDebug(LogClass.KernelSvc, "No threads waiting mutex!"); + } + } + } + + private bool CondVarWait( + KThread WaitThread, + int WaitThreadHandle, + long MutexAddress, + long CondVarAddress, + ulong Timeout) + { + WaitThread.WaitHandle = WaitThreadHandle; + WaitThread.MutexAddress = MutexAddress; + WaitThread.CondVarAddress = CondVarAddress; + + lock (Process.ThreadSyncLock) + { + MutexUnlock(WaitThread, MutexAddress); + + WaitThread.CondVarSignaled = false; + + Process.ThreadArbiterList.Add(WaitThread); + } + + Device.Log.PrintDebug(LogClass.KernelSvc, "Entering wait state..."); + + if (Timeout != ulong.MaxValue) + { + Process.Scheduler.EnterWait(WaitThread, NsTimeConverter.GetTimeMs(Timeout)); + + lock (Process.ThreadSyncLock) + { + if (!WaitThread.CondVarSignaled || WaitThread.MutexOwner != null) + { + if (WaitThread.MutexOwner != null) + { + WaitThread.MutexOwner.MutexWaiters.Remove(WaitThread); + WaitThread.MutexOwner.UpdatePriority(); + + WaitThread.MutexOwner = null; + } + + Process.ThreadArbiterList.Remove(WaitThread); + + Device.Log.PrintDebug(LogClass.KernelSvc, "Timed out..."); + + return false; + } + } + } + else + { + Process.Scheduler.EnterWait(WaitThread); + } + + return true; + } + + private void CondVarSignal( + AThreadState ThreadState, + KThread CurrThread, + long CondVarAddress, + int Count) + { + lock (Process.ThreadSyncLock) + { + while (Count == -1 || Count-- > 0) + { + KThread WaitThread = PopCondVarThreadUnsafe(CondVarAddress); + + if (WaitThread == null) + { + Device.Log.PrintDebug(LogClass.KernelSvc, "No more threads to wake up!"); + + break; + } + + WaitThread.CondVarSignaled = true; + + long MutexAddress = WaitThread.MutexAddress; + + Memory.SetExclusive(ThreadState, MutexAddress); + + int MutexValue = Memory.ReadInt32(MutexAddress); + + while (MutexValue != 0) + { + if (Memory.TestExclusive(ThreadState, MutexAddress)) + { + //Wait until the lock is released. + InsertWaitingMutexThreadUnsafe(MutexValue & ~MutexHasListenersMask, WaitThread); + + Memory.WriteInt32(MutexAddress, MutexValue | MutexHasListenersMask); + + Memory.ClearExclusiveForStore(ThreadState); + + break; + } + + Memory.SetExclusive(ThreadState, MutexAddress); + + MutexValue = Memory.ReadInt32(MutexAddress); + } + + Device.Log.PrintDebug(LogClass.KernelSvc, "MutexValue = 0x" + MutexValue.ToString("x8")); + + if (MutexValue == 0) + { + //Give the lock to this thread. + Memory.WriteInt32ToSharedAddr(MutexAddress, WaitThread.WaitHandle); + + WaitThread.WaitHandle = 0; + WaitThread.MutexAddress = 0; + WaitThread.CondVarAddress = 0; + + WaitThread.MutexOwner?.UpdatePriority(); + + WaitThread.MutexOwner = null; + + Process.Scheduler.WakeUp(WaitThread); + } + } + } + } + + private void UpdateMutexOwnerUnsafe(KThread CurrThread, KThread NewOwner, long MutexAddress) + { + //Go through all threads waiting for the mutex, + //and update the MutexOwner field to point to the new owner. + for (int Index = 0; Index < CurrThread.MutexWaiters.Count; Index++) + { + KThread Thread = CurrThread.MutexWaiters[Index]; + + if (Thread.MutexAddress == MutexAddress) + { + CurrThread.MutexWaiters.RemoveAt(Index--); + + InsertWaitingMutexThreadUnsafe(NewOwner, Thread); + } + } + } + + private void InsertWaitingMutexThreadUnsafe(int OwnerThreadHandle, KThread WaitThread) + { + KThread OwnerThread = Process.HandleTable.GetData(OwnerThreadHandle); + + if (OwnerThread == null) + { + Device.Log.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{OwnerThreadHandle:x8}!"); + + return; + } + + InsertWaitingMutexThreadUnsafe(OwnerThread, WaitThread); + } + + private void InsertWaitingMutexThreadUnsafe(KThread OwnerThread, KThread WaitThread) + { + WaitThread.MutexOwner = OwnerThread; + + if (!OwnerThread.MutexWaiters.Contains(WaitThread)) + { + OwnerThread.MutexWaiters.Add(WaitThread); + + OwnerThread.UpdatePriority(); + } + } + + private (KThread, int) PopMutexThreadUnsafe(KThread OwnerThread, long MutexAddress) + { + int Count = 0; + + KThread WakeThread = null; + + foreach (KThread Thread in OwnerThread.MutexWaiters) + { + if (Thread.MutexAddress != MutexAddress) + { + continue; + } + + if (WakeThread == null || Thread.ActualPriority < WakeThread.ActualPriority) + { + WakeThread = Thread; + } + + Count++; + } + + if (WakeThread != null) + { + OwnerThread.MutexWaiters.Remove(WakeThread); + } + + return (WakeThread, Count); + } + + private KThread PopCondVarThreadUnsafe(long CondVarAddress) + { + KThread WakeThread = null; + + foreach (KThread Thread in Process.ThreadArbiterList) + { + if (Thread.CondVarAddress != CondVarAddress) + { + continue; + } + + if (WakeThread == null || Thread.ActualPriority < WakeThread.ActualPriority) + { + WakeThread = Thread; + } + } + + if (WakeThread != null) + { + Process.ThreadArbiterList.Remove(WakeThread); + } + + return WakeThread; + } + + private bool IsPointingInsideKernel(long Address) + { + return ((ulong)Address + 0x1000000000) < 0xffffff000; + } + + private bool IsAddressNotWordAligned(long Address) + { + return (Address & 3) != 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Kernel/ThreadQueue.cs b/Ryujinx.HLE/HOS/Kernel/ThreadQueue.cs new file mode 100644 index 00000000..815e86ad --- /dev/null +++ b/Ryujinx.HLE/HOS/Kernel/ThreadQueue.cs @@ -0,0 +1,158 @@ +namespace Ryujinx.HLE.HOS.Kernel +{ + class ThreadQueue + { + private const int LowestPriority = 0x3f; + + private SchedulerThread Head; + + private object ListLock; + + public ThreadQueue() + { + ListLock = new object(); + } + + public void Push(SchedulerThread Wait) + { + lock (ListLock) + { + //Ensure that we're not creating circular references + //by adding a thread that is already on the list. + if (HasThread(Wait)) + { + return; + } + + if (Head == null || Head.Thread.ActualPriority >= Wait.Thread.ActualPriority) + { + Wait.Next = Head; + + Head = Wait; + + return; + } + + SchedulerThread Curr = Head; + + while (Curr.Next != null) + { + if (Curr.Next.Thread.ActualPriority >= Wait.Thread.ActualPriority) + { + break; + } + + Curr = Curr.Next; + } + + Wait.Next = Curr.Next; + Curr.Next = Wait; + } + } + + public SchedulerThread Pop(int Core, int MinPriority = LowestPriority) + { + lock (ListLock) + { + int CoreMask = 1 << Core; + + SchedulerThread Prev = null; + SchedulerThread Curr = Head; + + while (Curr != null) + { + KThread Thread = Curr.Thread; + + if (Thread.ActualPriority <= MinPriority && (Thread.CoreMask & CoreMask) != 0) + { + if (Prev != null) + { + Prev.Next = Curr.Next; + } + else + { + Head = Head.Next; + } + + break; + } + + Prev = Curr; + Curr = Curr.Next; + } + + return Curr; + } + } + + public bool Remove(SchedulerThread Thread) + { + lock (ListLock) + { + if (Head == null) + { + return false; + } + else if (Head == Thread) + { + Head = Head.Next; + + return true; + } + + SchedulerThread Prev = Head; + SchedulerThread Curr = Head.Next; + + while (Curr != null) + { + if (Curr == Thread) + { + Prev.Next = Curr.Next; + + return true; + } + + Prev = Curr; + Curr = Curr.Next; + } + + return false; + } + } + + public bool Resort(SchedulerThread Thread) + { + lock (ListLock) + { + if (Remove(Thread)) + { + Push(Thread); + + return true; + } + + return false; + } + } + + public bool HasThread(SchedulerThread Thread) + { + lock (ListLock) + { + SchedulerThread Curr = Head; + + while (Curr != null) + { + if (Curr == Thread) + { + return true; + } + + Curr = Curr.Next; + } + + return false; + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Process.cs b/Ryujinx.HLE/HOS/Process.cs new file mode 100644 index 00000000..bfda93f4 --- /dev/null +++ b/Ryujinx.HLE/HOS/Process.cs @@ -0,0 +1,438 @@ +using ChocolArm64; +using ChocolArm64.Events; +using ChocolArm64.Memory; +using ChocolArm64.State; +using Ryujinx.HLE.Exceptions; +using Ryujinx.HLE.HOS.Diagnostics; +using Ryujinx.HLE.HOS.Kernel; +using Ryujinx.HLE.HOS.Services.Nv; +using Ryujinx.HLE.HOS.SystemState; +using Ryujinx.HLE.Loaders; +using Ryujinx.HLE.Loaders.Executables; +using Ryujinx.HLE.Loaders.Npdm; +using Ryujinx.HLE.Logging; +using Ryujinx.HLE.Utilities; +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.IO; +using System.Text; + +namespace Ryujinx.HLE.HOS +{ + class Process : IDisposable + { + private const int TickFreq = 19_200_000; + + public Switch Device { get; private set; } + + public bool NeedsHbAbi { get; private set; } + + public long HbAbiDataPosition { get; private set; } + + public int ProcessId { get; private set; } + + private ATranslator Translator; + + public AMemory Memory { get; private set; } + + public KMemoryManager MemoryManager { get; private set; } + + private List TlsPages; + + public KProcessScheduler Scheduler { get; private set; } + + public List ThreadArbiterList { get; private set; } + + public object ThreadSyncLock { get; private set; } + + public Npdm MetaData { get; private set; } + + public KProcessHandleTable HandleTable { get; private set; } + + public AppletStateMgr AppletState { get; private set; } + + private SvcHandler SvcHandler; + + private ConcurrentDictionary Threads; + + private List Executables; + + private Dictionary SymbolTable; + + private long ImageBase; + + private bool ShouldDispose; + + private bool Disposed; + + public Process(Switch Device, KProcessScheduler Scheduler, int ProcessId, Npdm MetaData) + { + this.Device = Device; + this.Scheduler = Scheduler; + this.MetaData = MetaData; + this.ProcessId = ProcessId; + + Memory = new AMemory(Device.Memory.RamPointer); + + MemoryManager = new KMemoryManager(this); + + TlsPages = new List(); + + ThreadArbiterList = new List(); + + ThreadSyncLock = new object(); + + HandleTable = new KProcessHandleTable(); + + AppletState = new AppletStateMgr(); + + SvcHandler = new SvcHandler(Device, this); + + Threads = new ConcurrentDictionary(); + + Executables = new List(); + + ImageBase = MemoryManager.CodeRegionStart; + } + + public void LoadProgram(IExecutable Program) + { + if (Disposed) + { + throw new ObjectDisposedException(nameof(Process)); + } + + Device.Log.PrintInfo(LogClass.Loader, $"Image base at 0x{ImageBase:x16}."); + + Executable Executable = new Executable(Program, MemoryManager, Memory, ImageBase); + + Executables.Add(Executable); + + ImageBase = IntUtils.AlignUp(Executable.ImageEnd, KMemoryManager.PageSize); + } + + public void SetEmptyArgs() + { + //TODO: This should be part of Run. + ImageBase += KMemoryManager.PageSize; + } + + public bool Run(bool NeedsHbAbi = false) + { + if (Disposed) + { + throw new ObjectDisposedException(nameof(Process)); + } + + this.NeedsHbAbi = NeedsHbAbi; + + if (Executables.Count == 0) + { + return false; + } + + MakeSymbolTable(); + + long MainStackTop = MemoryManager.CodeRegionEnd - KMemoryManager.PageSize; + + long MainStackSize = 1 * 1024 * 1024; + + long MainStackBottom = MainStackTop - MainStackSize; + + MemoryManager.HleMapCustom( + MainStackBottom, + MainStackSize, + MemoryState.MappedMemory, + MemoryPermission.ReadAndWrite); + + int Handle = MakeThread(Executables[0].ImageBase, MainStackTop, 0, 44, 0); + + if (Handle == -1) + { + return false; + } + + KThread MainThread = HandleTable.GetData(Handle); + + if (NeedsHbAbi) + { + HbAbiDataPosition = IntUtils.AlignUp(Executables[0].ImageEnd, KMemoryManager.PageSize); + + const long HbAbiDataSize = KMemoryManager.PageSize; + + MemoryManager.HleMapCustom( + HbAbiDataPosition, + HbAbiDataSize, + MemoryState.MappedMemory, + MemoryPermission.ReadAndWrite); + + string SwitchPath = Device.FileSystem.SystemPathToSwitchPath(Executables[0].FilePath); + + Homebrew.WriteHbAbiData(Memory, HbAbiDataPosition, Handle, SwitchPath); + + MainThread.Thread.ThreadState.X0 = (ulong)HbAbiDataPosition; + MainThread.Thread.ThreadState.X1 = ulong.MaxValue; + } + + Scheduler.StartThread(MainThread); + + return true; + } + + public int MakeThread( + long EntryPoint, + long StackTop, + long ArgsPtr, + int Priority, + int ProcessorId) + { + if (Disposed) + { + throw new ObjectDisposedException(nameof(Process)); + } + + AThread CpuThread = new AThread(GetTranslator(), Memory, EntryPoint); + + long Tpidr = GetFreeTls(); + + int ThreadId = (int)((Tpidr - MemoryManager.TlsIoRegionStart) / 0x200) + 1; + + KThread Thread = new KThread(CpuThread, this, ProcessorId, Priority, ThreadId); + + Thread.LastPc = EntryPoint; + + int Handle = HandleTable.OpenHandle(Thread); + + CpuThread.ThreadState.CntfrqEl0 = TickFreq; + CpuThread.ThreadState.Tpidr = Tpidr; + + CpuThread.ThreadState.X0 = (ulong)ArgsPtr; + CpuThread.ThreadState.X1 = (ulong)Handle; + CpuThread.ThreadState.X31 = (ulong)StackTop; + + CpuThread.ThreadState.Break += BreakHandler; + CpuThread.ThreadState.SvcCall += SvcHandler.SvcCall; + CpuThread.ThreadState.Undefined += UndefinedHandler; + + CpuThread.WorkFinished += ThreadFinished; + + Threads.TryAdd(CpuThread.ThreadState.Tpidr, Thread); + + return Handle; + } + + private long GetFreeTls() + { + long Position; + + lock (TlsPages) + { + for (int Index = 0; Index < TlsPages.Count; Index++) + { + if (TlsPages[Index].TryGetFreeTlsAddr(out Position)) + { + return Position; + } + } + + long PagePosition = MemoryManager.HleMapTlsPage(); + + KTlsPageManager TlsPage = new KTlsPageManager(PagePosition); + + TlsPages.Add(TlsPage); + + TlsPage.TryGetFreeTlsAddr(out Position); + } + + return Position; + } + + private void BreakHandler(object sender, AInstExceptionEventArgs e) + { + throw new GuestBrokeExecutionException(); + } + + private void UndefinedHandler(object sender, AInstUndefinedEventArgs e) + { + throw new UndefinedInstructionException(e.Position, e.RawOpCode); + } + + private void MakeSymbolTable() + { + SymbolTable = new Dictionary(); + + foreach (Executable Exe in Executables) + { + foreach (KeyValuePair KV in Exe.SymbolTable) + { + SymbolTable.TryAdd(Exe.ImageBase + KV.Key, KV.Value); + } + } + } + + private ATranslator GetTranslator() + { + if (Translator == null) + { + Translator = new ATranslator(SymbolTable); + + Translator.CpuTrace += CpuTraceHandler; + } + + return Translator; + } + + public void EnableCpuTracing() + { + Translator.EnableCpuTrace = true; + } + + public void DisableCpuTracing() + { + Translator.EnableCpuTrace = false; + } + + private void CpuTraceHandler(object sender, ACpuTraceEventArgs e) + { + string NsoName = string.Empty; + + for (int Index = Executables.Count - 1; Index >= 0; Index--) + { + if (e.Position >= Executables[Index].ImageBase) + { + NsoName = $"{(e.Position - Executables[Index].ImageBase):x16}"; + + break; + } + } + + Device.Log.PrintDebug(LogClass.Cpu, $"Executing at 0x{e.Position:x16} {e.SubName} {NsoName}"); + } + + public void PrintStackTrace(AThreadState ThreadState) + { + long[] Positions = ThreadState.GetCallStack(); + + StringBuilder Trace = new StringBuilder(); + + Trace.AppendLine("Guest stack trace:"); + + foreach (long Position in Positions) + { + if (!SymbolTable.TryGetValue(Position, out string SubName)) + { + SubName = $"Sub{Position:x16}"; + } + else if (SubName.StartsWith("_Z")) + { + SubName = Demangler.Parse(SubName); + } + + Trace.AppendLine(" " + SubName + " (" + GetNsoNameAndAddress(Position) + ")"); + } + + Device.Log.PrintInfo(LogClass.Cpu, Trace.ToString()); + } + + private string GetNsoNameAndAddress(long Position) + { + string Name = string.Empty; + + for (int Index = Executables.Count - 1; Index >= 0; Index--) + { + if (Position >= Executables[Index].ImageBase) + { + long Offset = Position - Executables[Index].ImageBase; + + Name = $"{Executables[Index].Name}:{Offset:x8}"; + + break; + } + } + + return Name; + } + + private void ThreadFinished(object sender, EventArgs e) + { + if (sender is AThread Thread) + { + Threads.TryRemove(Thread.ThreadState.Tpidr, out KThread KernelThread); + + Scheduler.RemoveThread(KernelThread); + + KernelThread.WaitEvent.Set(); + } + + if (Threads.Count == 0) + { + Device.System.ExitProcess(ProcessId); + } + } + + public KThread GetThread(long Tpidr) + { + if (!Threads.TryGetValue(Tpidr, out KThread Thread)) + { + throw new InvalidOperationException(); + } + + return Thread; + } + + private void Unload() + { + if (Disposed || Threads.Count > 0) + { + return; + } + + Disposed = true; + + foreach (object Obj in HandleTable.Clear()) + { + if (Obj is KSession Session) + { + Session.Dispose(); + } + } + + INvDrvServices.UnloadProcess(this); + + AppletState.Dispose(); + + if (NeedsHbAbi && Executables.Count > 0 && Executables[0].FilePath.EndsWith(Homebrew.TemporaryNroSuffix)) + { + File.Delete(Executables[0].FilePath); + } + + Device.Log.PrintInfo(LogClass.Loader, $"Process {ProcessId} exiting..."); + } + + public void Dispose() + { + Dispose(true); + } + + protected virtual void Dispose(bool Disposing) + { + if (Disposing) + { + if (Threads.Count > 0) + { + foreach (KThread Thread in Threads.Values) + { + Thread.Thread.StopExecution(); + + Scheduler.ForceWakeUp(Thread); + } + } + else + { + Unload(); + } + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/ServiceCtx.cs b/Ryujinx.HLE/HOS/ServiceCtx.cs new file mode 100644 index 00000000..d8c9fdf6 --- /dev/null +++ b/Ryujinx.HLE/HOS/ServiceCtx.cs @@ -0,0 +1,39 @@ +using ChocolArm64.Memory; +using Ryujinx.HLE.HOS.Ipc; +using Ryujinx.HLE.HOS.Kernel; +using System.IO; + +namespace Ryujinx.HLE.HOS +{ + class ServiceCtx + { + public Switch Device { get; private set; } + public Process Process { get; private set; } + public AMemory Memory { get; private set; } + public KSession Session { get; private set; } + public IpcMessage Request { get; private set; } + public IpcMessage Response { get; private set; } + public BinaryReader RequestData { get; private set; } + public BinaryWriter ResponseData { get; private set; } + + public ServiceCtx( + Switch Device, + Process Process, + AMemory Memory, + KSession Session, + IpcMessage Request, + IpcMessage Response, + BinaryReader RequestData, + BinaryWriter ResponseData) + { + this.Device = Device; + this.Process = Process; + this.Memory = Memory; + this.Session = Session; + this.Request = Request; + this.Response = Response; + this.RequestData = RequestData; + this.ResponseData = ResponseData; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Acc/AccErr.cs b/Ryujinx.HLE/HOS/Services/Acc/AccErr.cs new file mode 100644 index 00000000..144d6680 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Acc/AccErr.cs @@ -0,0 +1,7 @@ +namespace Ryujinx.HLE.HOS.Services.Acc +{ + static class AccErr + { + public const int UserNotFound = 100; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Acc/IAccountServiceForApplication.cs b/Ryujinx.HLE/HOS/Services/Acc/IAccountServiceForApplication.cs new file mode 100644 index 00000000..36dfd9ef --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Acc/IAccountServiceForApplication.cs @@ -0,0 +1,125 @@ +using Ryujinx.HLE.HOS.Ipc; +using Ryujinx.HLE.HOS.SystemState; +using Ryujinx.HLE.Logging; +using System.Collections.Generic; + +using static Ryujinx.HLE.HOS.ErrorCode; + +namespace Ryujinx.HLE.HOS.Services.Acc +{ + class IAccountServiceForApplication : IpcService + { + private Dictionary m_Commands; + + public override IReadOnlyDictionary Commands => m_Commands; + + public IAccountServiceForApplication() + { + m_Commands = new Dictionary() + { + { 0, GetUserCount }, + { 1, GetUserExistence }, + { 2, ListAllUsers }, + { 3, ListOpenUsers }, + { 4, GetLastOpenedUser }, + { 5, GetProfile }, + { 100, InitializeApplicationInfo }, + { 101, GetBaasAccountManagerForApplication } + }; + } + + public long GetUserCount(ServiceCtx Context) + { + Context.ResponseData.Write(Context.Device.System.State.GetUserCount()); + + return 0; + } + + public long GetUserExistence(ServiceCtx Context) + { + UserId Uuid = new UserId( + Context.RequestData.ReadInt64(), + Context.RequestData.ReadInt64()); + + Context.ResponseData.Write(Context.Device.System.State.TryGetUser(Uuid, out _) ? 1 : 0); + + return 0; + } + + public long ListAllUsers(ServiceCtx Context) + { + return WriteUserList(Context, Context.Device.System.State.GetAllUsers()); + } + + public long ListOpenUsers(ServiceCtx Context) + { + return WriteUserList(Context, Context.Device.System.State.GetOpenUsers()); + } + + private long WriteUserList(ServiceCtx Context, IEnumerable Profiles) + { + long OutputPosition = Context.Request.RecvListBuff[0].Position; + long OutputSize = Context.Request.RecvListBuff[0].Size; + + long Offset = 0; + + foreach (UserProfile Profile in Profiles) + { + if ((ulong)Offset + 16 > (ulong)OutputSize) + { + break; + } + + byte[] Uuid = Profile.Uuid.Bytes; + + for (int Index = Uuid.Length - 1; Index >= 0; Index--) + { + Context.Memory.WriteByte(OutputPosition + Offset++, Uuid[Index]); + } + } + + return 0; + } + + public long GetLastOpenedUser(ServiceCtx Context) + { + UserProfile LastOpened = Context.Device.System.State.LastOpenUser; + + LastOpened.Uuid.Write(Context.ResponseData); + + return 0; + } + + public long GetProfile(ServiceCtx Context) + { + UserId Uuid = new UserId( + Context.RequestData.ReadInt64(), + Context.RequestData.ReadInt64()); + + if (!Context.Device.System.State.TryGetUser(Uuid, out UserProfile Profile)) + { + Context.Device.Log.PrintWarning(LogClass.ServiceAcc, $"User 0x{Uuid} not found!"); + + return MakeError(ErrorModule.Account, AccErr.UserNotFound); + } + + MakeObject(Context, new IProfile(Profile)); + + return 0; + } + + public long InitializeApplicationInfo(ServiceCtx Context) + { + Context.Device.Log.PrintStub(LogClass.ServiceAcc, "Stubbed."); + + return 0; + } + + public long GetBaasAccountManagerForApplication(ServiceCtx Context) + { + MakeObject(Context, new IManagerForApplication()); + + return 0; + } + } +} diff --git a/Ryujinx.HLE/HOS/Services/Acc/IManagerForApplication.cs b/Ryujinx.HLE/HOS/Services/Acc/IManagerForApplication.cs new file mode 100644 index 00000000..813a1b17 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Acc/IManagerForApplication.cs @@ -0,0 +1,38 @@ +using Ryujinx.HLE.HOS.Ipc; +using Ryujinx.HLE.Logging; +using System.Collections.Generic; + +namespace Ryujinx.HLE.HOS.Services.Acc +{ + class IManagerForApplication : IpcService + { + private Dictionary m_Commands; + + public override IReadOnlyDictionary Commands => m_Commands; + + public IManagerForApplication() + { + m_Commands = new Dictionary() + { + { 0, CheckAvailability }, + { 1, GetAccountId } + }; + } + + public long CheckAvailability(ServiceCtx Context) + { + Context.Device.Log.PrintStub(LogClass.ServiceAcc, "Stubbed."); + + return 0; + } + + public long GetAccountId(ServiceCtx Context) + { + Context.Device.Log.PrintStub(LogClass.ServiceAcc, "Stubbed."); + + Context.ResponseData.Write(0xcafeL); + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Acc/IProfile.cs b/Ryujinx.HLE/HOS/Services/Acc/IProfile.cs new file mode 100644 index 00000000..960cc49c --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Acc/IProfile.cs @@ -0,0 +1,58 @@ +using ChocolArm64.Memory; +using Ryujinx.HLE.HOS.Ipc; +using Ryujinx.HLE.HOS.SystemState; +using Ryujinx.HLE.Logging; +using Ryujinx.HLE.Utilities; +using System.Collections.Generic; +using System.Text; + +namespace Ryujinx.HLE.HOS.Services.Acc +{ + class IProfile : IpcService + { + private Dictionary m_Commands; + + public override IReadOnlyDictionary Commands => m_Commands; + + private UserProfile Profile; + + public IProfile(UserProfile Profile) + { + m_Commands = new Dictionary() + { + { 0, Get }, + { 1, GetBase } + }; + + this.Profile = Profile; + } + + public long Get(ServiceCtx Context) + { + Context.Device.Log.PrintStub(LogClass.ServiceAcc, "Stubbed."); + + long Position = Context.Request.ReceiveBuff[0].Position; + + AMemoryHelper.FillWithZeros(Context.Memory, Position, 0x80); + + Context.Memory.WriteInt32(Position, 0); + Context.Memory.WriteInt32(Position + 4, 1); + Context.Memory.WriteInt64(Position + 8, 1); + + return GetBase(Context); + } + + public long GetBase(ServiceCtx Context) + { + Profile.Uuid.Write(Context.ResponseData); + + Context.ResponseData.Write(Profile.LastModifiedTimestamp); + + byte[] Username = StringUtils.GetFixedLengthBytes(Profile.Name, 0x20, Encoding.UTF8); + + Context.ResponseData.Write(Username); + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Am/AmErr.cs b/Ryujinx.HLE/HOS/Services/Am/AmErr.cs new file mode 100644 index 00000000..4e7771b8 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Am/AmErr.cs @@ -0,0 +1,7 @@ +namespace Ryujinx.HLE.HOS.Services.Am +{ + static class AmErr + { + public const int NoMessages = 3; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Am/FocusState.cs b/Ryujinx.HLE/HOS/Services/Am/FocusState.cs new file mode 100644 index 00000000..e8ae7223 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Am/FocusState.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Am +{ + enum FocusState + { + InFocus = 1, + OutOfFocus = 2 + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Am/IAllSystemAppletProxiesService.cs b/Ryujinx.HLE/HOS/Services/Am/IAllSystemAppletProxiesService.cs new file mode 100644 index 00000000..2d44526a --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Am/IAllSystemAppletProxiesService.cs @@ -0,0 +1,27 @@ +using Ryujinx.HLE.HOS.Ipc; +using System.Collections.Generic; + +namespace Ryujinx.HLE.HOS.Services.Am +{ + class IAllSystemAppletProxiesService : IpcService + { + private Dictionary m_Commands; + + public override IReadOnlyDictionary Commands => m_Commands; + + public IAllSystemAppletProxiesService() + { + m_Commands = new Dictionary() + { + { 100, OpenSystemAppletProxy } + }; + } + + public long OpenSystemAppletProxy(ServiceCtx Context) + { + MakeObject(Context, new ISystemAppletProxy()); + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Am/IApplicationCreator.cs b/Ryujinx.HLE/HOS/Services/Am/IApplicationCreator.cs new file mode 100644 index 00000000..c5ed09f5 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Am/IApplicationCreator.cs @@ -0,0 +1,20 @@ +using Ryujinx.HLE.HOS.Ipc; +using System.Collections.Generic; + +namespace Ryujinx.HLE.HOS.Services.Am +{ + class IApplicationCreator : IpcService + { + private Dictionary m_Commands; + + public override IReadOnlyDictionary Commands => m_Commands; + + public IApplicationCreator() + { + m_Commands = new Dictionary() + { + //... + }; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Am/IApplicationFunctions.cs b/Ryujinx.HLE/HOS/Services/Am/IApplicationFunctions.cs new file mode 100644 index 00000000..0a10d2a6 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Am/IApplicationFunctions.cs @@ -0,0 +1,117 @@ +using Ryujinx.HLE.HOS.Ipc; +using Ryujinx.HLE.Logging; +using System.Collections.Generic; + +namespace Ryujinx.HLE.HOS.Services.Am +{ + class IApplicationFunctions : IpcService + { + private Dictionary m_Commands; + + public override IReadOnlyDictionary Commands => m_Commands; + + public IApplicationFunctions() + { + m_Commands = new Dictionary() + { + { 1, PopLaunchParameter }, + { 20, EnsureSaveData }, + { 21, GetDesiredLanguage }, + { 22, SetTerminateResult }, + { 23, GetDisplayVersion }, + { 40, NotifyRunning }, + { 50, GetPseudoDeviceId }, + { 66, InitializeGamePlayRecording }, + { 67, SetGamePlayRecordingState } + }; + } + + public long PopLaunchParameter(ServiceCtx Context) + { + //Only the first 0x18 bytes of the Data seems to be actually used. + MakeObject(Context, new IStorage(StorageHelper.MakeLaunchParams())); + + return 0; + } + + public long EnsureSaveData(ServiceCtx Context) + { + long UIdLow = Context.RequestData.ReadInt64(); + long UIdHigh = Context.RequestData.ReadInt64(); + + Context.Device.Log.PrintStub(LogClass.ServiceAm, "Stubbed."); + + Context.ResponseData.Write(0L); + + return 0; + } + + public long GetDesiredLanguage(ServiceCtx Context) + { + Context.ResponseData.Write(Context.Device.System.State.DesiredLanguageCode); + + return 0; + } + + public long SetTerminateResult(ServiceCtx Context) + { + int ErrorCode = Context.RequestData.ReadInt32(); + + string Result = GetFormattedErrorCode(ErrorCode); + + Context.Device.Log.PrintInfo(LogClass.ServiceAm, $"Result = 0x{ErrorCode:x8} ({Result})."); + + return 0; + } + + private string GetFormattedErrorCode(int ErrorCode) + { + int Module = (ErrorCode >> 0) & 0x1ff; + int Description = (ErrorCode >> 9) & 0x1fff; + + return $"{(2000 + Module):d4}-{Description:d4}"; + } + + public long GetDisplayVersion(ServiceCtx Context) + { + //FIXME: Need to check correct version on a switch. + Context.ResponseData.Write(1L); + Context.ResponseData.Write(0L); + + return 0; + } + + public long NotifyRunning(ServiceCtx Context) + { + Context.ResponseData.Write(1); + + return 0; + } + + public long GetPseudoDeviceId(ServiceCtx Context) + { + Context.Device.Log.PrintStub(LogClass.ServiceAm, "Stubbed."); + + Context.ResponseData.Write(0L); + Context.ResponseData.Write(0L); + + return 0; + } + + public long InitializeGamePlayRecording(ServiceCtx Context) + { + Context.Device.Log.PrintStub(LogClass.ServiceAm, "Stubbed."); + + return 0; + } + + public long SetGamePlayRecordingState(ServiceCtx Context) + { + int State = Context.RequestData.ReadInt32(); + + Context.Device.Log.PrintStub(LogClass.ServiceAm, "Stubbed."); + + return 0; + } + } +} diff --git a/Ryujinx.HLE/HOS/Services/Am/IApplicationProxy.cs b/Ryujinx.HLE/HOS/Services/Am/IApplicationProxy.cs new file mode 100644 index 00000000..4003f151 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Am/IApplicationProxy.cs @@ -0,0 +1,83 @@ +using Ryujinx.HLE.HOS.Ipc; +using System.Collections.Generic; + +namespace Ryujinx.HLE.HOS.Services.Am +{ + class IApplicationProxy : IpcService + { + private Dictionary m_Commands; + + public override IReadOnlyDictionary Commands => m_Commands; + + public IApplicationProxy() + { + m_Commands = new Dictionary() + { + { 0, GetCommonStateGetter }, + { 1, GetSelfController }, + { 2, GetWindowController }, + { 3, GetAudioController }, + { 4, GetDisplayController }, + { 11, GetLibraryAppletCreator }, + { 20, GetApplicationFunctions }, + { 1000, GetDebugFunctions } + }; + } + + public long GetCommonStateGetter(ServiceCtx Context) + { + MakeObject(Context, new ICommonStateGetter()); + + return 0; + } + + public long GetSelfController(ServiceCtx Context) + { + MakeObject(Context, new ISelfController()); + + return 0; + } + + public long GetWindowController(ServiceCtx Context) + { + MakeObject(Context, new IWindowController()); + + return 0; + } + + public long GetAudioController(ServiceCtx Context) + { + MakeObject(Context, new IAudioController()); + + return 0; + } + + public long GetDisplayController(ServiceCtx Context) + { + MakeObject(Context, new IDisplayController()); + + return 0; + } + + public long GetLibraryAppletCreator(ServiceCtx Context) + { + MakeObject(Context, new ILibraryAppletCreator()); + + return 0; + } + + public long GetApplicationFunctions(ServiceCtx Context) + { + MakeObject(Context, new IApplicationFunctions()); + + return 0; + } + + public long GetDebugFunctions(ServiceCtx Context) + { + MakeObject(Context, new IDebugFunctions()); + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Am/IApplicationProxyService.cs b/Ryujinx.HLE/HOS/Services/Am/IApplicationProxyService.cs new file mode 100644 index 00000000..fb518af9 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Am/IApplicationProxyService.cs @@ -0,0 +1,27 @@ +using Ryujinx.HLE.HOS.Ipc; +using System.Collections.Generic; + +namespace Ryujinx.HLE.HOS.Services.Am +{ + class IApplicationProxyService : IpcService + { + private Dictionary m_Commands; + + public override IReadOnlyDictionary Commands => m_Commands; + + public IApplicationProxyService() + { + m_Commands = new Dictionary() + { + { 0, OpenApplicationProxy } + }; + } + + public long OpenApplicationProxy(ServiceCtx Context) + { + MakeObject(Context, new IApplicationProxy()); + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Am/IAudioController.cs b/Ryujinx.HLE/HOS/Services/Am/IAudioController.cs new file mode 100644 index 00000000..8968ad72 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Am/IAudioController.cs @@ -0,0 +1,72 @@ +using Ryujinx.HLE.HOS.Ipc; +using Ryujinx.HLE.Logging; +using System.Collections.Generic; + +namespace Ryujinx.HLE.HOS.Services.Am +{ + class IAudioController : IpcService + { + private Dictionary m_Commands; + + public override IReadOnlyDictionary Commands => m_Commands; + + public IAudioController() + { + m_Commands = new Dictionary() + { + { 0, SetExpectedMasterVolume }, + { 1, GetMainAppletExpectedMasterVolume }, + { 2, GetLibraryAppletExpectedMasterVolume }, + { 3, ChangeMainAppletMasterVolume }, + { 4, SetTransparentVolumeRate } + }; + } + + public long SetExpectedMasterVolume(ServiceCtx Context) + { + float AppletVolume = Context.RequestData.ReadSingle(); + float LibraryAppletVolume = Context.RequestData.ReadSingle(); + + Context.Device.Log.PrintStub(LogClass.ServiceAm, "Stubbed."); + + return 0; + } + + public long GetMainAppletExpectedMasterVolume(ServiceCtx Context) + { + Context.ResponseData.Write(1f); + + Context.Device.Log.PrintStub(LogClass.ServiceAm, "Stubbed."); + + return 0; + } + + public long GetLibraryAppletExpectedMasterVolume(ServiceCtx Context) + { + Context.ResponseData.Write(1f); + + Context.Device.Log.PrintStub(LogClass.ServiceAm, "Stubbed."); + + return 0; + } + + public long ChangeMainAppletMasterVolume(ServiceCtx Context) + { + float Unknown0 = Context.RequestData.ReadSingle(); + long Unknown1 = Context.RequestData.ReadInt64(); + + Context.Device.Log.PrintStub(LogClass.ServiceAm, "Stubbed."); + + return 0; + } + + public long SetTransparentVolumeRate(ServiceCtx Context) + { + float Unknown0 = Context.RequestData.ReadSingle(); + + Context.Device.Log.PrintStub(LogClass.ServiceAm, "Stubbed."); + + return 0; + } + } +} diff --git a/Ryujinx.HLE/HOS/Services/Am/ICommonStateGetter.cs b/Ryujinx.HLE/HOS/Services/Am/ICommonStateGetter.cs new file mode 100644 index 00000000..3cdfbbdb --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Am/ICommonStateGetter.cs @@ -0,0 +1,115 @@ +using Ryujinx.HLE.HOS.Ipc; +using Ryujinx.HLE.HOS.Kernel; +using Ryujinx.HLE.Logging; +using System.Collections.Generic; + +using static Ryujinx.HLE.HOS.ErrorCode; + +namespace Ryujinx.HLE.HOS.Services.Am +{ + class ICommonStateGetter : IpcService + { + private Dictionary m_Commands; + + public override IReadOnlyDictionary Commands => m_Commands; + + private KEvent DisplayResolutionChangeEvent; + + public ICommonStateGetter() + { + m_Commands = new Dictionary() + { + { 0, GetEventHandle }, + { 1, ReceiveMessage }, + { 5, GetOperationMode }, + { 6, GetPerformanceMode }, + { 8, GetBootMode }, + { 9, GetCurrentFocusState }, + { 60, GetDefaultDisplayResolution }, + { 61, GetDefaultDisplayResolutionChangeEvent } + }; + + DisplayResolutionChangeEvent = new KEvent(); + } + + public long GetEventHandle(ServiceCtx Context) + { + KEvent Event = Context.Process.AppletState.MessageEvent; + + int Handle = Context.Process.HandleTable.OpenHandle(Event); + + Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle); + + return 0; + } + + public long ReceiveMessage(ServiceCtx Context) + { + if (!Context.Process.AppletState.TryDequeueMessage(out MessageInfo Message)) + { + return MakeError(ErrorModule.Am, AmErr.NoMessages); + } + + Context.ResponseData.Write((int)Message); + + return 0; + } + + public long GetOperationMode(ServiceCtx Context) + { + OperationMode Mode = Context.Device.System.State.DockedMode + ? OperationMode.Docked + : OperationMode.Handheld; + + Context.ResponseData.Write((byte)Mode); + + return 0; + } + + public long GetPerformanceMode(ServiceCtx Context) + { + Apm.PerformanceMode Mode = Context.Device.System.State.DockedMode + ? Apm.PerformanceMode.Docked + : Apm.PerformanceMode.Handheld; + + Context.ResponseData.Write((int)Mode); + + return 0; + } + + public long GetBootMode(ServiceCtx Context) + { + Context.ResponseData.Write((byte)0); //Unknown value. + + Context.Device.Log.PrintStub(LogClass.ServiceAm, "Stubbed."); + + return 0; + } + + public long GetCurrentFocusState(ServiceCtx Context) + { + Context.ResponseData.Write((byte)Context.Process.AppletState.FocusState); + + return 0; + } + + public long GetDefaultDisplayResolution(ServiceCtx Context) + { + Context.ResponseData.Write(1280); + Context.ResponseData.Write(720); + + return 0; + } + + public long GetDefaultDisplayResolutionChangeEvent(ServiceCtx Context) + { + int Handle = Context.Process.HandleTable.OpenHandle(DisplayResolutionChangeEvent); + + Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle); + + Context.Device.Log.PrintStub(LogClass.ServiceAm, "Stubbed."); + + return 0; + } + } +} diff --git a/Ryujinx.HLE/HOS/Services/Am/IDebugFunctions.cs b/Ryujinx.HLE/HOS/Services/Am/IDebugFunctions.cs new file mode 100644 index 00000000..d86743c0 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Am/IDebugFunctions.cs @@ -0,0 +1,20 @@ +using Ryujinx.HLE.HOS.Ipc; +using System.Collections.Generic; + +namespace Ryujinx.HLE.HOS.Services.Am +{ + class IDebugFunctions : IpcService + { + private Dictionary m_Commands; + + public override IReadOnlyDictionary Commands => m_Commands; + + public IDebugFunctions() + { + m_Commands = new Dictionary() + { + //... + }; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Am/IDisplayController.cs b/Ryujinx.HLE/HOS/Services/Am/IDisplayController.cs new file mode 100644 index 00000000..c4d49579 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Am/IDisplayController.cs @@ -0,0 +1,20 @@ +using Ryujinx.HLE.HOS.Ipc; +using System.Collections.Generic; + +namespace Ryujinx.HLE.HOS.Services.Am +{ + class IDisplayController : IpcService + { + private Dictionary m_Commands; + + public override IReadOnlyDictionary Commands => m_Commands; + + public IDisplayController() + { + m_Commands = new Dictionary() + { + //... + }; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Am/IGlobalStateController.cs b/Ryujinx.HLE/HOS/Services/Am/IGlobalStateController.cs new file mode 100644 index 00000000..e646327f --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Am/IGlobalStateController.cs @@ -0,0 +1,20 @@ +using Ryujinx.HLE.HOS.Ipc; +using System.Collections.Generic; + +namespace Ryujinx.HLE.HOS.Services.Am +{ + class IGlobalStateController : IpcService + { + private Dictionary m_Commands; + + public override IReadOnlyDictionary Commands => m_Commands; + + public IGlobalStateController() + { + m_Commands = new Dictionary() + { + //... + }; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Am/IHomeMenuFunctions.cs b/Ryujinx.HLE/HOS/Services/Am/IHomeMenuFunctions.cs new file mode 100644 index 00000000..95028ca0 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Am/IHomeMenuFunctions.cs @@ -0,0 +1,46 @@ +using Ryujinx.HLE.HOS.Ipc; +using Ryujinx.HLE.HOS.Kernel; +using Ryujinx.HLE.Logging; +using System.Collections.Generic; + +namespace Ryujinx.HLE.HOS.Services.Am +{ + class IHomeMenuFunctions : IpcService + { + private Dictionary m_Commands; + + public override IReadOnlyDictionary Commands => m_Commands; + + private KEvent ChannelEvent; + + public IHomeMenuFunctions() + { + m_Commands = new Dictionary() + { + { 10, RequestToGetForeground }, + { 21, GetPopFromGeneralChannelEvent } + }; + + //ToDo: Signal this Event somewhere in future. + ChannelEvent = new KEvent(); + } + + public long RequestToGetForeground(ServiceCtx Context) + { + Context.Device.Log.PrintStub(LogClass.ServiceAm, "Stubbed."); + + return 0; + } + + public long GetPopFromGeneralChannelEvent(ServiceCtx Context) + { + int Handle = Context.Process.HandleTable.OpenHandle(ChannelEvent); + + Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle); + + Context.Device.Log.PrintStub(LogClass.ServiceAm, "Stubbed."); + + return 0; + } + } +} diff --git a/Ryujinx.HLE/HOS/Services/Am/ILibraryAppletAccessor.cs b/Ryujinx.HLE/HOS/Services/Am/ILibraryAppletAccessor.cs new file mode 100644 index 00000000..e099ec64 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Am/ILibraryAppletAccessor.cs @@ -0,0 +1,71 @@ +using Ryujinx.HLE.HOS.Ipc; +using Ryujinx.HLE.HOS.Kernel; +using Ryujinx.HLE.Logging; +using System.Collections.Generic; + +namespace Ryujinx.HLE.HOS.Services.Am +{ + class ILibraryAppletAccessor : IpcService + { + private Dictionary m_Commands; + + public override IReadOnlyDictionary Commands => m_Commands; + + private KEvent StateChangedEvent; + + public ILibraryAppletAccessor() + { + m_Commands = new Dictionary() + { + { 0, GetAppletStateChangedEvent }, + { 10, Start }, + { 30, GetResult }, + { 100, PushInData }, + { 101, PopOutData } + }; + + StateChangedEvent = new KEvent(); + } + + public long GetAppletStateChangedEvent(ServiceCtx Context) + { + StateChangedEvent.WaitEvent.Set(); + + int Handle = Context.Process.HandleTable.OpenHandle(StateChangedEvent); + + Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle); + + Context.Device.Log.PrintStub(LogClass.ServiceAm, "Stubbed."); + + return 0; + } + + public long Start(ServiceCtx Context) + { + Context.Device.Log.PrintStub(LogClass.ServiceAm, "Stubbed."); + + return 0; + } + + public long GetResult(ServiceCtx Context) + { + Context.Device.Log.PrintStub(LogClass.ServiceAm, "Stubbed."); + + return 0; + } + + public long PushInData(ServiceCtx Context) + { + Context.Device.Log.PrintStub(LogClass.ServiceAm, "Stubbed."); + + return 0; + } + + public long PopOutData(ServiceCtx Context) + { + MakeObject(Context, new IStorage(StorageHelper.MakeLaunchParams())); + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Am/ILibraryAppletCreator.cs b/Ryujinx.HLE/HOS/Services/Am/ILibraryAppletCreator.cs new file mode 100644 index 00000000..065574c7 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Am/ILibraryAppletCreator.cs @@ -0,0 +1,37 @@ +using Ryujinx.HLE.HOS.Ipc; +using System.Collections.Generic; + +namespace Ryujinx.HLE.HOS.Services.Am +{ + class ILibraryAppletCreator : IpcService + { + private Dictionary m_Commands; + + public override IReadOnlyDictionary Commands => m_Commands; + + public ILibraryAppletCreator() + { + m_Commands = new Dictionary() + { + { 0, CreateLibraryApplet }, + { 10, CreateStorage } + }; + } + + public long CreateLibraryApplet(ServiceCtx Context) + { + MakeObject(Context, new ILibraryAppletAccessor()); + + return 0; + } + + public long CreateStorage(ServiceCtx Context) + { + long Size = Context.RequestData.ReadInt64(); + + MakeObject(Context, new IStorage(new byte[Size])); + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Am/ISelfController.cs b/Ryujinx.HLE/HOS/Services/Am/ISelfController.cs new file mode 100644 index 00000000..ccd96e0d --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Am/ISelfController.cs @@ -0,0 +1,145 @@ +using Ryujinx.HLE.HOS.Ipc; +using Ryujinx.HLE.HOS.Kernel; +using Ryujinx.HLE.Logging; +using System.Collections.Generic; + +namespace Ryujinx.HLE.HOS.Services.Am +{ + class ISelfController : IpcService + { + private Dictionary m_Commands; + + public override IReadOnlyDictionary Commands => m_Commands; + + private KEvent LaunchableEvent; + + public ISelfController() + { + m_Commands = new Dictionary() + { + { 0, Exit }, + { 1, LockExit }, + { 2, UnlockExit }, + { 9, GetLibraryAppletLaunchableEvent }, + { 10, SetScreenShotPermission }, + { 11, SetOperationModeChangedNotification }, + { 12, SetPerformanceModeChangedNotification }, + { 13, SetFocusHandlingMode }, + { 14, SetRestartMessageEnabled }, + { 16, SetOutOfFocusSuspendingEnabled }, + { 19, SetScreenShotImageOrientation }, + { 50, SetHandlesRequestToDisplay } + }; + + LaunchableEvent = new KEvent(); + } + + public long Exit(ServiceCtx Context) + { + Context.Device.Log.PrintStub(LogClass.ServiceAm, "Stubbed."); + + return 0; + } + + public long LockExit(ServiceCtx Context) + { + Context.Device.Log.PrintStub(LogClass.ServiceAm, "Stubbed."); + + return 0; + } + + public long UnlockExit(ServiceCtx Context) + { + Context.Device.Log.PrintStub(LogClass.ServiceAm, "Stubbed."); + + return 0; + } + + public long GetLibraryAppletLaunchableEvent(ServiceCtx Context) + { + LaunchableEvent.WaitEvent.Set(); + + int Handle = Context.Process.HandleTable.OpenHandle(LaunchableEvent); + + Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle); + + Context.Device.Log.PrintStub(LogClass.ServiceAm, "Stubbed."); + + return 0; + } + + public long SetScreenShotPermission(ServiceCtx Context) + { + bool Enable = Context.RequestData.ReadByte() != 0 ? true : false; + + Context.Device.Log.PrintStub(LogClass.ServiceAm, "Stubbed."); + + return 0; + } + + public long SetOperationModeChangedNotification(ServiceCtx Context) + { + bool Enable = Context.RequestData.ReadByte() != 0 ? true : false; + + Context.Device.Log.PrintStub(LogClass.ServiceAm, "Stubbed."); + + return 0; + } + + public long SetPerformanceModeChangedNotification(ServiceCtx Context) + { + bool Enable = Context.RequestData.ReadByte() != 0 ? true : false; + + Context.Device.Log.PrintStub(LogClass.ServiceAm, "Stubbed."); + + return 0; + } + + public long SetFocusHandlingMode(ServiceCtx Context) + { + bool Flag1 = Context.RequestData.ReadByte() != 0 ? true : false; + bool Flag2 = Context.RequestData.ReadByte() != 0 ? true : false; + bool Flag3 = Context.RequestData.ReadByte() != 0 ? true : false; + + Context.Device.Log.PrintStub(LogClass.ServiceAm, "Stubbed."); + + return 0; + } + + public long SetRestartMessageEnabled(ServiceCtx Context) + { + bool Enable = Context.RequestData.ReadByte() != 0 ? true : false; + + Context.Device.Log.PrintStub(LogClass.ServiceAm, "Stubbed."); + + return 0; + } + + public long SetOutOfFocusSuspendingEnabled(ServiceCtx Context) + { + bool Enable = Context.RequestData.ReadByte() != 0 ? true : false; + + Context.Device.Log.PrintStub(LogClass.ServiceAm, "Stubbed."); + + return 0; + } + + public long SetScreenShotImageOrientation(ServiceCtx Context) + { + int Orientation = Context.RequestData.ReadInt32(); + + Context.Device.Log.PrintStub(LogClass.ServiceAm, "Stubbed."); + + return 0; + } + + public long SetHandlesRequestToDisplay(ServiceCtx Context) + { + bool Enable = Context.RequestData.ReadByte() != 0 ? true : false; + + Context.Device.Log.PrintStub(LogClass.ServiceAm, "Stubbed."); + + return 0; + } + } +} diff --git a/Ryujinx.HLE/HOS/Services/Am/IStorage.cs b/Ryujinx.HLE/HOS/Services/Am/IStorage.cs new file mode 100644 index 00000000..10778122 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Am/IStorage.cs @@ -0,0 +1,31 @@ +using Ryujinx.HLE.HOS.Ipc; +using System.Collections.Generic; + +namespace Ryujinx.HLE.HOS.Services.Am +{ + class IStorage : IpcService + { + private Dictionary m_Commands; + + public override IReadOnlyDictionary Commands => m_Commands; + + public byte[] Data { get; private set; } + + public IStorage(byte[] Data) + { + m_Commands = new Dictionary() + { + { 0, Open } + }; + + this.Data = Data; + } + + public long Open(ServiceCtx Context) + { + MakeObject(Context, new IStorageAccessor(this)); + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Am/IStorageAccessor.cs b/Ryujinx.HLE/HOS/Services/Am/IStorageAccessor.cs new file mode 100644 index 00000000..a60cf149 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Am/IStorageAccessor.cs @@ -0,0 +1,83 @@ +using Ryujinx.HLE.HOS.Ipc; +using System; +using System.Collections.Generic; + +namespace Ryujinx.HLE.HOS.Services.Am +{ + class IStorageAccessor : IpcService + { + private Dictionary m_Commands; + + public override IReadOnlyDictionary Commands => m_Commands; + + private IStorage Storage; + + public IStorageAccessor(IStorage Storage) + { + m_Commands = new Dictionary() + { + { 0, GetSize }, + { 10, Write }, + { 11, Read } + }; + + this.Storage = Storage; + } + + public long GetSize(ServiceCtx Context) + { + Context.ResponseData.Write((long)Storage.Data.Length); + + return 0; + } + + public long Write(ServiceCtx Context) + { + //TODO: Error conditions. + long WritePosition = Context.RequestData.ReadInt64(); + + (long Position, long Size) = Context.Request.GetBufferType0x21(); + + if (Size > 0) + { + long MaxSize = Storage.Data.Length - WritePosition; + + if (Size > MaxSize) + { + Size = MaxSize; + } + + byte[] Data = Context.Memory.ReadBytes(Position, Size); + + Buffer.BlockCopy(Data, 0, Storage.Data, (int)WritePosition, (int)Size); + } + + return 0; + } + + public long Read(ServiceCtx Context) + { + //TODO: Error conditions. + long ReadPosition = Context.RequestData.ReadInt64(); + + (long Position, long Size) = Context.Request.GetBufferType0x22(); + + byte[] Data; + + if (Storage.Data.Length > Size) + { + Data = new byte[Size]; + + Buffer.BlockCopy(Storage.Data, 0, Data, 0, (int)Size); + } + else + { + Data = Storage.Data; + } + + Context.Memory.WriteBytes(Position, Data); + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Am/ISystemAppletProxy.cs b/Ryujinx.HLE/HOS/Services/Am/ISystemAppletProxy.cs new file mode 100644 index 00000000..c08d4018 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Am/ISystemAppletProxy.cs @@ -0,0 +1,99 @@ +using Ryujinx.HLE.HOS.Ipc; +using System.Collections.Generic; + +namespace Ryujinx.HLE.HOS.Services.Am +{ + class ISystemAppletProxy : IpcService + { + private Dictionary m_Commands; + + public override IReadOnlyDictionary Commands => m_Commands; + + public ISystemAppletProxy() + { + m_Commands = new Dictionary() + { + { 0, GetCommonStateGetter }, + { 1, GetSelfController }, + { 2, GetWindowController }, + { 3, GetAudioController }, + { 4, GetDisplayController }, + { 11, GetLibraryAppletCreator }, + { 20, GetHomeMenuFunctions }, + { 21, GetGlobalStateController }, + { 22, GetApplicationCreator }, + { 1000, GetDebugFunctions } + }; + } + + public long GetCommonStateGetter(ServiceCtx Context) + { + MakeObject(Context, new ICommonStateGetter()); + + return 0; + } + + public long GetSelfController(ServiceCtx Context) + { + MakeObject(Context, new ISelfController()); + + return 0; + } + + public long GetWindowController(ServiceCtx Context) + { + MakeObject(Context, new IWindowController()); + + return 0; + } + + public long GetAudioController(ServiceCtx Context) + { + MakeObject(Context, new IAudioController()); + + return 0; + } + + public long GetDisplayController(ServiceCtx Context) + { + MakeObject(Context, new IDisplayController()); + + return 0; + } + + public long GetLibraryAppletCreator(ServiceCtx Context) + { + MakeObject(Context, new ILibraryAppletCreator()); + + return 0; + } + + public long GetHomeMenuFunctions(ServiceCtx Context) + { + MakeObject(Context, new IHomeMenuFunctions()); + + return 0; + } + + public long GetGlobalStateController(ServiceCtx Context) + { + MakeObject(Context, new IGlobalStateController()); + + return 0; + } + + public long GetApplicationCreator(ServiceCtx Context) + { + MakeObject(Context, new IApplicationCreator()); + + return 0; + } + + public long GetDebugFunctions(ServiceCtx Context) + { + MakeObject(Context, new IDebugFunctions()); + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Am/IWindowController.cs b/Ryujinx.HLE/HOS/Services/Am/IWindowController.cs new file mode 100644 index 00000000..1a5a716f --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Am/IWindowController.cs @@ -0,0 +1,38 @@ +using Ryujinx.HLE.HOS.Ipc; +using Ryujinx.HLE.Logging; +using System.Collections.Generic; + +namespace Ryujinx.HLE.HOS.Services.Am +{ + class IWindowController : IpcService + { + private Dictionary m_Commands; + + public override IReadOnlyDictionary Commands => m_Commands; + + public IWindowController() + { + m_Commands = new Dictionary() + { + { 1, GetAppletResourceUserId }, + { 10, AcquireForegroundRights } + }; + } + + public long GetAppletResourceUserId(ServiceCtx Context) + { + Context.Device.Log.PrintStub(LogClass.ServiceAm, "Stubbed."); + + Context.ResponseData.Write(0L); + + return 0; + } + + public long AcquireForegroundRights(ServiceCtx Context) + { + Context.Device.Log.PrintStub(LogClass.ServiceAm, "Stubbed."); + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Am/MessageInfo.cs b/Ryujinx.HLE/HOS/Services/Am/MessageInfo.cs new file mode 100644 index 00000000..65fddbed --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Am/MessageInfo.cs @@ -0,0 +1,9 @@ +namespace Ryujinx.HLE.HOS.Services.Am +{ + enum MessageInfo + { + FocusStateChanged = 0xf, + OperationModeChanged = 0x1e, + PerformanceModeChanged = 0x1f + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Am/OperationMode.cs b/Ryujinx.HLE/HOS/Services/Am/OperationMode.cs new file mode 100644 index 00000000..cb11fff9 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Am/OperationMode.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Am +{ + enum OperationMode + { + Handheld = 0, + Docked = 1 + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Am/StorageHelper.cs b/Ryujinx.HLE/HOS/Services/Am/StorageHelper.cs new file mode 100644 index 00000000..b97ffc1e --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Am/StorageHelper.cs @@ -0,0 +1,27 @@ +using System.IO; + +namespace Ryujinx.HLE.HOS.Services.Am +{ + class StorageHelper + { + private const uint LaunchParamsMagic = 0xc79497ca; + + public static byte[] MakeLaunchParams() + { + //Size needs to be at least 0x88 bytes otherwise application errors. + using (MemoryStream MS = new MemoryStream()) + { + BinaryWriter Writer = new BinaryWriter(MS); + + MS.SetLength(0x88); + + Writer.Write(LaunchParamsMagic); + Writer.Write(1); //IsAccountSelected? Only lower 8 bits actually used. + Writer.Write(1L); //User Id Low (note: User Id needs to be != 0) + Writer.Write(0L); //User Id High + + return MS.ToArray(); + } + } + } +} diff --git a/Ryujinx.HLE/HOS/Services/Apm/IManager.cs b/Ryujinx.HLE/HOS/Services/Apm/IManager.cs new file mode 100644 index 00000000..50822def --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Apm/IManager.cs @@ -0,0 +1,27 @@ +using Ryujinx.HLE.HOS.Ipc; +using System.Collections.Generic; + +namespace Ryujinx.HLE.HOS.Services.Apm +{ + class IManager : IpcService + { + private Dictionary m_Commands; + + public override IReadOnlyDictionary Commands => m_Commands; + + public IManager() + { + m_Commands = new Dictionary() + { + { 0, OpenSession } + }; + } + + public long OpenSession(ServiceCtx Context) + { + MakeObject(Context, new ISession()); + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Apm/ISession.cs b/Ryujinx.HLE/HOS/Services/Apm/ISession.cs new file mode 100644 index 00000000..739e264d --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Apm/ISession.cs @@ -0,0 +1,41 @@ +using Ryujinx.HLE.HOS.Ipc; +using Ryujinx.HLE.Logging; +using System.Collections.Generic; + +namespace Ryujinx.HLE.HOS.Services.Apm +{ + class ISession : IpcService + { + private Dictionary m_Commands; + + public override IReadOnlyDictionary Commands => m_Commands; + + public ISession() + { + m_Commands = new Dictionary() + { + { 0, SetPerformanceConfiguration }, + { 1, GetPerformanceConfiguration } + }; + } + + public long SetPerformanceConfiguration(ServiceCtx Context) + { + PerformanceMode PerfMode = (PerformanceMode)Context.RequestData.ReadInt32(); + PerformanceConfiguration PerfConfig = (PerformanceConfiguration)Context.RequestData.ReadInt32(); + + return 0; + } + + public long GetPerformanceConfiguration(ServiceCtx Context) + { + PerformanceMode PerfMode = (PerformanceMode)Context.RequestData.ReadInt32(); + + Context.ResponseData.Write((uint)PerformanceConfiguration.PerformanceConfiguration1); + + Context.Device.Log.PrintStub(LogClass.ServiceApm, "Stubbed."); + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Apm/PerformanceConfiguration.cs b/Ryujinx.HLE/HOS/Services/Apm/PerformanceConfiguration.cs new file mode 100644 index 00000000..b24adfb3 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Apm/PerformanceConfiguration.cs @@ -0,0 +1,18 @@ +namespace Ryujinx.HLE.HOS.Services.Apm +{ + enum PerformanceConfiguration : uint + { + PerformanceConfiguration1 = 0x00010000, + PerformanceConfiguration2 = 0x00010001, + PerformanceConfiguration3 = 0x00010002, + PerformanceConfiguration4 = 0x00020000, + PerformanceConfiguration5 = 0x00020001, + PerformanceConfiguration6 = 0x00020002, + PerformanceConfiguration7 = 0x00020003, + PerformanceConfiguration8 = 0x00020004, + PerformanceConfiguration9 = 0x00020005, + PerformanceConfiguration10 = 0x00020006, + PerformanceConfiguration11 = 0x92220007, + PerformanceConfiguration12 = 0x92220008 + } +} diff --git a/Ryujinx.HLE/HOS/Services/Apm/PerformanceMode.cs b/Ryujinx.HLE/HOS/Services/Apm/PerformanceMode.cs new file mode 100644 index 00000000..c4ab3cf2 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Apm/PerformanceMode.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Apm +{ + enum PerformanceMode + { + Handheld = 0, + Docked = 1 + } +} diff --git a/Ryujinx.HLE/HOS/Services/Aud/AudErr.cs b/Ryujinx.HLE/HOS/Services/Aud/AudErr.cs new file mode 100644 index 00000000..cecea860 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Aud/AudErr.cs @@ -0,0 +1,9 @@ +namespace Ryujinx.HLE.HOS.Services.Aud +{ + static class AudErr + { + public const int DeviceNotFound = 1; + public const int UnsupportedRevision = 2; + public const int UnsupportedSampleRate = 3; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Aud/AudioOut/AudioOutData.cs b/Ryujinx.HLE/HOS/Services/Aud/AudioOut/AudioOutData.cs new file mode 100644 index 00000000..e25ebe66 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Aud/AudioOut/AudioOutData.cs @@ -0,0 +1,14 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Aud.AudioOut +{ + [StructLayout(LayoutKind.Sequential)] + struct AudioOutData + { + public long NextBufferPtr; + public long SampleBufferPtr; + public long SampleBufferCapacity; + public long SampleBufferSize; + public long SampleBufferInnerOffset; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Aud/AudioOut/IAudioOut.cs b/Ryujinx.HLE/HOS/Services/Aud/AudioOut/IAudioOut.cs new file mode 100644 index 00000000..81561f04 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Aud/AudioOut/IAudioOut.cs @@ -0,0 +1,163 @@ +using ChocolArm64.Memory; +using Ryujinx.Audio; +using Ryujinx.HLE.HOS.Ipc; +using Ryujinx.HLE.HOS.Kernel; +using System; +using System.Collections.Generic; + +namespace Ryujinx.HLE.HOS.Services.Aud.AudioOut +{ + class IAudioOut : IpcService, IDisposable + { + private Dictionary m_Commands; + + public override IReadOnlyDictionary Commands => m_Commands; + + private IAalOutput AudioOut; + + private KEvent ReleaseEvent; + + private int Track; + + public IAudioOut(IAalOutput AudioOut, KEvent ReleaseEvent, int Track) + { + m_Commands = new Dictionary() + { + { 0, GetAudioOutState }, + { 1, StartAudioOut }, + { 2, StopAudioOut }, + { 3, AppendAudioOutBuffer }, + { 4, RegisterBufferEvent }, + { 5, GetReleasedAudioOutBuffer }, + { 6, ContainsAudioOutBuffer }, + { 7, AppendAudioOutBufferAuto }, + { 8, GetReleasedAudioOutBufferAuto } + }; + + this.AudioOut = AudioOut; + this.ReleaseEvent = ReleaseEvent; + this.Track = Track; + } + + public long GetAudioOutState(ServiceCtx Context) + { + Context.ResponseData.Write((int)AudioOut.GetState(Track)); + + return 0; + } + + public long StartAudioOut(ServiceCtx Context) + { + AudioOut.Start(Track); + + return 0; + } + + public long StopAudioOut(ServiceCtx Context) + { + AudioOut.Stop(Track); + + return 0; + } + + public long AppendAudioOutBuffer(ServiceCtx Context) + { + return AppendAudioOutBufferImpl(Context, Context.Request.SendBuff[0].Position); + } + + public long RegisterBufferEvent(ServiceCtx Context) + { + int Handle = Context.Process.HandleTable.OpenHandle(ReleaseEvent); + + Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle); + + return 0; + } + + public long GetReleasedAudioOutBuffer(ServiceCtx Context) + { + long Position = Context.Request.ReceiveBuff[0].Position; + long Size = Context.Request.ReceiveBuff[0].Size; + + return GetReleasedAudioOutBufferImpl(Context, Position, Size); + } + + public long ContainsAudioOutBuffer(ServiceCtx Context) + { + long Tag = Context.RequestData.ReadInt64(); + + Context.ResponseData.Write(AudioOut.ContainsBuffer(Track, Tag) ? 1 : 0); + + return 0; + } + + public long AppendAudioOutBufferAuto(ServiceCtx Context) + { + (long Position, long Size) = Context.Request.GetBufferType0x21(); + + return AppendAudioOutBufferImpl(Context, Position); + } + + public long AppendAudioOutBufferImpl(ServiceCtx Context, long Position) + { + long Tag = Context.RequestData.ReadInt64(); + + AudioOutData Data = AMemoryHelper.Read( + Context.Memory, + Position); + + byte[] Buffer = Context.Memory.ReadBytes( + Data.SampleBufferPtr, + Data.SampleBufferSize); + + AudioOut.AppendBuffer(Track, Tag, Buffer); + + return 0; + } + + public long GetReleasedAudioOutBufferAuto(ServiceCtx Context) + { + (long Position, long Size) = Context.Request.GetBufferType0x22(); + + return GetReleasedAudioOutBufferImpl(Context, Position, Size); + } + + public long GetReleasedAudioOutBufferImpl(ServiceCtx Context, long Position, long Size) + { + uint Count = (uint)((ulong)Size >> 3); + + long[] ReleasedBuffers = AudioOut.GetReleasedBuffers(Track, (int)Count); + + for (uint Index = 0; Index < Count; Index++) + { + long Tag = 0; + + if (Index < ReleasedBuffers.Length) + { + Tag = ReleasedBuffers[Index]; + } + + Context.Memory.WriteInt64(Position + Index * 8, Tag); + } + + Context.ResponseData.Write(ReleasedBuffers.Length); + + return 0; + } + + public void Dispose() + { + Dispose(true); + } + + protected virtual void Dispose(bool Disposing) + { + if (Disposing) + { + AudioOut.CloseTrack(Track); + + ReleaseEvent.Dispose(); + } + } + } +} diff --git a/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/AudioConsts.cs b/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/AudioConsts.cs new file mode 100644 index 00000000..773ef6dd --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/AudioConsts.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Aud.AudioRenderer +{ + static class AudioConsts + { + public const int HostSampleRate = 48000; + public const int HostChannelsCount = 2; + } +} diff --git a/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/BehaviorIn.cs b/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/BehaviorIn.cs new file mode 100644 index 00000000..69b6d522 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/BehaviorIn.cs @@ -0,0 +1,11 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Aud.AudioRenderer +{ + [StructLayout(LayoutKind.Sequential, Size = 0x10, Pack = 4)] + struct BehaviorIn + { + public long Unknown0; + public long Unknown8; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/BiquadFilter.cs b/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/BiquadFilter.cs new file mode 100644 index 00000000..51dddf20 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/BiquadFilter.cs @@ -0,0 +1,16 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Aud.AudioRenderer +{ + [StructLayout(LayoutKind.Sequential, Size = 0xc, Pack = 1)] + struct BiquadFilter + { + public byte Enable; + public byte Padding; + public short B0; + public short B1; + public short B2; + public short A1; + public short A2; + } +} diff --git a/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/IAudioRenderer.cs b/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/IAudioRenderer.cs new file mode 100644 index 00000000..8c83338d --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/IAudioRenderer.cs @@ -0,0 +1,318 @@ +using ChocolArm64.Memory; +using Ryujinx.Audio; +using Ryujinx.Audio.Adpcm; +using Ryujinx.HLE.HOS.Ipc; +using Ryujinx.HLE.HOS.Kernel; +using Ryujinx.HLE.Logging; +using Ryujinx.HLE.Utilities; +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Aud.AudioRenderer +{ + class IAudioRenderer : IpcService, IDisposable + { + //This is the amount of samples that are going to be appended + //each time that RequestUpdateAudioRenderer is called. Ideally, + //this value shouldn't be neither too small (to avoid the player + //starving due to running out of samples) or too large (to avoid + //high latency). + private const int MixBufferSamplesCount = 960; + + private Dictionary m_Commands; + + public override IReadOnlyDictionary Commands => m_Commands; + + private KEvent UpdateEvent; + + private AMemory Memory; + + private IAalOutput AudioOut; + + private AudioRendererParameter Params; + + private MemoryPoolContext[] MemoryPools; + + private VoiceContext[] Voices; + + private int Track; + + public IAudioRenderer(AMemory Memory, IAalOutput AudioOut, AudioRendererParameter Params) + { + m_Commands = new Dictionary() + { + { 4, RequestUpdateAudioRenderer }, + { 5, StartAudioRenderer }, + { 6, StopAudioRenderer }, + { 7, QuerySystemEvent } + }; + + UpdateEvent = new KEvent(); + + this.Memory = Memory; + this.AudioOut = AudioOut; + this.Params = Params; + + Track = AudioOut.OpenTrack( + AudioConsts.HostSampleRate, + AudioConsts.HostChannelsCount, + AudioCallback); + + MemoryPools = CreateArray(Params.EffectCount + Params.VoiceCount * 4); + + Voices = CreateArray(Params.VoiceCount); + + InitializeAudioOut(); + } + + private void AudioCallback() + { + UpdateEvent.WaitEvent.Set(); + } + + private static T[] CreateArray(int Size) where T : new() + { + T[] Output = new T[Size]; + + for (int Index = 0; Index < Size; Index++) + { + Output[Index] = new T(); + } + + return Output; + } + + private void InitializeAudioOut() + { + AppendMixedBuffer(0); + AppendMixedBuffer(1); + AppendMixedBuffer(2); + + AudioOut.Start(Track); + } + + public long RequestUpdateAudioRenderer(ServiceCtx Context) + { + long OutputPosition = Context.Request.ReceiveBuff[0].Position; + long OutputSize = Context.Request.ReceiveBuff[0].Size; + + AMemoryHelper.FillWithZeros(Context.Memory, OutputPosition, (int)OutputSize); + + long InputPosition = Context.Request.SendBuff[0].Position; + + StructReader Reader = new StructReader(Context.Memory, InputPosition); + StructWriter Writer = new StructWriter(Context.Memory, OutputPosition); + + UpdateDataHeader InputHeader = Reader.Read(); + + Reader.Read(InputHeader.BehaviorSize); + + MemoryPoolIn[] MemoryPoolsIn = Reader.Read(InputHeader.MemoryPoolSize); + + for (int Index = 0; Index < MemoryPoolsIn.Length; Index++) + { + MemoryPoolIn MemoryPool = MemoryPoolsIn[Index]; + + if (MemoryPool.State == MemoryPoolState.RequestAttach) + { + MemoryPools[Index].OutStatus.State = MemoryPoolState.Attached; + } + else if (MemoryPool.State == MemoryPoolState.RequestDetach) + { + MemoryPools[Index].OutStatus.State = MemoryPoolState.Detached; + } + } + + Reader.Read(InputHeader.VoiceResourceSize); + + VoiceIn[] VoicesIn = Reader.Read(InputHeader.VoiceSize); + + for (int Index = 0; Index < VoicesIn.Length; Index++) + { + VoiceIn Voice = VoicesIn[Index]; + + VoiceContext VoiceCtx = Voices[Index]; + + VoiceCtx.SetAcquireState(Voice.Acquired != 0); + + if (Voice.Acquired == 0) + { + continue; + } + + if (Voice.FirstUpdate != 0) + { + VoiceCtx.AdpcmCtx = GetAdpcmDecoderContext( + Voice.AdpcmCoeffsPosition, + Voice.AdpcmCoeffsSize); + + VoiceCtx.SampleFormat = Voice.SampleFormat; + VoiceCtx.SampleRate = Voice.SampleRate; + VoiceCtx.ChannelsCount = Voice.ChannelsCount; + + VoiceCtx.SetBufferIndex(Voice.BaseWaveBufferIndex); + } + + VoiceCtx.WaveBuffers[0] = Voice.WaveBuffer0; + VoiceCtx.WaveBuffers[1] = Voice.WaveBuffer1; + VoiceCtx.WaveBuffers[2] = Voice.WaveBuffer2; + VoiceCtx.WaveBuffers[3] = Voice.WaveBuffer3; + VoiceCtx.Volume = Voice.Volume; + VoiceCtx.PlayState = Voice.PlayState; + } + + UpdateAudio(); + + UpdateDataHeader OutputHeader = new UpdateDataHeader(); + + int UpdateHeaderSize = Marshal.SizeOf(); + + OutputHeader.Revision = IAudioRendererManager.RevMagic; + OutputHeader.BehaviorSize = 0xb0; + OutputHeader.MemoryPoolSize = (Params.EffectCount + Params.VoiceCount * 4) * 0x10; + OutputHeader.VoiceSize = Params.VoiceCount * 0x10; + OutputHeader.EffectSize = Params.EffectCount * 0x10; + OutputHeader.SinkSize = Params.SinkCount * 0x20; + OutputHeader.PerformanceManagerSize = 0x10; + OutputHeader.TotalSize = UpdateHeaderSize + + OutputHeader.BehaviorSize + + OutputHeader.MemoryPoolSize + + OutputHeader.VoiceSize + + OutputHeader.EffectSize + + OutputHeader.SinkSize + + OutputHeader.PerformanceManagerSize; + + Writer.Write(OutputHeader); + + foreach (MemoryPoolContext MemoryPool in MemoryPools) + { + Writer.Write(MemoryPool.OutStatus); + } + + foreach (VoiceContext Voice in Voices) + { + Writer.Write(Voice.OutStatus); + } + + return 0; + } + + public long StartAudioRenderer(ServiceCtx Context) + { + Context.Device.Log.PrintStub(LogClass.ServiceAudio, "Stubbed."); + + return 0; + } + + public long StopAudioRenderer(ServiceCtx Context) + { + Context.Device.Log.PrintStub(LogClass.ServiceAudio, "Stubbed."); + + return 0; + } + + public long QuerySystemEvent(ServiceCtx Context) + { + int Handle = Context.Process.HandleTable.OpenHandle(UpdateEvent); + + Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle); + + return 0; + } + + private AdpcmDecoderContext GetAdpcmDecoderContext(long Position, long Size) + { + if (Size == 0) + { + return null; + } + + AdpcmDecoderContext Context = new AdpcmDecoderContext(); + + Context.Coefficients = new short[Size >> 1]; + + for (int Offset = 0; Offset < Size; Offset += 2) + { + Context.Coefficients[Offset >> 1] = Memory.ReadInt16(Position + Offset); + } + + return Context; + } + + private void UpdateAudio() + { + long[] Released = AudioOut.GetReleasedBuffers(Track, 2); + + for (int Index = 0; Index < Released.Length; Index++) + { + AppendMixedBuffer(Released[Index]); + } + } + + private void AppendMixedBuffer(long Tag) + { + int[] MixBuffer = new int[MixBufferSamplesCount * AudioConsts.HostChannelsCount]; + + foreach (VoiceContext Voice in Voices) + { + if (!Voice.Playing) + { + continue; + } + + int OutOffset = 0; + + int PendingSamples = MixBufferSamplesCount; + + while (PendingSamples > 0) + { + int[] Samples = Voice.GetBufferData(Memory, PendingSamples, out int ReturnedSamples); + + if (ReturnedSamples == 0) + { + break; + } + + PendingSamples -= ReturnedSamples; + + for (int Offset = 0; Offset < Samples.Length; Offset++) + { + int Sample = (int)(Samples[Offset] * Voice.Volume); + + MixBuffer[OutOffset++] += Sample; + } + } + } + + AudioOut.AppendBuffer(Track, Tag, GetFinalBuffer(MixBuffer)); + } + + private static short[] GetFinalBuffer(int[] Buffer) + { + short[] Output = new short[Buffer.Length]; + + for (int Offset = 0; Offset < Buffer.Length; Offset++) + { + Output[Offset] = DspUtils.Saturate(Buffer[Offset]); + } + + return Output; + } + + public void Dispose() + { + Dispose(true); + } + + protected virtual void Dispose(bool Disposing) + { + if (Disposing) + { + AudioOut.CloseTrack(Track); + + UpdateEvent.Dispose(); + } + } + } +} diff --git a/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/MemoryPoolContext.cs b/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/MemoryPoolContext.cs new file mode 100644 index 00000000..2b68c40d --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/MemoryPoolContext.cs @@ -0,0 +1,12 @@ +namespace Ryujinx.HLE.HOS.Services.Aud.AudioRenderer +{ + class MemoryPoolContext + { + public MemoryPoolOut OutStatus; + + public MemoryPoolContext() + { + OutStatus.State = MemoryPoolState.Detached; + } + } +} diff --git a/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/MemoryPoolIn.cs b/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/MemoryPoolIn.cs new file mode 100644 index 00000000..f6e424ee --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/MemoryPoolIn.cs @@ -0,0 +1,14 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Aud.AudioRenderer +{ + [StructLayout(LayoutKind.Sequential, Size = 0x20, Pack = 4)] + struct MemoryPoolIn + { + public long Address; + public long Size; + public MemoryPoolState State; + public int Unknown14; + public long Unknown18; + } +} diff --git a/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/MemoryPoolOut.cs b/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/MemoryPoolOut.cs new file mode 100644 index 00000000..f0621e3e --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/MemoryPoolOut.cs @@ -0,0 +1,12 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Aud.AudioRenderer +{ + [StructLayout(LayoutKind.Sequential, Size = 0x10, Pack = 4)] + struct MemoryPoolOut + { + public MemoryPoolState State; + public int Unknown14; + public long Unknown18; + } +} diff --git a/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/MemoryPoolState.cs b/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/MemoryPoolState.cs new file mode 100644 index 00000000..6baf507c --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/MemoryPoolState.cs @@ -0,0 +1,13 @@ +namespace Ryujinx.HLE.HOS.Services.Aud.AudioRenderer +{ + enum MemoryPoolState : int + { + Invalid = 0, + Unknown = 1, + RequestDetach = 2, + Detached = 3, + RequestAttach = 4, + Attached = 5, + Released = 6 + } +} diff --git a/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/PlayState.cs b/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/PlayState.cs new file mode 100644 index 00000000..f09bf46e --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/PlayState.cs @@ -0,0 +1,9 @@ +namespace Ryujinx.HLE.HOS.Services.Aud.AudioRenderer +{ + enum PlayState : byte + { + Playing = 0, + Stopped = 1, + Paused = 2 + } +} diff --git a/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/Resampler.cs b/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/Resampler.cs new file mode 100644 index 00000000..baa0bc62 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/Resampler.cs @@ -0,0 +1,191 @@ +using System; + +namespace Ryujinx.HLE.HOS.Services.Aud.AudioRenderer +{ + static class Resampler + { +#region "LookUp Tables" + private static short[] CurveLut0 = new short[] + { + 6600, 19426, 6722, 3, 6479, 19424, 6845, 9, 6359, 19419, 6968, 15, 6239, 19412, 7093, 22, + 6121, 19403, 7219, 28, 6004, 19391, 7345, 34, 5888, 19377, 7472, 41, 5773, 19361, 7600, 48, + 5659, 19342, 7728, 55, 5546, 19321, 7857, 62, 5434, 19298, 7987, 69, 5323, 19273, 8118, 77, + 5213, 19245, 8249, 84, 5104, 19215, 8381, 92, 4997, 19183, 8513, 101, 4890, 19148, 8646, 109, + 4785, 19112, 8780, 118, 4681, 19073, 8914, 127, 4579, 19031, 9048, 137, 4477, 18988, 9183, 147, + 4377, 18942, 9318, 157, 4277, 18895, 9454, 168, 4179, 18845, 9590, 179, 4083, 18793, 9726, 190, + 3987, 18738, 9863, 202, 3893, 18682, 10000, 215, 3800, 18624, 10137, 228, 3709, 18563, 10274, 241, + 3618, 18500, 10411, 255, 3529, 18436, 10549, 270, 3441, 18369, 10687, 285, 3355, 18300, 10824, 300, + 3269, 18230, 10962, 317, 3186, 18157, 11100, 334, 3103, 18082, 11238, 351, 3022, 18006, 11375, 369, + 2942, 17927, 11513, 388, 2863, 17847, 11650, 408, 2785, 17765, 11788, 428, 2709, 17681, 11925, 449, + 2635, 17595, 12062, 471, 2561, 17507, 12198, 494, 2489, 17418, 12334, 517, 2418, 17327, 12470, 541, + 2348, 17234, 12606, 566, 2280, 17140, 12741, 592, 2213, 17044, 12876, 619, 2147, 16946, 13010, 647, + 2083, 16846, 13144, 675, 2020, 16745, 13277, 704, 1958, 16643, 13409, 735, 1897, 16539, 13541, 766, + 1838, 16434, 13673, 798, 1780, 16327, 13803, 832, 1723, 16218, 13933, 866, 1667, 16109, 14062, 901, + 1613, 15998, 14191, 937, 1560, 15885, 14318, 975, 1508, 15772, 14445, 1013, 1457, 15657, 14571, 1052, + 1407, 15540, 14695, 1093, 1359, 15423, 14819, 1134, 1312, 15304, 14942, 1177, 1266, 15185, 15064, 1221, + 1221, 15064, 15185, 1266, 1177, 14942, 15304, 1312, 1134, 14819, 15423, 1359, 1093, 14695, 15540, 1407, + 1052, 14571, 15657, 1457, 1013, 14445, 15772, 1508, 975, 14318, 15885, 1560, 937, 14191, 15998, 1613, + 901, 14062, 16109, 1667, 866, 13933, 16218, 1723, 832, 13803, 16327, 1780, 798, 13673, 16434, 1838, + 766, 13541, 16539, 1897, 735, 13409, 16643, 1958, 704, 13277, 16745, 2020, 675, 13144, 16846, 2083, + 647, 13010, 16946, 2147, 619, 12876, 17044, 2213, 592, 12741, 17140, 2280, 566, 12606, 17234, 2348, + 541, 12470, 17327, 2418, 517, 12334, 17418, 2489, 494, 12198, 17507, 2561, 471, 12062, 17595, 2635, + 449, 11925, 17681, 2709, 428, 11788, 17765, 2785, 408, 11650, 17847, 2863, 388, 11513, 17927, 2942, + 369, 11375, 18006, 3022, 351, 11238, 18082, 3103, 334, 11100, 18157, 3186, 317, 10962, 18230, 3269, + 300, 10824, 18300, 3355, 285, 10687, 18369, 3441, 270, 10549, 18436, 3529, 255, 10411, 18500, 3618, + 241, 10274, 18563, 3709, 228, 10137, 18624, 3800, 215, 10000, 18682, 3893, 202, 9863, 18738, 3987, + 190, 9726, 18793, 4083, 179, 9590, 18845, 4179, 168, 9454, 18895, 4277, 157, 9318, 18942, 4377, + 147, 9183, 18988, 4477, 137, 9048, 19031, 4579, 127, 8914, 19073, 4681, 118, 8780, 19112, 4785, + 109, 8646, 19148, 4890, 101, 8513, 19183, 4997, 92, 8381, 19215, 5104, 84, 8249, 19245, 5213, + 77, 8118, 19273, 5323, 69, 7987, 19298, 5434, 62, 7857, 19321, 5546, 55, 7728, 19342, 5659, + 48, 7600, 19361, 5773, 41, 7472, 19377, 5888, 34, 7345, 19391, 6004, 28, 7219, 19403, 6121, + 22, 7093, 19412, 6239, 15, 6968, 19419, 6359, 9, 6845, 19424, 6479, 3, 6722, 19426, 6600 + }; + + private static short[] CurveLut1 = new short[] + { + -68, 32639, 69, -5, -200, 32630, 212, -15, -328, 32613, 359, -26, -450, 32586, 512, -36, + -568, 32551, 669, -47, -680, 32507, 832, -58, -788, 32454, 1000, -69, -891, 32393, 1174, -80, + -990, 32323, 1352, -92, -1084, 32244, 1536, -103, -1173, 32157, 1724, -115, -1258, 32061, 1919, -128, + -1338, 31956, 2118, -140, -1414, 31844, 2322, -153, -1486, 31723, 2532, -167, -1554, 31593, 2747, -180, + -1617, 31456, 2967, -194, -1676, 31310, 3192, -209, -1732, 31157, 3422, -224, -1783, 30995, 3657, -240, + -1830, 30826, 3897, -256, -1874, 30649, 4143, -272, -1914, 30464, 4393, -289, -1951, 30272, 4648, -307, + -1984, 30072, 4908, -325, -2014, 29866, 5172, -343, -2040, 29652, 5442, -362, -2063, 29431, 5716, -382, + -2083, 29203, 5994, -403, -2100, 28968, 6277, -424, -2114, 28727, 6565, -445, -2125, 28480, 6857, -468, + -2133, 28226, 7153, -490, -2139, 27966, 7453, -514, -2142, 27700, 7758, -538, -2142, 27428, 8066, -563, + -2141, 27151, 8378, -588, -2136, 26867, 8694, -614, -2130, 26579, 9013, -641, -2121, 26285, 9336, -668, + -2111, 25987, 9663, -696, -2098, 25683, 9993, -724, -2084, 25375, 10326, -753, -2067, 25063, 10662, -783, + -2049, 24746, 11000, -813, -2030, 24425, 11342, -844, -2009, 24100, 11686, -875, -1986, 23771, 12033, -907, + -1962, 23438, 12382, -939, -1937, 23103, 12733, -972, -1911, 22764, 13086, -1005, -1883, 22422, 13441, -1039, + -1855, 22077, 13798, -1072, -1825, 21729, 14156, -1107, -1795, 21380, 14516, -1141, -1764, 21027, 14877, -1176, + -1732, 20673, 15239, -1211, -1700, 20317, 15602, -1246, -1667, 19959, 15965, -1282, -1633, 19600, 16329, -1317, + -1599, 19239, 16694, -1353, -1564, 18878, 17058, -1388, -1530, 18515, 17423, -1424, -1495, 18151, 17787, -1459, + -1459, 17787, 18151, -1495, -1424, 17423, 18515, -1530, -1388, 17058, 18878, -1564, -1353, 16694, 19239, -1599, + -1317, 16329, 19600, -1633, -1282, 15965, 19959, -1667, -1246, 15602, 20317, -1700, -1211, 15239, 20673, -1732, + -1176, 14877, 21027, -1764, -1141, 14516, 21380, -1795, -1107, 14156, 21729, -1825, -1072, 13798, 22077, -1855, + -1039, 13441, 22422, -1883, -1005, 13086, 22764, -1911, -972, 12733, 23103, -1937, -939, 12382, 23438, -1962, + -907, 12033, 23771, -1986, -875, 11686, 24100, -2009, -844, 11342, 24425, -2030, -813, 11000, 24746, -2049, + -783, 10662, 25063, -2067, -753, 10326, 25375, -2084, -724, 9993, 25683, -2098, -696, 9663, 25987, -2111, + -668, 9336, 26285, -2121, -641, 9013, 26579, -2130, -614, 8694, 26867, -2136, -588, 8378, 27151, -2141, + -563, 8066, 27428, -2142, -538, 7758, 27700, -2142, -514, 7453, 27966, -2139, -490, 7153, 28226, -2133, + -468, 6857, 28480, -2125, -445, 6565, 28727, -2114, -424, 6277, 28968, -2100, -403, 5994, 29203, -2083, + -382, 5716, 29431, -2063, -362, 5442, 29652, -2040, -343, 5172, 29866, -2014, -325, 4908, 30072, -1984, + -307, 4648, 30272, -1951, -289, 4393, 30464, -1914, -272, 4143, 30649, -1874, -256, 3897, 30826, -1830, + -240, 3657, 30995, -1783, -224, 3422, 31157, -1732, -209, 3192, 31310, -1676, -194, 2967, 31456, -1617, + -180, 2747, 31593, -1554, -167, 2532, 31723, -1486, -153, 2322, 31844, -1414, -140, 2118, 31956, -1338, + -128, 1919, 32061, -1258, -115, 1724, 32157, -1173, -103, 1536, 32244, -1084, -92, 1352, 32323, -990, + -80, 1174, 32393, -891, -69, 1000, 32454, -788, -58, 832, 32507, -680, -47, 669, 32551, -568, + -36, 512, 32586, -450, -26, 359, 32613, -328, -15, 212, 32630, -200, -5, 69, 32639, -68 + }; + + private static short[] CurveLut2 = new short[] + { + 3195, 26287, 3329, -32, 3064, 26281, 3467, -34, 2936, 26270, 3608, -38, 2811, 26253, 3751, -42, + 2688, 26230, 3897, -46, 2568, 26202, 4046, -50, 2451, 26169, 4199, -54, 2338, 26130, 4354, -58, + 2227, 26085, 4512, -63, 2120, 26035, 4673, -67, 2015, 25980, 4837, -72, 1912, 25919, 5004, -76, + 1813, 25852, 5174, -81, 1716, 25780, 5347, -87, 1622, 25704, 5522, -92, 1531, 25621, 5701, -98, + 1442, 25533, 5882, -103, 1357, 25440, 6066, -109, 1274, 25342, 6253, -115, 1193, 25239, 6442, -121, + 1115, 25131, 6635, -127, 1040, 25018, 6830, -133, 967, 24899, 7027, -140, 897, 24776, 7227, -146, + 829, 24648, 7430, -153, 764, 24516, 7635, -159, 701, 24379, 7842, -166, 641, 24237, 8052, -174, + 583, 24091, 8264, -181, 526, 23940, 8478, -187, 472, 23785, 8695, -194, 420, 23626, 8914, -202, + 371, 23462, 9135, -209, 324, 23295, 9358, -215, 279, 23123, 9583, -222, 236, 22948, 9809, -230, + 194, 22769, 10038, -237, 154, 22586, 10269, -243, 117, 22399, 10501, -250, 81, 22208, 10735, -258, + 47, 22015, 10970, -265, 15, 21818, 11206, -271, -16, 21618, 11444, -277, -44, 21415, 11684, -283, + -71, 21208, 11924, -290, -97, 20999, 12166, -296, -121, 20786, 12409, -302, -143, 20571, 12653, -306, + -163, 20354, 12898, -311, -183, 20134, 13143, -316, -201, 19911, 13389, -321, -218, 19686, 13635, -325, + -234, 19459, 13882, -328, -248, 19230, 14130, -332, -261, 18998, 14377, -335, -273, 18765, 14625, -337, + -284, 18531, 14873, -339, -294, 18295, 15121, -341, -302, 18057, 15369, -341, -310, 17817, 15617, -341, + -317, 17577, 15864, -340, -323, 17335, 16111, -340, -328, 17092, 16357, -338, -332, 16848, 16603, -336, + -336, 16603, 16848, -332, -338, 16357, 17092, -328, -340, 16111, 17335, -323, -340, 15864, 17577, -317, + -341, 15617, 17817, -310, -341, 15369, 18057, -302, -341, 15121, 18295, -294, -339, 14873, 18531, -284, + -337, 14625, 18765, -273, -335, 14377, 18998, -261, -332, 14130, 19230, -248, -328, 13882, 19459, -234, + -325, 13635, 19686, -218, -321, 13389, 19911, -201, -316, 13143, 20134, -183, -311, 12898, 20354, -163, + -306, 12653, 20571, -143, -302, 12409, 20786, -121, -296, 12166, 20999, -97, -290, 11924, 21208, -71, + -283, 11684, 21415, -44, -277, 11444, 21618, -16, -271, 11206, 21818, 15, -265, 10970, 22015, 47, + -258, 10735, 22208, 81, -250, 10501, 22399, 117, -243, 10269, 22586, 154, -237, 10038, 22769, 194, + -230, 9809, 22948, 236, -222, 9583, 23123, 279, -215, 9358, 23295, 324, -209, 9135, 23462, 371, + -202, 8914, 23626, 420, -194, 8695, 23785, 472, -187, 8478, 23940, 526, -181, 8264, 24091, 583, + -174, 8052, 24237, 641, -166, 7842, 24379, 701, -159, 7635, 24516, 764, -153, 7430, 24648, 829, + -146, 7227, 24776, 897, -140, 7027, 24899, 967, -133, 6830, 25018, 1040, -127, 6635, 25131, 1115, + -121, 6442, 25239, 1193, -115, 6253, 25342, 1274, -109, 6066, 25440, 1357, -103, 5882, 25533, 1442, + -98, 5701, 25621, 1531, -92, 5522, 25704, 1622, -87, 5347, 25780, 1716, -81, 5174, 25852, 1813, + -76, 5004, 25919, 1912, -72, 4837, 25980, 2015, -67, 4673, 26035, 2120, -63, 4512, 26085, 2227, + -58, 4354, 26130, 2338, -54, 4199, 26169, 2451, -50, 4046, 26202, 2568, -46, 3897, 26230, 2688, + -42, 3751, 26253, 2811, -38, 3608, 26270, 2936, -34, 3467, 26281, 3064, -32, 3329, 26287, 3195 + }; +#endregion + + public static int[] Resample2Ch( + int[] Buffer, + int SrcSampleRate, + int DstSampleRate, + int SamplesCount, + ref int FracPart) + { + if (Buffer == null) + { + throw new ArgumentNullException(nameof(Buffer)); + } + + if (SrcSampleRate <= 0) + { + throw new ArgumentOutOfRangeException(nameof(SrcSampleRate)); + } + + if (DstSampleRate <= 0) + { + throw new ArgumentOutOfRangeException(nameof(DstSampleRate)); + } + + double Ratio = (double)SrcSampleRate / DstSampleRate; + + int NewSamplesCount = (int)(SamplesCount / Ratio); + + int Step = (int)(Ratio * 0x8000); + + int[] Output = new int[NewSamplesCount * 2]; + + short[] Lut; + + if (Step > 0xaaaa) + { + Lut = CurveLut0; + } + else if (Step <= 0x8000) + { + Lut = CurveLut1; + } + else + { + Lut = CurveLut2; + } + + int InOffs = 0; + + for (int OutOffs = 0; OutOffs < Output.Length; OutOffs += 2) + { + int LutIndex = (FracPart >> 8) * 4; + + int Sample0 = Buffer[(InOffs + 0) * 2 + 0] * Lut[LutIndex + 0] + + Buffer[(InOffs + 1) * 2 + 0] * Lut[LutIndex + 1] + + Buffer[(InOffs + 2) * 2 + 0] * Lut[LutIndex + 2] + + Buffer[(InOffs + 3) * 2 + 0] * Lut[LutIndex + 3]; + + int Sample1 = Buffer[(InOffs + 0) * 2 + 1] * Lut[LutIndex + 0] + + Buffer[(InOffs + 1) * 2 + 1] * Lut[LutIndex + 1] + + Buffer[(InOffs + 2) * 2 + 1] * Lut[LutIndex + 2] + + Buffer[(InOffs + 3) * 2 + 1] * Lut[LutIndex + 3]; + + int NewOffset = FracPart + Step; + + InOffs += NewOffset >> 15; + + FracPart = NewOffset & 0x7fff; + + Output[OutOffs + 0] = Sample0 >> 15; + Output[OutOffs + 1] = Sample1 >> 15; + } + + return Output; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/UpdateDataHeader.cs b/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/UpdateDataHeader.cs new file mode 100644 index 00000000..a71e865d --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/UpdateDataHeader.cs @@ -0,0 +1,22 @@ +namespace Ryujinx.HLE.HOS.Services.Aud.AudioRenderer +{ + struct UpdateDataHeader + { + public int Revision; + public int BehaviorSize; + public int MemoryPoolSize; + public int VoiceSize; + public int VoiceResourceSize; + public int EffectSize; + public int MixeSize; + public int SinkSize; + public int PerformanceManagerSize; + public int Unknown24; + public int Unknown28; + public int Unknown2C; + public int Unknown30; + public int Unknown34; + public int Unknown38; + public int TotalSize; + } +} diff --git a/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/VoiceChannelResourceIn.cs b/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/VoiceChannelResourceIn.cs new file mode 100644 index 00000000..2a6f424f --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/VoiceChannelResourceIn.cs @@ -0,0 +1,10 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Aud.AudioRenderer +{ + [StructLayout(LayoutKind.Sequential, Size = 0x70, Pack = 1)] + struct VoiceChannelResourceIn + { + //??? + } +} diff --git a/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/VoiceContext.cs b/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/VoiceContext.cs new file mode 100644 index 00000000..bee574ff --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/VoiceContext.cs @@ -0,0 +1,188 @@ +using ChocolArm64.Memory; +using Ryujinx.Audio.Adpcm; +using System; + +namespace Ryujinx.HLE.HOS.Services.Aud.AudioRenderer +{ + class VoiceContext + { + private bool Acquired; + private bool BufferReload; + + private int ResamplerFracPart; + + private int BufferIndex; + private int Offset; + + public int SampleRate; + public int ChannelsCount; + + public float Volume; + + public PlayState PlayState; + + public SampleFormat SampleFormat; + + public AdpcmDecoderContext AdpcmCtx; + + public WaveBuffer[] WaveBuffers; + + public VoiceOut OutStatus; + + private int[] Samples; + + public bool Playing => Acquired && PlayState == PlayState.Playing; + + public VoiceContext() + { + WaveBuffers = new WaveBuffer[4]; + } + + public void SetAcquireState(bool NewState) + { + if (Acquired && !NewState) + { + //Release. + Reset(); + } + + Acquired = NewState; + } + + private void Reset() + { + BufferReload = true; + + BufferIndex = 0; + Offset = 0; + + OutStatus.PlayedSamplesCount = 0; + OutStatus.PlayedWaveBuffersCount = 0; + OutStatus.VoiceDropsCount = 0; + } + + public int[] GetBufferData(AMemory Memory, int MaxSamples, out int SamplesCount) + { + if (!Playing) + { + SamplesCount = 0; + + return null; + } + + if (BufferReload) + { + BufferReload = false; + + UpdateBuffer(Memory); + } + + WaveBuffer Wb = WaveBuffers[BufferIndex]; + + int MaxSize = Samples.Length - Offset; + + int Size = MaxSamples * AudioConsts.HostChannelsCount; + + if (Size > MaxSize) + { + Size = MaxSize; + } + + int[] Output = new int[Size]; + + Array.Copy(Samples, Offset, Output, 0, Size); + + SamplesCount = Size / AudioConsts.HostChannelsCount; + + OutStatus.PlayedSamplesCount += SamplesCount; + + Offset += Size; + + if (Offset == Samples.Length) + { + Offset = 0; + + if (Wb.Looping == 0) + { + SetBufferIndex((BufferIndex + 1) & 3); + } + + OutStatus.PlayedWaveBuffersCount++; + + if (Wb.LastBuffer != 0) + { + PlayState = PlayState.Paused; + } + } + + return Output; + } + + private void UpdateBuffer(AMemory Memory) + { + //TODO: Implement conversion for formats other + //than interleaved stereo (2 channels). + //As of now, it assumes that HostChannelsCount == 2. + WaveBuffer Wb = WaveBuffers[BufferIndex]; + + if (SampleFormat == SampleFormat.PcmInt16) + { + int SamplesCount = (int)(Wb.Size / (sizeof(short) * ChannelsCount)); + + Samples = new int[SamplesCount * AudioConsts.HostChannelsCount]; + + if (ChannelsCount == 1) + { + for (int Index = 0; Index < SamplesCount; Index++) + { + short Sample = Memory.ReadInt16(Wb.Position + Index * 2); + + Samples[Index * 2 + 0] = Sample; + Samples[Index * 2 + 1] = Sample; + } + } + else + { + for (int Index = 0; Index < SamplesCount * 2; Index++) + { + Samples[Index] = Memory.ReadInt16(Wb.Position + Index * 2); + } + } + } + else if (SampleFormat == SampleFormat.Adpcm) + { + byte[] Buffer = Memory.ReadBytes(Wb.Position, Wb.Size); + + Samples = AdpcmDecoder.Decode(Buffer, AdpcmCtx); + } + else + { + throw new InvalidOperationException(); + } + + if (SampleRate != AudioConsts.HostSampleRate) + { + //TODO: We should keep the frames being discarded (see the 4 below) + //on a buffer and include it on the next samples buffer, to allow + //the resampler to do seamless interpolation between wave buffers. + int SamplesCount = Samples.Length / AudioConsts.HostChannelsCount; + + SamplesCount = Math.Max(SamplesCount - 4, 0); + + Samples = Resampler.Resample2Ch( + Samples, + SampleRate, + AudioConsts.HostSampleRate, + SamplesCount, + ref ResamplerFracPart); + } + } + + public void SetBufferIndex(int Index) + { + BufferIndex = Index & 3; + + BufferReload = true; + } + } +} diff --git a/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/VoiceIn.cs b/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/VoiceIn.cs new file mode 100644 index 00000000..fc83b65b --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/VoiceIn.cs @@ -0,0 +1,49 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Aud.AudioRenderer +{ + [StructLayout(LayoutKind.Sequential, Size = 0x170, Pack = 1)] + struct VoiceIn + { + public int VoiceSlot; + public int NodeId; + + public byte FirstUpdate; + public byte Acquired; + + public PlayState PlayState; + + public SampleFormat SampleFormat; + + public int SampleRate; + + public int Priority; + + public int Unknown14; + + public int ChannelsCount; + + public float Pitch; + public float Volume; + + public BiquadFilter BiquadFilter0; + public BiquadFilter BiquadFilter1; + + public int AppendedWaveBuffersCount; + + public int BaseWaveBufferIndex; + + public int Unknown44; + + public long AdpcmCoeffsPosition; + public long AdpcmCoeffsSize; + + public int VoiceDestination; + public int Padding; + + public WaveBuffer WaveBuffer0; + public WaveBuffer WaveBuffer1; + public WaveBuffer WaveBuffer2; + public WaveBuffer WaveBuffer3; + } +} diff --git a/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/VoiceOut.cs b/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/VoiceOut.cs new file mode 100644 index 00000000..6551acdb --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/VoiceOut.cs @@ -0,0 +1,12 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Aud.AudioRenderer +{ + [StructLayout(LayoutKind.Sequential, Size = 0x10, Pack = 4)] + struct VoiceOut + { + public long PlayedSamplesCount; + public int PlayedWaveBuffersCount; + public int VoiceDropsCount; //? + } +} diff --git a/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/WaveBuffer.cs b/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/WaveBuffer.cs new file mode 100644 index 00000000..bb188877 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/WaveBuffer.cs @@ -0,0 +1,20 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Aud.AudioRenderer +{ + [StructLayout(LayoutKind.Sequential, Size = 0x38, Pack = 1)] + struct WaveBuffer + { + public long Position; + public long Size; + public int FirstSampleOffset; + public int LastSampleOffset; + public byte Looping; + public byte LastBuffer; + public short Unknown1A; + public int Unknown1C; + public long AdpcmLoopContextPosition; + public long AdpcmLoopContextSize; + public long Unknown30; + } +} diff --git a/Ryujinx.HLE/HOS/Services/Aud/AudioRendererParameter.cs b/Ryujinx.HLE/HOS/Services/Aud/AudioRendererParameter.cs new file mode 100644 index 00000000..4d01a0de --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Aud/AudioRendererParameter.cs @@ -0,0 +1,22 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Aud +{ + [StructLayout(LayoutKind.Sequential)] + struct AudioRendererParameter + { + public int SampleRate; + public int SampleCount; + public int Unknown8; + public int MixCount; + public int VoiceCount; + public int SinkCount; + public int EffectCount; + public int PerformanceManagerCount; + public int VoiceDropEnable; + public int SplitterCount; + public int SplitterDestinationDataCount; + public int Unknown2C; + public int Revision; + } +} diff --git a/Ryujinx.HLE/HOS/Services/Aud/IAudioDevice.cs b/Ryujinx.HLE/HOS/Services/Aud/IAudioDevice.cs new file mode 100644 index 00000000..2e6056ef --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Aud/IAudioDevice.cs @@ -0,0 +1,223 @@ +using Ryujinx.HLE.HOS.Ipc; +using Ryujinx.HLE.HOS.Kernel; +using Ryujinx.HLE.HOS.SystemState; +using Ryujinx.HLE.Logging; +using System.Collections.Generic; +using System.Text; + +namespace Ryujinx.HLE.HOS.Services.Aud +{ + class IAudioDevice : IpcService + { + private Dictionary m_Commands; + + public override IReadOnlyDictionary Commands => m_Commands; + + private KEvent SystemEvent; + + public IAudioDevice() + { + m_Commands = new Dictionary() + { + { 0, ListAudioDeviceName }, + { 1, SetAudioDeviceOutputVolume }, + { 3, GetActiveAudioDeviceName }, + { 4, QueryAudioDeviceSystemEvent }, + { 5, GetActiveChannelCount }, + { 6, ListAudioDeviceNameAuto }, + { 7, SetAudioDeviceOutputVolumeAuto }, + { 8, GetAudioDeviceOutputVolumeAuto }, + { 10, GetActiveAudioDeviceNameAuto }, + { 11, QueryAudioDeviceInputEvent }, + { 12, QueryAudioDeviceOutputEvent } + }; + + SystemEvent = new KEvent(); + + //TODO: We shouldn't be signaling this here. + SystemEvent.WaitEvent.Set(); + } + + public long ListAudioDeviceName(ServiceCtx Context) + { + string[] DeviceNames = SystemStateMgr.AudioOutputs; + + Context.ResponseData.Write(DeviceNames.Length); + + long Position = Context.Request.ReceiveBuff[0].Position; + long Size = Context.Request.ReceiveBuff[0].Size; + + long BasePosition = Position; + + foreach (string Name in DeviceNames) + { + byte[] Buffer = Encoding.ASCII.GetBytes(Name + "\0"); + + if ((Position - BasePosition) + Buffer.Length > Size) + { + Context.Device.Log.PrintError(LogClass.ServiceAudio, $"Output buffer size {Size} too small!"); + + break; + } + + Context.Memory.WriteBytes(Position, Buffer); + + Position += Buffer.Length; + } + + return 0; + } + + public long SetAudioDeviceOutputVolume(ServiceCtx Context) + { + float Volume = Context.RequestData.ReadSingle(); + + long Position = Context.Request.SendBuff[0].Position; + long Size = Context.Request.SendBuff[0].Size; + + byte[] DeviceNameBuffer = Context.Memory.ReadBytes(Position, Size); + + string DeviceName = Encoding.ASCII.GetString(DeviceNameBuffer); + + Context.Device.Log.PrintStub(LogClass.ServiceAudio, "Stubbed."); + + return 0; + } + + public long GetActiveAudioDeviceName(ServiceCtx Context) + { + string Name = Context.Device.System.State.ActiveAudioOutput; + + long Position = Context.Request.ReceiveBuff[0].Position; + long Size = Context.Request.ReceiveBuff[0].Size; + + byte[] DeviceNameBuffer = Encoding.ASCII.GetBytes(Name + "\0"); + + if ((ulong)DeviceNameBuffer.Length <= (ulong)Size) + { + Context.Memory.WriteBytes(Position, DeviceNameBuffer); + } + else + { + Context.Device.Log.PrintError(LogClass.ServiceAudio, $"Output buffer size {Size} too small!"); + } + + return 0; + } + + public long QueryAudioDeviceSystemEvent(ServiceCtx Context) + { + int Handle = Context.Process.HandleTable.OpenHandle(SystemEvent); + + Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle); + + Context.Device.Log.PrintStub(LogClass.ServiceAudio, "Stubbed."); + + return 0; + } + + public long GetActiveChannelCount(ServiceCtx Context) + { + Context.ResponseData.Write(2); + + Context.Device.Log.PrintStub(LogClass.ServiceAudio, "Stubbed."); + + return 0; + } + + public long ListAudioDeviceNameAuto(ServiceCtx Context) + { + string[] DeviceNames = SystemStateMgr.AudioOutputs; + + Context.ResponseData.Write(DeviceNames.Length); + + (long Position, long Size) = Context.Request.GetBufferType0x22(); + + long BasePosition = Position; + + foreach (string Name in DeviceNames) + { + byte[] Buffer = Encoding.UTF8.GetBytes(Name + '\0'); + + if ((Position - BasePosition) + Buffer.Length > Size) + { + Context.Device.Log.PrintError(LogClass.ServiceAudio, $"Output buffer size {Size} too small!"); + + break; + } + + Context.Memory.WriteBytes(Position, Buffer); + + Position += Buffer.Length; + } + + return 0; + } + + public long SetAudioDeviceOutputVolumeAuto(ServiceCtx Context) + { + float Volume = Context.RequestData.ReadSingle(); + + (long Position, long Size) = Context.Request.GetBufferType0x21(); + + byte[] DeviceNameBuffer = Context.Memory.ReadBytes(Position, Size); + + string DeviceName = Encoding.UTF8.GetString(DeviceNameBuffer); + + Context.Device.Log.PrintStub(LogClass.ServiceAudio, "Stubbed."); + + return 0; + } + + public long GetAudioDeviceOutputVolumeAuto(ServiceCtx Context) + { + Context.ResponseData.Write(1f); + + Context.Device.Log.PrintStub(LogClass.ServiceAudio, "Stubbed."); + + return 0; + } + + public long GetActiveAudioDeviceNameAuto(ServiceCtx Context) + { + string Name = Context.Device.System.State.ActiveAudioOutput; + + (long Position, long Size) = Context.Request.GetBufferType0x22(); + + byte[] DeviceNameBuffer = Encoding.UTF8.GetBytes(Name + '\0'); + + if ((ulong)DeviceNameBuffer.Length <= (ulong)Size) + { + Context.Memory.WriteBytes(Position, DeviceNameBuffer); + } + else + { + Context.Device.Log.PrintError(LogClass.ServiceAudio, $"Output buffer size {Size} too small!"); + } + + return 0; + } + + public long QueryAudioDeviceInputEvent(ServiceCtx Context) + { + int Handle = Context.Process.HandleTable.OpenHandle(SystemEvent); + + Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle); + + Context.Device.Log.PrintStub(LogClass.ServiceAudio, "Stubbed."); + + return 0; + } + + public long QueryAudioDeviceOutputEvent(ServiceCtx Context) + { + int Handle = Context.Process.HandleTable.OpenHandle(SystemEvent); + + Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle); + + Context.Device.Log.PrintStub(LogClass.ServiceAudio, "Stubbed."); + + return 0; + } + } +} diff --git a/Ryujinx.HLE/HOS/Services/Aud/IAudioOutManager.cs b/Ryujinx.HLE/HOS/Services/Aud/IAudioOutManager.cs new file mode 100644 index 00000000..8d2435b0 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Aud/IAudioOutManager.cs @@ -0,0 +1,170 @@ +using ChocolArm64.Memory; +using Ryujinx.Audio; +using Ryujinx.HLE.HOS.Ipc; +using Ryujinx.HLE.HOS.Kernel; +using Ryujinx.HLE.HOS.Services.Aud.AudioOut; +using Ryujinx.HLE.Logging; +using System.Collections.Generic; +using System.Text; + +using static Ryujinx.HLE.HOS.ErrorCode; + +namespace Ryujinx.HLE.HOS.Services.Aud +{ + class IAudioOutManager : IpcService + { + private const string DefaultAudioOutput = "DeviceOut"; + + private const int DefaultSampleRate = 48000; + + private const int DefaultChannelsCount = 2; + + private Dictionary m_Commands; + + public override IReadOnlyDictionary Commands => m_Commands; + + public IAudioOutManager() + { + m_Commands = new Dictionary() + { + { 0, ListAudioOuts }, + { 1, OpenAudioOut }, + { 2, ListAudioOutsAuto }, + { 3, OpenAudioOutAuto } + }; + } + + public long ListAudioOuts(ServiceCtx Context) + { + return ListAudioOutsImpl( + Context, + Context.Request.ReceiveBuff[0].Position, + Context.Request.ReceiveBuff[0].Size); + } + + public long OpenAudioOut(ServiceCtx Context) + { + return OpenAudioOutImpl( + Context, + Context.Request.SendBuff[0].Position, + Context.Request.SendBuff[0].Size, + Context.Request.ReceiveBuff[0].Position, + Context.Request.ReceiveBuff[0].Size); + } + + public long ListAudioOutsAuto(ServiceCtx Context) + { + (long RecvPosition, long RecvSize) = Context.Request.GetBufferType0x22(); + + return ListAudioOutsImpl(Context, RecvPosition, RecvSize); + } + + public long OpenAudioOutAuto(ServiceCtx Context) + { + (long SendPosition, long SendSize) = Context.Request.GetBufferType0x21(); + (long RecvPosition, long RecvSize) = Context.Request.GetBufferType0x22(); + + return OpenAudioOutImpl( + Context, + SendPosition, + SendSize, + RecvPosition, + RecvSize); + } + + private long ListAudioOutsImpl(ServiceCtx Context, long Position, long Size) + { + int NameCount = 0; + + byte[] DeviceNameBuffer = Encoding.ASCII.GetBytes(DefaultAudioOutput + "\0"); + + if ((ulong)DeviceNameBuffer.Length <= (ulong)Size) + { + Context.Memory.WriteBytes(Position, DeviceNameBuffer); + + NameCount++; + } + else + { + Context.Device.Log.PrintError(LogClass.ServiceAudio, $"Output buffer size {Size} too small!"); + } + + Context.ResponseData.Write(NameCount); + + return 0; + } + + private long OpenAudioOutImpl(ServiceCtx Context, long SendPosition, long SendSize, long ReceivePosition, long ReceiveSize) + { + string DeviceName = AMemoryHelper.ReadAsciiString( + Context.Memory, + SendPosition, + SendSize); + + if (DeviceName == string.Empty) + { + DeviceName = DefaultAudioOutput; + } + + if (DeviceName != DefaultAudioOutput) + { + Context.Device.Log.PrintWarning(LogClass.Audio, "Invalid device name!"); + + return MakeError(ErrorModule.Audio, AudErr.DeviceNotFound); + } + + byte[] DeviceNameBuffer = Encoding.ASCII.GetBytes(DeviceName + "\0"); + + if ((ulong)DeviceNameBuffer.Length <= (ulong)ReceiveSize) + { + Context.Memory.WriteBytes(ReceivePosition, DeviceNameBuffer); + } + else + { + Context.Device.Log.PrintError(LogClass.ServiceAudio, $"Output buffer size {ReceiveSize} too small!"); + } + + int SampleRate = Context.RequestData.ReadInt32(); + int Channels = Context.RequestData.ReadInt32(); + + if (SampleRate == 0) + { + SampleRate = DefaultSampleRate; + } + + if (SampleRate != DefaultSampleRate) + { + Context.Device.Log.PrintWarning(LogClass.Audio, "Invalid sample rate!"); + + return MakeError(ErrorModule.Audio, AudErr.UnsupportedSampleRate); + } + + Channels = (ushort)Channels; + + if (Channels == 0) + { + Channels = DefaultChannelsCount; + } + + KEvent ReleaseEvent = new KEvent(); + + ReleaseCallback Callback = () => + { + ReleaseEvent.WaitEvent.Set(); + }; + + IAalOutput AudioOut = Context.Device.AudioOut; + + int Track = AudioOut.OpenTrack(SampleRate, Channels, Callback); + + MakeObject(Context, new IAudioOut(AudioOut, ReleaseEvent, Track)); + + Context.ResponseData.Write(SampleRate); + Context.ResponseData.Write(Channels); + Context.ResponseData.Write((int)SampleFormat.PcmInt16); + Context.ResponseData.Write((int)PlaybackState.Stopped); + + return 0; + } + } +} diff --git a/Ryujinx.HLE/HOS/Services/Aud/IAudioRendererManager.cs b/Ryujinx.HLE/HOS/Services/Aud/IAudioRendererManager.cs new file mode 100644 index 00000000..faa42290 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Aud/IAudioRendererManager.cs @@ -0,0 +1,169 @@ +using Ryujinx.Audio; +using Ryujinx.HLE.HOS.Ipc; +using Ryujinx.HLE.HOS.Services.Aud.AudioRenderer; +using Ryujinx.HLE.Logging; +using Ryujinx.HLE.Utilities; +using System.Collections.Generic; + +using static Ryujinx.HLE.HOS.ErrorCode; + +namespace Ryujinx.HLE.HOS.Services.Aud +{ + class IAudioRendererManager : IpcService + { + private const int Rev0Magic = ('R' << 0) | + ('E' << 8) | + ('V' << 16) | + ('0' << 24); + + private const int Rev = 4; + + public const int RevMagic = Rev0Magic + (Rev << 24); + + private Dictionary m_Commands; + + public override IReadOnlyDictionary Commands => m_Commands; + + public IAudioRendererManager() + { + m_Commands = new Dictionary() + { + { 0, OpenAudioRenderer }, + { 1, GetAudioRendererWorkBufferSize }, + { 2, GetAudioDevice } + }; + } + + public long OpenAudioRenderer(ServiceCtx Context) + { + IAalOutput AudioOut = Context.Device.AudioOut; + + AudioRendererParameter Params = GetAudioRendererParameter(Context); + + MakeObject(Context, new IAudioRenderer(Context.Memory, AudioOut, Params)); + + return 0; + } + + public long GetAudioRendererWorkBufferSize(ServiceCtx Context) + { + AudioRendererParameter Params = GetAudioRendererParameter(Context); + + int Revision = (Params.Revision - Rev0Magic) >> 24; + + if (Revision <= Rev) + { + bool IsSplitterSupported = Revision >= 3; + + long Size; + + Size = IntUtils.AlignUp(Params.Unknown8 * 4, 64); + Size += Params.MixCount * 0x400; + Size += (Params.MixCount + 1) * 0x940; + Size += Params.VoiceCount * 0x3F0; + Size += IntUtils.AlignUp((Params.MixCount + 1) * 8, 16); + Size += IntUtils.AlignUp(Params.VoiceCount * 8, 16); + Size += IntUtils.AlignUp( + ((Params.SinkCount + Params.MixCount) * 0x3C0 + Params.SampleCount * 4) * + (Params.Unknown8 + 6), 64); + Size += (Params.SinkCount + Params.MixCount) * 0x2C0; + Size += (Params.EffectCount + Params.VoiceCount * 4) * 0x30 + 0x50; + + if (IsSplitterSupported) + { + Size += IntUtils.AlignUp(( + NodeStatesGetWorkBufferSize(Params.MixCount + 1) + + EdgeMatrixGetWorkBufferSize(Params.MixCount + 1)), 16); + + Size += Params.SplitterDestinationDataCount * 0xE0; + Size += Params.SplitterCount * 0x20; + Size += IntUtils.AlignUp(Params.SplitterDestinationDataCount * 4, 16); + } + + Size = Params.EffectCount * 0x4C0 + + Params.SinkCount * 0x170 + + Params.VoiceCount * 0x100 + + IntUtils.AlignUp(Size, 64) + 0x40; + + if (Params.PerformanceManagerCount >= 1) + { + Size += (((Params.EffectCount + + Params.SinkCount + + Params.VoiceCount + + Params.MixCount + 1) * 16 + 0x658) * + (Params.PerformanceManagerCount + 1) + 0x13F) & ~0x3FL; + } + + Size = (Size + 0x1907D) & ~0xFFFL; + + Context.ResponseData.Write(Size); + + Context.Device.Log.PrintDebug(LogClass.ServiceAudio, $"WorkBufferSize is 0x{Size:x16}."); + + return 0; + } + else + { + Context.ResponseData.Write(0L); + + Context.Device.Log.PrintWarning(LogClass.ServiceAudio, $"Library Revision 0x{Params.Revision:x8} is not supported!"); + + return MakeError(ErrorModule.Audio, AudErr.UnsupportedRevision); + } + } + + private AudioRendererParameter GetAudioRendererParameter(ServiceCtx Context) + { + AudioRendererParameter Params = new AudioRendererParameter(); + + Params.SampleRate = Context.RequestData.ReadInt32(); + Params.SampleCount = Context.RequestData.ReadInt32(); + Params.Unknown8 = Context.RequestData.ReadInt32(); + Params.MixCount = Context.RequestData.ReadInt32(); + Params.VoiceCount = Context.RequestData.ReadInt32(); + Params.SinkCount = Context.RequestData.ReadInt32(); + Params.EffectCount = Context.RequestData.ReadInt32(); + Params.PerformanceManagerCount = Context.RequestData.ReadInt32(); + Params.VoiceDropEnable = Context.RequestData.ReadInt32(); + Params.SplitterCount = Context.RequestData.ReadInt32(); + Params.SplitterDestinationDataCount = Context.RequestData.ReadInt32(); + Params.Unknown2C = Context.RequestData.ReadInt32(); + Params.Revision = Context.RequestData.ReadInt32(); + + return Params; + } + + private static int NodeStatesGetWorkBufferSize(int Value) + { + int Result = IntUtils.AlignUp(Value, 64); + + if (Result < 0) + { + Result |= 7; + } + + return 4 * (Value * Value) + 0x12 * Value + 2 * (Result / 8); + } + + private static int EdgeMatrixGetWorkBufferSize(int Value) + { + int Result = IntUtils.AlignUp(Value * Value, 64); + + if (Result < 0) + { + Result |= 7; + } + + return Result / 8; + } + + public long GetAudioDevice(ServiceCtx Context) + { + long UserId = Context.RequestData.ReadInt64(); + + MakeObject(Context, new IAudioDevice()); + + return 0; + } + } +} diff --git a/Ryujinx.HLE/HOS/Services/Aud/SampleFormat.cs b/Ryujinx.HLE/HOS/Services/Aud/SampleFormat.cs new file mode 100644 index 00000000..8da80381 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Aud/SampleFormat.cs @@ -0,0 +1,13 @@ +namespace Ryujinx.HLE.HOS.Services.Aud +{ + enum SampleFormat : byte + { + Invalid = 0, + PcmInt8 = 1, + PcmInt16 = 2, + PcmInt24 = 3, + PcmInt32 = 4, + PcmFloat = 5, + Adpcm = 6 + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Bcat/IBcatService.cs b/Ryujinx.HLE/HOS/Services/Bcat/IBcatService.cs new file mode 100644 index 00000000..6263dfa8 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Bcat/IBcatService.cs @@ -0,0 +1,21 @@ +using Ryujinx.HLE.HOS.Ipc; +using System.Collections.Generic; + +namespace Ryujinx.HLE.HOS.Services.Bcat +{ + class IBcatService : IpcService + { + private Dictionary m_Commands; + + public override IReadOnlyDictionary Commands => m_Commands; + + public IBcatService() + { + m_Commands = new Dictionary() + { + //... + }; + } + + } +} diff --git a/Ryujinx.HLE/HOS/Services/Bcat/IDeliveryCacheStorageService.cs b/Ryujinx.HLE/HOS/Services/Bcat/IDeliveryCacheStorageService.cs new file mode 100644 index 00000000..7a55c6c8 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Bcat/IDeliveryCacheStorageService.cs @@ -0,0 +1,21 @@ +using Ryujinx.HLE.HOS.Ipc; +using System.Collections.Generic; + +namespace Ryujinx.HLE.HOS.Services.Bcat +{ + class IDeliveryCacheStorageService : IpcService + { + private Dictionary m_Commands; + + public override IReadOnlyDictionary Commands => m_Commands; + + public IDeliveryCacheStorageService() + { + m_Commands = new Dictionary() + { + //... + }; + } + + } +} diff --git a/Ryujinx.HLE/HOS/Services/Bcat/IServiceCreator.cs b/Ryujinx.HLE/HOS/Services/Bcat/IServiceCreator.cs new file mode 100644 index 00000000..55583c94 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Bcat/IServiceCreator.cs @@ -0,0 +1,39 @@ +using Ryujinx.HLE.HOS.Ipc; +using System.Collections.Generic; + +namespace Ryujinx.HLE.HOS.Services.Bcat +{ + class IServiceCreator : IpcService + { + private Dictionary m_Commands; + + public override IReadOnlyDictionary Commands => m_Commands; + + public IServiceCreator() + { + m_Commands = new Dictionary() + { + { 0, CreateBcatService }, + { 1, CreateDeliveryCacheStorageService } + }; + } + + public long CreateBcatService(ServiceCtx Context) + { + long Id = Context.RequestData.ReadInt64(); + + MakeObject(Context, new IBcatService()); + + return 0; + } + + public long CreateDeliveryCacheStorageService(ServiceCtx Context) + { + long Id = Context.RequestData.ReadInt64(); + + MakeObject(Context, new IDeliveryCacheStorageService()); + + return 0; + } + } +} diff --git a/Ryujinx.HLE/HOS/Services/Bsd/BsdError.cs b/Ryujinx.HLE/HOS/Services/Bsd/BsdError.cs new file mode 100644 index 00000000..675edcc3 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Bsd/BsdError.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Bsd +{ + //bsd_errno == (SocketException.ErrorCode - 10000) + enum BsdError + { + Timeout = 60 + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Bsd/BsdSocket.cs b/Ryujinx.HLE/HOS/Services/Bsd/BsdSocket.cs new file mode 100644 index 00000000..2361ed31 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Bsd/BsdSocket.cs @@ -0,0 +1,18 @@ +using System.Net; +using System.Net.Sockets; + +namespace Ryujinx.HLE.HOS.Services.Bsd +{ + class BsdSocket + { + public int Family; + public int Type; + public int Protocol; + + public IPAddress IpAddress; + + public IPEndPoint RemoteEP; + + public Socket Handle; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Bsd/IClient.cs b/Ryujinx.HLE/HOS/Services/Bsd/IClient.cs new file mode 100644 index 00000000..b5a457db --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Bsd/IClient.cs @@ -0,0 +1,445 @@ +using Ryujinx.HLE.HOS.Ipc; +using Ryujinx.HLE.Utilities; +using System.Collections.Generic; +using System.IO; +using System.Net; +using System.Net.Sockets; +using System.Threading.Tasks; + +namespace Ryujinx.HLE.HOS.Services.Bsd +{ + class IClient : IpcService + { + private Dictionary m_Commands; + + public override IReadOnlyDictionary Commands => m_Commands; + + private List Sockets = new List(); + + public IClient() + { + m_Commands = new Dictionary() + { + { 0, Initialize }, + { 1, StartMonitoring }, + { 2, Socket }, + { 6, Poll }, + { 8, Recv }, + { 10, Send }, + { 11, SendTo }, + { 12, Accept }, + { 13, Bind }, + { 14, Connect }, + { 18, Listen }, + { 21, SetSockOpt }, + { 26, Close } + }; + } + + //(u32, u32, u32, u32, u32, u32, u32, u32, u64 pid, u64 transferMemorySize, pid, KObject) -> u32 bsd_errno + public long Initialize(ServiceCtx Context) + { + /* + typedef struct { + u32 version; // Observed 1 on 2.0 LibAppletWeb, 2 on 3.0. + u32 tcp_tx_buf_size; // Size of the TCP transfer (send) buffer (initial or fixed). + u32 tcp_rx_buf_size; // Size of the TCP recieve buffer (initial or fixed). + u32 tcp_tx_buf_max_size; // Maximum size of the TCP transfer (send) buffer. If it is 0, the size of the buffer is fixed to its initial value. + u32 tcp_rx_buf_max_size; // Maximum size of the TCP receive buffer. If it is 0, the size of the buffer is fixed to its initial value. + u32 udp_tx_buf_size; // Size of the UDP transfer (send) buffer (typically 0x2400 bytes). + u32 udp_rx_buf_size; // Size of the UDP receive buffer (typically 0xA500 bytes). + u32 sb_efficiency; // Number of buffers for each socket (standard values range from 1 to 8). + } BsdBufferConfig; + */ + + Context.ResponseData.Write(0); + + //Todo: Stub + + return 0; + } + + //(u64, pid) + public long StartMonitoring(ServiceCtx Context) + { + //Todo: Stub + + return 0; + } + + //(u32 domain, u32 type, u32 protocol) -> (i32 ret, u32 bsd_errno) + public long Socket(ServiceCtx Context) + { + BsdSocket NewBsdSocket = new BsdSocket + { + Family = Context.RequestData.ReadInt32(), + Type = Context.RequestData.ReadInt32(), + Protocol = Context.RequestData.ReadInt32() + }; + + Sockets.Add(NewBsdSocket); + + NewBsdSocket.Handle = new Socket((AddressFamily)NewBsdSocket.Family, + (SocketType)NewBsdSocket.Type, + (ProtocolType)NewBsdSocket.Protocol); + + Context.ResponseData.Write(Sockets.Count - 1); + Context.ResponseData.Write(0); + + return 0; + } + + //(u32, u32, buffer) -> (i32 ret, u32 bsd_errno, buffer) + public long Poll(ServiceCtx Context) + { + int PollCount = Context.RequestData.ReadInt32(); + int TimeOut = Context.RequestData.ReadInt32(); + + //https://github.com/torvalds/linux/blob/master/include/uapi/asm-generic/poll.h + //https://msdn.microsoft.com/fr-fr/library/system.net.sockets.socket.poll(v=vs.110).aspx + //https://github.com/switchbrew/libnx/blob/e0457c4534b3c37426d83e1a620f82cb28c3b528/nx/source/services/bsd.c#L343 + //https://github.com/TuxSH/ftpd/blob/switch_pr/source/ftp.c#L1634 + //https://linux.die.net/man/2/poll + + byte[] SentBuffer = Context.Memory.ReadBytes(Context.Request.SendBuff[0].Position, + Context.Request.SendBuff[0].Size); + + int SocketId = Get32(SentBuffer, 0); + int RequestedEvents = Get16(SentBuffer, 4); + int ReturnedEvents = Get16(SentBuffer, 6); + + //Todo: Stub - Need to implemented the Type-22 buffer. + + Context.ResponseData.Write(1); + Context.ResponseData.Write(0); + + return 0; + } + + //(u32 socket, u32 flags) -> (i32 ret, u32 bsd_errno, buffer message) + public long Recv(ServiceCtx Context) + { + int SocketId = Context.RequestData.ReadInt32(); + int SocketFlags = Context.RequestData.ReadInt32(); + + byte[] ReceivedBuffer = new byte[Context.Request.ReceiveBuff[0].Size]; + + try + { + int BytesRead = Sockets[SocketId].Handle.Receive(ReceivedBuffer); + + //Logging.Debug("Received Buffer:" + Environment.NewLine + Logging.HexDump(ReceivedBuffer)); + + Context.Memory.WriteBytes(Context.Request.ReceiveBuff[0].Position, ReceivedBuffer); + + Context.ResponseData.Write(BytesRead); + Context.ResponseData.Write(0); + } + catch (SocketException Ex) + { + Context.ResponseData.Write(-1); + Context.ResponseData.Write(Ex.ErrorCode - 10000); + } + + return 0; + } + + //(u32 socket, u32 flags, buffer) -> (i32 ret, u32 bsd_errno) + public long Send(ServiceCtx Context) + { + int SocketId = Context.RequestData.ReadInt32(); + int SocketFlags = Context.RequestData.ReadInt32(); + + byte[] SentBuffer = Context.Memory.ReadBytes(Context.Request.SendBuff[0].Position, + Context.Request.SendBuff[0].Size); + + try + { + //Logging.Debug("Sent Buffer:" + Environment.NewLine + Logging.HexDump(SentBuffer)); + + int BytesSent = Sockets[SocketId].Handle.Send(SentBuffer); + + Context.ResponseData.Write(BytesSent); + Context.ResponseData.Write(0); + } + catch (SocketException Ex) + { + Context.ResponseData.Write(-1); + Context.ResponseData.Write(Ex.ErrorCode - 10000); + } + + return 0; + } + + //(u32 socket, u32 flags, buffer, buffer) -> (i32 ret, u32 bsd_errno) + public long SendTo(ServiceCtx Context) + { + int SocketId = Context.RequestData.ReadInt32(); + int SocketFlags = Context.RequestData.ReadInt32(); + + byte[] SentBuffer = Context.Memory.ReadBytes(Context.Request.SendBuff[0].Position, + Context.Request.SendBuff[0].Size); + + byte[] AddressBuffer = Context.Memory.ReadBytes(Context.Request.SendBuff[1].Position, + Context.Request.SendBuff[1].Size); + + if (!Sockets[SocketId].Handle.Connected) + { + try + { + ParseAddrBuffer(SocketId, AddressBuffer); + + Sockets[SocketId].Handle.Connect(Sockets[SocketId].RemoteEP); + } + catch (SocketException Ex) + { + Context.ResponseData.Write(-1); + Context.ResponseData.Write(Ex.ErrorCode - 10000); + } + } + + try + { + //Logging.Debug("Sent Buffer:" + Environment.NewLine + Logging.HexDump(SentBuffer)); + + int BytesSent = Sockets[SocketId].Handle.Send(SentBuffer); + + Context.ResponseData.Write(BytesSent); + Context.ResponseData.Write(0); + } + catch (SocketException Ex) + { + Context.ResponseData.Write(-1); + Context.ResponseData.Write(Ex.ErrorCode - 10000); + } + + return 0; + } + + //(u32 socket) -> (i32 ret, u32 bsd_errno, u32 addrlen, buffer addr) + public long Accept(ServiceCtx Context) + { + int SocketId = Context.RequestData.ReadInt32(); + + long AddrBufferPtr = Context.Request.ReceiveBuff[0].Position; + + Socket HandleAccept = null; + + Task TimeOut = Task.Factory.StartNew(() => + { + try + { + HandleAccept = Sockets[SocketId].Handle.Accept(); + } + catch (SocketException Ex) + { + Context.ResponseData.Write(-1); + Context.ResponseData.Write(Ex.ErrorCode - 10000); + } + }); + + TimeOut.Wait(10000); + + if (HandleAccept != null) + { + BsdSocket NewBsdSocket = new BsdSocket + { + IpAddress = ((IPEndPoint)Sockets[SocketId].Handle.LocalEndPoint).Address, + RemoteEP = ((IPEndPoint)Sockets[SocketId].Handle.LocalEndPoint), + Handle = HandleAccept + }; + + Sockets.Add(NewBsdSocket); + + using (MemoryStream MS = new MemoryStream()) + { + BinaryWriter Writer = new BinaryWriter(MS); + + Writer.Write((byte)0); + + Writer.Write((byte)NewBsdSocket.Handle.AddressFamily); + + Writer.Write((short)((IPEndPoint)NewBsdSocket.Handle.LocalEndPoint).Port); + + byte[] IpAddress = NewBsdSocket.IpAddress.GetAddressBytes(); + + Writer.Write(IpAddress); + + Context.Memory.WriteBytes(AddrBufferPtr, MS.ToArray()); + + Context.ResponseData.Write(Sockets.Count - 1); + Context.ResponseData.Write(0); + Context.ResponseData.Write(MS.Length); + } + } + else + { + Context.ResponseData.Write(-1); + Context.ResponseData.Write((int)BsdError.Timeout); + } + + return 0; + } + + //(u32 socket, buffer) -> (i32 ret, u32 bsd_errno) + public long Bind(ServiceCtx Context) + { + int SocketId = Context.RequestData.ReadInt32(); + + byte[] AddressBuffer = Context.Memory.ReadBytes(Context.Request.SendBuff[0].Position, + Context.Request.SendBuff[0].Size); + + try + { + ParseAddrBuffer(SocketId, AddressBuffer); + + Context.ResponseData.Write(0); + Context.ResponseData.Write(0); + } + catch (SocketException Ex) + { + Context.ResponseData.Write(-1); + Context.ResponseData.Write(Ex.ErrorCode - 10000); + } + + return 0; + } + + //(u32 socket, buffer) -> (i32 ret, u32 bsd_errno) + public long Connect(ServiceCtx Context) + { + int SocketId = Context.RequestData.ReadInt32(); + + byte[] AddressBuffer = Context.Memory.ReadBytes(Context.Request.SendBuff[0].Position, + Context.Request.SendBuff[0].Size); + + try + { + ParseAddrBuffer(SocketId, AddressBuffer); + + Sockets[SocketId].Handle.Connect(Sockets[SocketId].RemoteEP); + + Context.ResponseData.Write(0); + Context.ResponseData.Write(0); + } + catch (SocketException Ex) + { + Context.ResponseData.Write(-1); + Context.ResponseData.Write(Ex.ErrorCode - 10000); + } + + return 0; + } + + //(u32 socket, u32 backlog) -> (i32 ret, u32 bsd_errno) + public long Listen(ServiceCtx Context) + { + int SocketId = Context.RequestData.ReadInt32(); + int BackLog = Context.RequestData.ReadInt32(); + + try + { + Sockets[SocketId].Handle.Bind(Sockets[SocketId].RemoteEP); + Sockets[SocketId].Handle.Listen(BackLog); + + Context.ResponseData.Write(0); + Context.ResponseData.Write(0); + } + catch (SocketException Ex) + { + Context.ResponseData.Write(-1); + Context.ResponseData.Write(Ex.ErrorCode - 10000); + } + + return 0; + } + + //(u32 socket, u32 level, u32 option_name, buffer) -> (i32 ret, u32 bsd_errno) + public long SetSockOpt(ServiceCtx Context) + { + int SocketId = Context.RequestData.ReadInt32(); + + SocketOptionLevel SocketLevel = (SocketOptionLevel)Context.RequestData.ReadInt32(); + SocketOptionName SocketOptionName = (SocketOptionName)Context.RequestData.ReadInt32(); + + byte[] SocketOptionValue = Context.Memory.ReadBytes(Context.Request.PtrBuff[0].Position, + Context.Request.PtrBuff[0].Size); + + int OptionValue = Get32(SocketOptionValue, 0); + + try + { + Sockets[SocketId].Handle.SetSocketOption(SocketLevel, SocketOptionName, OptionValue); + + Context.ResponseData.Write(0); + Context.ResponseData.Write(0); + } + catch (SocketException Ex) + { + Context.ResponseData.Write(-1); + Context.ResponseData.Write(Ex.ErrorCode - 10000); + } + + return 0; + } + + //(u32 socket) -> (i32 ret, u32 bsd_errno) + public long Close(ServiceCtx Context) + { + int SocketId = Context.RequestData.ReadInt32(); + + try + { + Sockets[SocketId].Handle.Close(); + Sockets[SocketId] = null; + + Context.ResponseData.Write(0); + Context.ResponseData.Write(0); + } + catch (SocketException Ex) + { + Context.ResponseData.Write(-1); + Context.ResponseData.Write(Ex.ErrorCode - 10000); + } + + return 0; + } + + public void ParseAddrBuffer(int SocketId, byte[] AddrBuffer) + { + using (MemoryStream MS = new MemoryStream(AddrBuffer)) + { + BinaryReader Reader = new BinaryReader(MS); + + int Size = Reader.ReadByte(); + int Family = Reader.ReadByte(); + int Port = EndianSwap.Swap16(Reader.ReadInt16()); + + string IpAddress = Reader.ReadByte().ToString() + "." + + Reader.ReadByte().ToString() + "." + + Reader.ReadByte().ToString() + "." + + Reader.ReadByte().ToString(); + + Sockets[SocketId].IpAddress = IPAddress.Parse(IpAddress); + + Sockets[SocketId].RemoteEP = new IPEndPoint(Sockets[SocketId].IpAddress, Port); + } + } + + private int Get16(byte[] Data, int Address) + { + return + Data[Address + 0] << 0 | + Data[Address + 1] << 8; + } + + private int Get32(byte[] Data, int Address) + { + return + Data[Address + 0] << 0 | + Data[Address + 1] << 8 | + Data[Address + 2] << 16 | + Data[Address + 3] << 24; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Caps/IAlbumAccessorService.cs b/Ryujinx.HLE/HOS/Services/Caps/IAlbumAccessorService.cs new file mode 100644 index 00000000..6d96b769 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Caps/IAlbumAccessorService.cs @@ -0,0 +1,20 @@ +using Ryujinx.HLE.HOS.Ipc; +using System.Collections.Generic; + +namespace Ryujinx.HLE.HOS.Services.Caps +{ + class IAlbumAccessorService : IpcService + { + private Dictionary m_Commands; + + public override IReadOnlyDictionary Commands => m_Commands; + + public IAlbumAccessorService() + { + m_Commands = new Dictionary() + { + //... + }; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Caps/IScreenshotService.cs b/Ryujinx.HLE/HOS/Services/Caps/IScreenshotService.cs new file mode 100644 index 00000000..5a54d563 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Caps/IScreenshotService.cs @@ -0,0 +1,20 @@ +using Ryujinx.HLE.HOS.Ipc; +using System.Collections.Generic; + +namespace Ryujinx.HLE.HOS.Services.Caps +{ + class IScreenshotService : IpcService + { + private Dictionary m_Commands; + + public override IReadOnlyDictionary Commands => m_Commands; + + public IScreenshotService() + { + m_Commands = new Dictionary() + { + //... + }; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Friend/IFriendService.cs b/Ryujinx.HLE/HOS/Services/Friend/IFriendService.cs new file mode 100644 index 00000000..3b06ba8a --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Friend/IFriendService.cs @@ -0,0 +1,49 @@ +using Ryujinx.HLE.HOS.Ipc; +using Ryujinx.HLE.HOS.SystemState; +using Ryujinx.HLE.Logging; +using System.Collections.Generic; + +namespace Ryujinx.HLE.HOS.Services.Friend +{ + class IFriendService : IpcService + { + private Dictionary m_Commands; + + public override IReadOnlyDictionary Commands => m_Commands; + + public IFriendService() + { + m_Commands = new Dictionary() + { + { 10601, DeclareCloseOnlinePlaySession }, + { 10610, UpdateUserPresence } + }; + } + + public long DeclareCloseOnlinePlaySession(ServiceCtx Context) + { + UserId Uuid = new UserId( + Context.RequestData.ReadInt64(), + Context.RequestData.ReadInt64()); + + if (Context.Device.System.State.TryGetUser(Uuid, out UserProfile Profile)) + { + Profile.OnlinePlayState = OpenCloseState.Closed; + } + + return 0; + } + + public long UpdateUserPresence(ServiceCtx Context) + { + UserId Uuid = new UserId( + Context.RequestData.ReadInt64(), + Context.RequestData.ReadInt64()); + + //TODO. + Context.Device.Log.PrintStub(LogClass.ServiceFriend, "Stubbed."); + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Friend/IServiceCreator.cs b/Ryujinx.HLE/HOS/Services/Friend/IServiceCreator.cs new file mode 100644 index 00000000..065e230d --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Friend/IServiceCreator.cs @@ -0,0 +1,27 @@ +using Ryujinx.HLE.HOS.Ipc; +using System.Collections.Generic; + +namespace Ryujinx.HLE.HOS.Services.Friend +{ + class IServiceCreator : IpcService + { + private Dictionary m_Commands; + + public override IReadOnlyDictionary Commands => m_Commands; + + public IServiceCreator() + { + m_Commands = new Dictionary() + { + { 0, CreateFriendService } + }; + } + + public static long CreateFriendService(ServiceCtx Context) + { + MakeObject(Context, new IFriendService()); + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/FspSrv/FsErr.cs b/Ryujinx.HLE/HOS/Services/FspSrv/FsErr.cs new file mode 100644 index 00000000..39eadcec --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/FspSrv/FsErr.cs @@ -0,0 +1,9 @@ +namespace Ryujinx.HLE.HOS.Services.FspSrv +{ + static class FsErr + { + public const int PathDoesNotExist = 1; + public const int PathAlreadyExists = 2; + public const int PathAlreadyInUse = 7; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/FspSrv/IDirectory.cs b/Ryujinx.HLE/HOS/Services/FspSrv/IDirectory.cs new file mode 100644 index 00000000..d6ae084f --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/FspSrv/IDirectory.cs @@ -0,0 +1,116 @@ +using Ryujinx.HLE.HOS.Ipc; +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; + +namespace Ryujinx.HLE.HOS.Services.FspSrv +{ + class IDirectory : IpcService, IDisposable + { + private const int DirectoryEntrySize = 0x310; + + private Dictionary m_Commands; + + public override IReadOnlyDictionary Commands => m_Commands; + + private List DirectoryEntries; + + private int CurrentItemIndex; + + public event EventHandler Disposed; + + public string HostPath { get; private set; } + + public IDirectory(string HostPath, int Flags) + { + m_Commands = new Dictionary() + { + { 0, Read }, + { 1, GetEntryCount } + }; + + this.HostPath = HostPath; + + DirectoryEntries = new List(); + + if ((Flags & 1) != 0) + { + DirectoryEntries.AddRange(Directory.GetDirectories(HostPath)); + } + + if ((Flags & 2) != 0) + { + DirectoryEntries.AddRange(Directory.GetFiles(HostPath)); + } + + CurrentItemIndex = 0; + } + + public long Read(ServiceCtx Context) + { + long BufferPosition = Context.Request.ReceiveBuff[0].Position; + long BufferLen = Context.Request.ReceiveBuff[0].Size; + + int MaxReadCount = (int)(BufferLen / DirectoryEntrySize); + + int Count = Math.Min(DirectoryEntries.Count - CurrentItemIndex, MaxReadCount); + + for (int Index = 0; Index < Count; Index++) + { + long Position = BufferPosition + Index * DirectoryEntrySize; + + WriteDirectoryEntry(Context, Position, DirectoryEntries[CurrentItemIndex++]); + } + + Context.ResponseData.Write((long)Count); + + return 0; + } + + private void WriteDirectoryEntry(ServiceCtx Context, long Position, string FullPath) + { + for (int Offset = 0; Offset < 0x300; Offset += 8) + { + Context.Memory.WriteInt64(Position + Offset, 0); + } + + byte[] NameBuffer = Encoding.UTF8.GetBytes(Path.GetFileName(FullPath)); + + Context.Memory.WriteBytes(Position, NameBuffer); + + int Type = 0; + long Size = 0; + + if (File.Exists(FullPath)) + { + Type = 1; + Size = new FileInfo(FullPath).Length; + } + + Context.Memory.WriteInt32(Position + 0x300, 0); //Padding? + Context.Memory.WriteInt32(Position + 0x304, Type); + Context.Memory.WriteInt64(Position + 0x308, Size); + } + + public long GetEntryCount(ServiceCtx Context) + { + Context.ResponseData.Write((long)DirectoryEntries.Count); + + return 0; + } + + public void Dispose() + { + Dispose(true); + } + + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + Disposed?.Invoke(this, EventArgs.Empty); + } + } + } +} diff --git a/Ryujinx.HLE/HOS/Services/FspSrv/IFile.cs b/Ryujinx.HLE/HOS/Services/FspSrv/IFile.cs new file mode 100644 index 00000000..194d9420 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/FspSrv/IFile.cs @@ -0,0 +1,110 @@ +using Ryujinx.HLE.HOS.Ipc; +using System; +using System.Collections.Generic; +using System.IO; + +namespace Ryujinx.HLE.HOS.Services.FspSrv +{ + class IFile : IpcService, IDisposable + { + private Dictionary m_Commands; + + public override IReadOnlyDictionary Commands => m_Commands; + + private Stream BaseStream; + + public event EventHandler Disposed; + + public string HostPath { get; private set; } + + public IFile(Stream BaseStream, string HostPath) + { + m_Commands = new Dictionary() + { + { 0, Read }, + { 1, Write }, + { 2, Flush }, + { 3, SetSize }, + { 4, GetSize } + }; + + this.BaseStream = BaseStream; + this.HostPath = HostPath; + } + + public long Read(ServiceCtx Context) + { + long Position = Context.Request.ReceiveBuff[0].Position; + + long Zero = Context.RequestData.ReadInt64(); + long Offset = Context.RequestData.ReadInt64(); + long Size = Context.RequestData.ReadInt64(); + + byte[] Data = new byte[Size]; + + BaseStream.Seek(Offset, SeekOrigin.Begin); + + int ReadSize = BaseStream.Read(Data, 0, (int)Size); + + Context.Memory.WriteBytes(Position, Data); + + Context.ResponseData.Write((long)ReadSize); + + return 0; + } + + public long Write(ServiceCtx Context) + { + long Position = Context.Request.SendBuff[0].Position; + + long Zero = Context.RequestData.ReadInt64(); + long Offset = Context.RequestData.ReadInt64(); + long Size = Context.RequestData.ReadInt64(); + + byte[] Data = Context.Memory.ReadBytes(Position, Size); + + BaseStream.Seek(Offset, SeekOrigin.Begin); + BaseStream.Write(Data, 0, (int)Size); + + return 0; + } + + public long Flush(ServiceCtx Context) + { + BaseStream.Flush(); + + return 0; + } + + public long SetSize(ServiceCtx Context) + { + long Size = Context.RequestData.ReadInt64(); + + BaseStream.SetLength(Size); + + return 0; + } + + public long GetSize(ServiceCtx Context) + { + Context.ResponseData.Write(BaseStream.Length); + + return 0; + } + + public void Dispose() + { + Dispose(true); + } + + protected virtual void Dispose(bool disposing) + { + if (disposing && BaseStream != null) + { + BaseStream.Dispose(); + + Disposed?.Invoke(this, EventArgs.Empty); + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/FspSrv/IFileSystem.cs b/Ryujinx.HLE/HOS/Services/FspSrv/IFileSystem.cs new file mode 100644 index 00000000..b77043bd --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/FspSrv/IFileSystem.cs @@ -0,0 +1,412 @@ +using Ryujinx.HLE.HOS.Ipc; +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; + +using static Ryujinx.HLE.HOS.ErrorCode; + +namespace Ryujinx.HLE.HOS.Services.FspSrv +{ + class IFileSystem : IpcService + { + private Dictionary m_Commands; + + public override IReadOnlyDictionary Commands => m_Commands; + + private HashSet OpenPaths; + + private string Path; + + public IFileSystem(string Path) + { + m_Commands = new Dictionary() + { + { 0, CreateFile }, + { 1, DeleteFile }, + { 2, CreateDirectory }, + { 3, DeleteDirectory }, + { 4, DeleteDirectoryRecursively }, + { 5, RenameFile }, + { 6, RenameDirectory }, + { 7, GetEntryType }, + { 8, OpenFile }, + { 9, OpenDirectory }, + { 10, Commit }, + { 11, GetFreeSpaceSize }, + { 12, GetTotalSpaceSize }, + { 13, CleanDirectoryRecursively }, + //{ 14, GetFileTimeStampRaw } + }; + + OpenPaths = new HashSet(); + + this.Path = Path; + } + + public long CreateFile(ServiceCtx Context) + { + string Name = ReadUtf8String(Context); + + long Mode = Context.RequestData.ReadInt64(); + int Size = Context.RequestData.ReadInt32(); + + string FileName = Context.Device.FileSystem.GetFullPath(Path, Name); + + if (FileName == null) + { + return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist); + } + + if (File.Exists(FileName)) + { + return MakeError(ErrorModule.Fs, FsErr.PathAlreadyExists); + } + + if (IsPathAlreadyInUse(FileName)) + { + return MakeError(ErrorModule.Fs, FsErr.PathAlreadyInUse); + } + + using (FileStream NewFile = File.Create(FileName)) + { + NewFile.SetLength(Size); + } + + return 0; + } + + public long DeleteFile(ServiceCtx Context) + { + string Name = ReadUtf8String(Context); + + string FileName = Context.Device.FileSystem.GetFullPath(Path, Name); + + if (!File.Exists(FileName)) + { + return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist); + } + + if (IsPathAlreadyInUse(FileName)) + { + return MakeError(ErrorModule.Fs, FsErr.PathAlreadyInUse); + } + + File.Delete(FileName); + + return 0; + } + + public long CreateDirectory(ServiceCtx Context) + { + string Name = ReadUtf8String(Context); + + string DirName = Context.Device.FileSystem.GetFullPath(Path, Name); + + if (DirName == null) + { + return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist); + } + + if (Directory.Exists(DirName)) + { + return MakeError(ErrorModule.Fs, FsErr.PathAlreadyExists); + } + + if (IsPathAlreadyInUse(DirName)) + { + return MakeError(ErrorModule.Fs, FsErr.PathAlreadyInUse); + } + + Directory.CreateDirectory(DirName); + + return 0; + } + + public long DeleteDirectory(ServiceCtx Context) + { + return DeleteDirectory(Context, false); + } + + public long DeleteDirectoryRecursively(ServiceCtx Context) + { + return DeleteDirectory(Context, true); + } + + private long DeleteDirectory(ServiceCtx Context, bool Recursive) + { + string Name = ReadUtf8String(Context); + + string DirName = Context.Device.FileSystem.GetFullPath(Path, Name); + + if (!Directory.Exists(DirName)) + { + return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist); + } + + if (IsPathAlreadyInUse(DirName)) + { + return MakeError(ErrorModule.Fs, FsErr.PathAlreadyInUse); + } + + Directory.Delete(DirName, Recursive); + + return 0; + } + + public long RenameFile(ServiceCtx Context) + { + string OldName = ReadUtf8String(Context, 0); + string NewName = ReadUtf8String(Context, 1); + + string OldFileName = Context.Device.FileSystem.GetFullPath(Path, OldName); + string NewFileName = Context.Device.FileSystem.GetFullPath(Path, NewName); + + if (!File.Exists(OldFileName)) + { + return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist); + } + + if (File.Exists(NewFileName)) + { + return MakeError(ErrorModule.Fs, FsErr.PathAlreadyExists); + } + + if (IsPathAlreadyInUse(OldFileName)) + { + return MakeError(ErrorModule.Fs, FsErr.PathAlreadyInUse); + } + + File.Move(OldFileName, NewFileName); + + return 0; + } + + public long RenameDirectory(ServiceCtx Context) + { + string OldName = ReadUtf8String(Context, 0); + string NewName = ReadUtf8String(Context, 1); + + string OldDirName = Context.Device.FileSystem.GetFullPath(Path, OldName); + string NewDirName = Context.Device.FileSystem.GetFullPath(Path, NewName); + + if (!Directory.Exists(OldDirName)) + { + return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist); + } + + if (Directory.Exists(NewDirName)) + { + return MakeError(ErrorModule.Fs, FsErr.PathAlreadyExists); + } + + if (IsPathAlreadyInUse(OldDirName)) + { + return MakeError(ErrorModule.Fs, FsErr.PathAlreadyInUse); + } + + Directory.Move(OldDirName, NewDirName); + + return 0; + } + + public long GetEntryType(ServiceCtx Context) + { + string Name = ReadUtf8String(Context); + + string FileName = Context.Device.FileSystem.GetFullPath(Path, Name); + + if (File.Exists(FileName)) + { + Context.ResponseData.Write(1); + } + else if (Directory.Exists(FileName)) + { + Context.ResponseData.Write(0); + } + else + { + Context.ResponseData.Write(0); + + return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist); + } + + return 0; + } + + public long OpenFile(ServiceCtx Context) + { + int FilterFlags = Context.RequestData.ReadInt32(); + + string Name = ReadUtf8String(Context); + + string FileName = Context.Device.FileSystem.GetFullPath(Path, Name); + + if (!File.Exists(FileName)) + { + return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist); + } + + if (IsPathAlreadyInUse(FileName)) + { + return MakeError(ErrorModule.Fs, FsErr.PathAlreadyInUse); + } + + FileStream Stream = new FileStream(FileName, FileMode.Open); + + IFile FileInterface = new IFile(Stream, FileName); + + FileInterface.Disposed += RemoveFileInUse; + + lock (OpenPaths) + { + OpenPaths.Add(FileName); + } + + MakeObject(Context, FileInterface); + + return 0; + } + + public long OpenDirectory(ServiceCtx Context) + { + int FilterFlags = Context.RequestData.ReadInt32(); + + string Name = ReadUtf8String(Context); + + string DirName = Context.Device.FileSystem.GetFullPath(Path, Name); + + if (!Directory.Exists(DirName)) + { + return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist); + } + + if (IsPathAlreadyInUse(DirName)) + { + return MakeError(ErrorModule.Fs, FsErr.PathAlreadyInUse); + } + + IDirectory DirInterface = new IDirectory(DirName, FilterFlags); + + DirInterface.Disposed += RemoveDirectoryInUse; + + lock (OpenPaths) + { + OpenPaths.Add(DirName); + } + + MakeObject(Context, DirInterface); + + return 0; + } + + public long Commit(ServiceCtx Context) + { + return 0; + } + + public long GetFreeSpaceSize(ServiceCtx Context) + { + string Name = ReadUtf8String(Context); + + Context.ResponseData.Write(Context.Device.FileSystem.GetDrive().AvailableFreeSpace); + + return 0; + } + + public long GetTotalSpaceSize(ServiceCtx Context) + { + string Name = ReadUtf8String(Context); + + Context.ResponseData.Write(Context.Device.FileSystem.GetDrive().TotalSize); + + return 0; + } + + public long CleanDirectoryRecursively(ServiceCtx Context) + { + string Name = ReadUtf8String(Context); + + string DirName = Context.Device.FileSystem.GetFullPath(Path, Name); + + if (!Directory.Exists(DirName)) + { + return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist); + } + + if (IsPathAlreadyInUse(DirName)) + { + return MakeError(ErrorModule.Fs, FsErr.PathAlreadyInUse); + } + + foreach (string Entry in Directory.EnumerateFileSystemEntries(DirName)) + { + if (Directory.Exists(Entry)) + { + Directory.Delete(Entry, true); + } + else if (File.Exists(Entry)) + { + File.Delete(Entry); + } + } + + return 0; + } + + private bool IsPathAlreadyInUse(string Path) + { + lock (OpenPaths) + { + return OpenPaths.Contains(Path); + } + } + + private void RemoveFileInUse(object sender, EventArgs e) + { + IFile FileInterface = (IFile)sender; + + lock (OpenPaths) + { + FileInterface.Disposed -= RemoveFileInUse; + + OpenPaths.Remove(FileInterface.HostPath); + } + } + + private void RemoveDirectoryInUse(object sender, EventArgs e) + { + IDirectory DirInterface = (IDirectory)sender; + + lock (OpenPaths) + { + DirInterface.Disposed -= RemoveDirectoryInUse; + + OpenPaths.Remove(DirInterface.HostPath); + } + } + + private string ReadUtf8String(ServiceCtx Context, int Index = 0) + { + long Position = Context.Request.PtrBuff[Index].Position; + long Size = Context.Request.PtrBuff[Index].Size; + + using (MemoryStream MS = new MemoryStream()) + { + while (Size-- > 0) + { + byte Value = Context.Memory.ReadByte(Position++); + + if (Value == 0) + { + break; + } + + MS.WriteByte(Value); + } + + return Encoding.UTF8.GetString(MS.ToArray()); + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/FspSrv/IFileSystemProxy.cs b/Ryujinx.HLE/HOS/Services/FspSrv/IFileSystemProxy.cs new file mode 100644 index 00000000..14edcc75 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/FspSrv/IFileSystemProxy.cs @@ -0,0 +1,74 @@ +using Ryujinx.HLE.HOS.Ipc; +using Ryujinx.HLE.Logging; +using System.Collections.Generic; + +namespace Ryujinx.HLE.HOS.Services.FspSrv +{ + class IFileSystemProxy : IpcService + { + private Dictionary m_Commands; + + public override IReadOnlyDictionary Commands => m_Commands; + + public IFileSystemProxy() + { + m_Commands = new Dictionary() + { + { 1, SetCurrentProcess }, + { 18, OpenSdCardFileSystem }, + { 22, CreateSaveDataFileSystem }, + { 51, OpenSaveDataFileSystem }, + { 200, OpenDataStorageByCurrentProcess }, + { 203, OpenPatchDataStorageByCurrentProcess }, + { 1005, GetGlobalAccessLogMode } + }; + } + + public long SetCurrentProcess(ServiceCtx Context) + { + return 0; + } + + public long OpenSdCardFileSystem(ServiceCtx Context) + { + MakeObject(Context, new IFileSystem(Context.Device.FileSystem.GetSdCardPath())); + + return 0; + } + + public long CreateSaveDataFileSystem(ServiceCtx Context) + { + Context.Device.Log.PrintStub(LogClass.ServiceFs, "Stubbed."); + + return 0; + } + + public long OpenSaveDataFileSystem(ServiceCtx Context) + { + MakeObject(Context, new IFileSystem(Context.Device.FileSystem.GetGameSavesPath())); + + return 0; + } + + public long OpenDataStorageByCurrentProcess(ServiceCtx Context) + { + MakeObject(Context, new IStorage(Context.Device.FileSystem.RomFs)); + + return 0; + } + + public long OpenPatchDataStorageByCurrentProcess(ServiceCtx Context) + { + MakeObject(Context, new IStorage(Context.Device.FileSystem.RomFs)); + + return 0; + } + + public long GetGlobalAccessLogMode(ServiceCtx Context) + { + Context.ResponseData.Write(0); + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/FspSrv/IStorage.cs b/Ryujinx.HLE/HOS/Services/FspSrv/IStorage.cs new file mode 100644 index 00000000..5118fa45 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/FspSrv/IStorage.cs @@ -0,0 +1,51 @@ +using Ryujinx.HLE.HOS.Ipc; +using System.Collections.Generic; +using System.IO; + +namespace Ryujinx.HLE.HOS.Services.FspSrv +{ + class IStorage : IpcService + { + private Dictionary m_Commands; + + public override IReadOnlyDictionary Commands => m_Commands; + + private Stream BaseStream; + + public IStorage(Stream BaseStream) + { + m_Commands = new Dictionary() + { + { 0, Read } + }; + + this.BaseStream = BaseStream; + } + + public long Read(ServiceCtx Context) + { + long Offset = Context.RequestData.ReadInt64(); + long Size = Context.RequestData.ReadInt64(); + + if (Context.Request.ReceiveBuff.Count > 0) + { + IpcBuffDesc BuffDesc = Context.Request.ReceiveBuff[0]; + + //Use smaller length to avoid overflows. + if (Size > BuffDesc.Size) + { + Size = BuffDesc.Size; + } + + byte[] Data = new byte[Size]; + + BaseStream.Seek(Offset, SeekOrigin.Begin); + BaseStream.Read(Data, 0, Data.Length); + + Context.Memory.WriteBytes(BuffDesc.Position, Data); + } + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/IActiveVibrationDeviceList.cs b/Ryujinx.HLE/HOS/Services/Hid/IActiveVibrationDeviceList.cs new file mode 100644 index 00000000..6e666919 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/IActiveVibrationDeviceList.cs @@ -0,0 +1,27 @@ +using Ryujinx.HLE.HOS.Ipc; +using System.Collections.Generic; + +namespace Ryujinx.HLE.HOS.Services.Hid +{ + class IActiveApplicationDeviceList : IpcService + { + private Dictionary m_Commands; + + public override IReadOnlyDictionary Commands => m_Commands; + + public IActiveApplicationDeviceList() + { + m_Commands = new Dictionary() + { + { 0, ActivateVibrationDevice } + }; + } + + public long ActivateVibrationDevice(ServiceCtx Context) + { + int VibrationDeviceHandle = Context.RequestData.ReadInt32(); + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/IAppletResource.cs b/Ryujinx.HLE/HOS/Services/Hid/IAppletResource.cs new file mode 100644 index 00000000..012ccb40 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/IAppletResource.cs @@ -0,0 +1,34 @@ +using Ryujinx.HLE.HOS.Ipc; +using Ryujinx.HLE.HOS.Kernel; +using System.Collections.Generic; + +namespace Ryujinx.HLE.HOS.Services.Hid +{ + class IAppletResource : IpcService + { + private Dictionary m_Commands; + + public override IReadOnlyDictionary Commands => m_Commands; + + private KSharedMemory HidSharedMem; + + public IAppletResource(KSharedMemory HidSharedMem) + { + m_Commands = new Dictionary() + { + { 0, GetSharedMemoryHandle } + }; + + this.HidSharedMem = HidSharedMem; + } + + public long GetSharedMemoryHandle(ServiceCtx Context) + { + int Handle = Context.Process.HandleTable.OpenHandle(HidSharedMem); + + Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle); + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs b/Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs new file mode 100644 index 00000000..70f1f1f1 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs @@ -0,0 +1,299 @@ +using Ryujinx.HLE.HOS.Ipc; +using Ryujinx.HLE.HOS.Kernel; +using Ryujinx.HLE.Input; +using Ryujinx.HLE.Logging; +using System; +using System.Collections.Generic; + +namespace Ryujinx.HLE.HOS.Services.Hid +{ + class IHidServer : IpcService, IDisposable + { + private Dictionary m_Commands; + + private KEvent NpadStyleSetUpdateEvent; + + public override IReadOnlyDictionary Commands => m_Commands; + + public IHidServer() + { + m_Commands = new Dictionary() + { + { 0, CreateAppletResource }, + { 1, ActivateDebugPad }, + { 11, ActivateTouchScreen }, + { 21, ActivateMouse }, + { 31, ActivateKeyboard }, + { 66, StartSixAxisSensor }, + { 79, SetGyroscopeZeroDriftMode }, + { 100, SetSupportedNpadStyleSet }, + { 101, GetSupportedNpadStyleSet }, + { 102, SetSupportedNpadIdType }, + { 103, ActivateNpad }, + { 106, AcquireNpadStyleSetUpdateEventHandle }, + { 108, GetPlayerLedPattern }, + { 120, SetNpadJoyHoldType }, + { 121, GetNpadJoyHoldType }, + { 122, SetNpadJoyAssignmentModeSingleByDefault }, + { 123, SetNpadJoyAssignmentModeSingle }, + { 124, SetNpadJoyAssignmentModeDual }, + { 125, MergeSingleJoyAsDualJoy }, + { 128, SetNpadHandheldActivationMode }, + { 200, GetVibrationDeviceInfo }, + { 201, SendVibrationValue }, + { 203, CreateActiveVibrationDeviceList }, + { 206, SendVibrationValues } + }; + + NpadStyleSetUpdateEvent = new KEvent(); + } + + public long CreateAppletResource(ServiceCtx Context) + { + MakeObject(Context, new IAppletResource(Context.Device.System.HidSharedMem)); + + return 0; + } + + public long ActivateDebugPad(ServiceCtx Context) + { + Context.Device.Log.PrintStub(LogClass.ServiceHid, "Stubbed."); + + return 0; + } + + public long ActivateTouchScreen(ServiceCtx Context) + { + long AppletResourceUserId = Context.RequestData.ReadInt64(); + + Context.Device.Log.PrintStub(LogClass.ServiceHid, "Stubbed."); + + return 0; + } + + public long ActivateMouse(ServiceCtx Context) + { + long AppletResourceUserId = Context.RequestData.ReadInt64(); + + Context.Device.Log.PrintStub(LogClass.ServiceHid, "Stubbed."); + + return 0; + } + + public long ActivateKeyboard(ServiceCtx Context) + { + long AppletResourceUserId = Context.RequestData.ReadInt64(); + + Context.Device.Log.PrintStub(LogClass.ServiceHid, "Stubbed."); + + return 0; + } + + public long StartSixAxisSensor(ServiceCtx Context) + { + int Handle = Context.RequestData.ReadInt32(); + + long AppletResourceUserId = Context.RequestData.ReadInt64(); + + Context.Device.Log.PrintStub(LogClass.ServiceHid, "Stubbed."); + + return 0; + } + + public long SetGyroscopeZeroDriftMode(ServiceCtx Context) + { + int Handle = Context.RequestData.ReadInt32(); + int Unknown = Context.RequestData.ReadInt32(); + long AppletResourceUserId = Context.RequestData.ReadInt64(); + + Context.Device.Log.PrintStub(LogClass.ServiceHid, "Stubbed."); + + return 0; + } + + public long AcquireNpadStyleSetUpdateEventHandle(ServiceCtx Context) + { + int Handle = Context.Process.HandleTable.OpenHandle(NpadStyleSetUpdateEvent); + + Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle); + + return 0; + } + + public long GetSupportedNpadStyleSet(ServiceCtx Context) + { + Context.ResponseData.Write(0); + + Context.Device.Log.PrintStub(LogClass.ServiceHid, "Stubbed."); + + return 0; + } + + public long SetSupportedNpadStyleSet(ServiceCtx Context) + { + long Unknown0 = Context.RequestData.ReadInt64(); + long Unknown8 = Context.RequestData.ReadInt64(); + + Context.Device.Log.PrintStub(LogClass.ServiceHid, "Stubbed."); + + return 0; + } + + public long SetSupportedNpadIdType(ServiceCtx Context) + { + long Unknown = Context.RequestData.ReadInt64(); + + Context.Device.Log.PrintStub(LogClass.ServiceHid, "Stubbed."); + + return 0; + } + + public long ActivateNpad(ServiceCtx Context) + { + long Unknown = Context.RequestData.ReadInt64(); + + Context.Device.Log.PrintStub(LogClass.ServiceHid, "Stubbed."); + + return 0; + } + + public long GetPlayerLedPattern(ServiceCtx Context) + { + long Unknown = Context.RequestData.ReadInt32(); + + Context.ResponseData.Write(0L); + + Context.Device.Log.PrintStub(LogClass.ServiceHid, "Stubbed."); + + return 0; + } + + public long SetNpadJoyHoldType(ServiceCtx Context) + { + long Unknown0 = Context.RequestData.ReadInt64(); + long Unknown8 = Context.RequestData.ReadInt64(); + + Context.Device.Log.PrintStub(LogClass.ServiceHid, "Stubbed."); + + return 0; + } + + public long GetNpadJoyHoldType(ServiceCtx Context) + { + Context.ResponseData.Write(0L); + + Context.Device.Log.PrintStub(LogClass.ServiceHid, "Stubbed."); + + return 0; + } + + public long SetNpadJoyAssignmentModeSingleByDefault(ServiceCtx Context) + { + HidControllerId HidControllerId = (HidControllerId)Context.RequestData.ReadInt32(); + + long AppletUserResourceId = Context.RequestData.ReadInt64(); + + Context.Device.Log.PrintStub(LogClass.ServiceHid, "Stubbed."); + + return 0; + } + + public long SetNpadJoyAssignmentModeSingle(ServiceCtx Context) + { + HidControllerId HidControllerId = (HidControllerId)Context.RequestData.ReadInt32(); + + long AppletUserResourceId = Context.RequestData.ReadInt64(); + long NpadJoyDeviceType = Context.RequestData.ReadInt64(); + + Context.Device.Log.PrintStub(LogClass.ServiceHid, "Stubbed."); + + return 0; + } + + public long SetNpadJoyAssignmentModeDual(ServiceCtx Context) + { + HidControllerId HidControllerId = (HidControllerId)Context.RequestData.ReadInt32(); + + long AppletUserResourceId = Context.RequestData.ReadInt64(); + + Context.Device.Log.PrintStub(LogClass.ServiceHid, "Stubbed."); + + return 0; + } + + public long MergeSingleJoyAsDualJoy(ServiceCtx Context) + { + long Unknown0 = Context.RequestData.ReadInt32(); + long Unknown8 = Context.RequestData.ReadInt32(); + long AppletUserResourceId = Context.RequestData.ReadInt64(); + + Context.Device.Log.PrintStub(LogClass.ServiceHid, "Stubbed."); + + return 0; + } + + public long SetNpadHandheldActivationMode(ServiceCtx Context) + { + long AppletUserResourceId = Context.RequestData.ReadInt64(); + long Unknown = Context.RequestData.ReadInt64(); + + Context.Device.Log.PrintStub(LogClass.ServiceHid, "Stubbed."); + + return 0; + } + + public long GetVibrationDeviceInfo(ServiceCtx Context) + { + int VibrationDeviceHandle = Context.RequestData.ReadInt32(); + + Context.Device.Log.PrintStub(LogClass.ServiceHid, "Stubbed."); + + Context.ResponseData.Write(0L); //VibrationDeviceInfoForIpc + + return 0; + } + + public long SendVibrationValue(ServiceCtx Context) + { + int VibrationDeviceHandle = Context.RequestData.ReadInt32(); + + int VibrationValue1 = Context.RequestData.ReadInt32(); + int VibrationValue2 = Context.RequestData.ReadInt32(); + int VibrationValue3 = Context.RequestData.ReadInt32(); + int VibrationValue4 = Context.RequestData.ReadInt32(); + + long AppletUserResourceId = Context.RequestData.ReadInt64(); + + Context.Device.Log.PrintStub(LogClass.ServiceHid, "Stubbed."); + + return 0; + } + + public long CreateActiveVibrationDeviceList(ServiceCtx Context) + { + MakeObject(Context, new IActiveApplicationDeviceList()); + + return 0; + } + + public long SendVibrationValues(ServiceCtx Context) + { + Context.Device.Log.PrintStub(LogClass.ServiceHid, "Stubbed."); + + return 0; + } + + public void Dispose() + { + Dispose(true); + } + + protected virtual void Dispose(bool Disposing) + { + if (Disposing) + { + NpadStyleSetUpdateEvent.Dispose(); + } + } + } +} diff --git a/Ryujinx.HLE/HOS/Services/IIpcService.cs b/Ryujinx.HLE/HOS/Services/IIpcService.cs new file mode 100644 index 00000000..f6bafe97 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/IIpcService.cs @@ -0,0 +1,10 @@ +using Ryujinx.HLE.HOS.Ipc; +using System.Collections.Generic; + +namespace Ryujinx.HLE.HOS.Services +{ + interface IIpcService + { + IReadOnlyDictionary Commands { get; } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/IpcService.cs b/Ryujinx.HLE/HOS/Services/IpcService.cs new file mode 100644 index 00000000..8e487d55 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/IpcService.cs @@ -0,0 +1,183 @@ +using Ryujinx.HLE.HOS.Ipc; +using Ryujinx.HLE.HOS.Kernel; +using Ryujinx.HLE.Logging; +using System; +using System.Collections.Generic; +using System.IO; + +namespace Ryujinx.HLE.HOS.Services +{ + abstract class IpcService : IIpcService + { + public abstract IReadOnlyDictionary Commands { get; } + + private IdDictionary DomainObjects; + + private int SelfId; + + private bool IsDomain; + + public IpcService() + { + DomainObjects = new IdDictionary(); + + SelfId = -1; + } + + public int ConvertToDomain() + { + if (SelfId == -1) + { + SelfId = DomainObjects.Add(this); + } + + IsDomain = true; + + return SelfId; + } + + public void ConvertToSession() + { + IsDomain = false; + } + + public void CallMethod(ServiceCtx Context) + { + IIpcService Service = this; + + if (IsDomain) + { + int DomainWord0 = Context.RequestData.ReadInt32(); + int DomainObjId = Context.RequestData.ReadInt32(); + + int DomainCmd = (DomainWord0 >> 0) & 0xff; + int InputObjCount = (DomainWord0 >> 8) & 0xff; + int DataPayloadSize = (DomainWord0 >> 16) & 0xffff; + + Context.RequestData.BaseStream.Seek(0x10 + DataPayloadSize, SeekOrigin.Begin); + + for (int Index = 0; Index < InputObjCount; Index++) + { + Context.Request.ObjectIds.Add(Context.RequestData.ReadInt32()); + } + + Context.RequestData.BaseStream.Seek(0x10, SeekOrigin.Begin); + + if (DomainCmd == 1) + { + Service = GetObject(DomainObjId); + + Context.ResponseData.Write(0L); + Context.ResponseData.Write(0L); + } + else if (DomainCmd == 2) + { + Delete(DomainObjId); + + Context.ResponseData.Write(0L); + + return; + } + else + { + throw new NotImplementedException($"Domain command: {DomainCmd}"); + } + } + + long SfciMagic = Context.RequestData.ReadInt64(); + int CommandId = (int)Context.RequestData.ReadInt64(); + + if (Service.Commands.TryGetValue(CommandId, out ServiceProcessRequest ProcessRequest)) + { + Context.ResponseData.BaseStream.Seek(IsDomain ? 0x20 : 0x10, SeekOrigin.Begin); + + Context.Device.Log.PrintDebug(LogClass.KernelIpc, $"{Service.GetType().Name}: {ProcessRequest.Method.Name}"); + + long Result = ProcessRequest(Context); + + if (IsDomain) + { + foreach (int Id in Context.Response.ObjectIds) + { + Context.ResponseData.Write(Id); + } + + Context.ResponseData.BaseStream.Seek(0, SeekOrigin.Begin); + + Context.ResponseData.Write(Context.Response.ObjectIds.Count); + } + + Context.ResponseData.BaseStream.Seek(IsDomain ? 0x10 : 0, SeekOrigin.Begin); + + Context.ResponseData.Write(IpcMagic.Sfco); + Context.ResponseData.Write(Result); + } + else + { + string DbgMessage = $"{Context.Session.ServiceName} {Service.GetType().Name}: {CommandId}"; + + throw new NotImplementedException(DbgMessage); + } + } + + protected static void MakeObject(ServiceCtx Context, IpcService Obj) + { + IpcService Service = Context.Session.Service; + + if (Service.IsDomain) + { + Context.Response.ObjectIds.Add(Service.Add(Obj)); + } + else + { + KSession Session = new KSession(Obj, Context.Session.ServiceName); + + int Handle = Context.Process.HandleTable.OpenHandle(Session); + + Context.Response.HandleDesc = IpcHandleDesc.MakeMove(Handle); + } + } + + protected static T GetObject(ServiceCtx Context, int Index) where T : IpcService + { + IpcService Service = Context.Session.Service; + + if (!Service.IsDomain) + { + int Handle = Context.Request.HandleDesc.ToMove[Index]; + + KSession Session = Context.Process.HandleTable.GetData(Handle); + + return Session?.Service is T ? (T)Session.Service : null; + } + + int ObjId = Context.Request.ObjectIds[Index]; + + IIpcService Obj = Service.GetObject(ObjId); + + return Obj is T ? (T)Obj : null; + } + + private int Add(IIpcService Obj) + { + return DomainObjects.Add(Obj); + } + + private bool Delete(int Id) + { + object Obj = DomainObjects.Delete(Id); + + if (Obj is IDisposable DisposableObj) + { + DisposableObj.Dispose(); + } + + return Obj != null; + } + + private IIpcService GetObject(int Id) + { + return DomainObjects.GetData(Id); + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Lm/ILogService.cs b/Ryujinx.HLE/HOS/Services/Lm/ILogService.cs new file mode 100644 index 00000000..d79da515 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Lm/ILogService.cs @@ -0,0 +1,27 @@ +using Ryujinx.HLE.HOS.Ipc; +using System.Collections.Generic; + +namespace Ryujinx.HLE.HOS.Services.Lm +{ + class ILogService : IpcService + { + private Dictionary m_Commands; + + public override IReadOnlyDictionary Commands => m_Commands; + + public ILogService() + { + m_Commands = new Dictionary() + { + { 0, Initialize } + }; + } + + public long Initialize(ServiceCtx Context) + { + MakeObject(Context, new ILogger()); + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Lm/ILogger.cs b/Ryujinx.HLE/HOS/Services/Lm/ILogger.cs new file mode 100644 index 00000000..42d57c6f --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Lm/ILogger.cs @@ -0,0 +1,86 @@ +using Ryujinx.HLE.HOS.Ipc; +using Ryujinx.HLE.Logging; +using System.Collections.Generic; +using System.IO; +using System.Text; + +namespace Ryujinx.HLE.HOS.Services.Lm +{ + class ILogger : IpcService + { + private Dictionary m_Commands; + + public override IReadOnlyDictionary Commands => m_Commands; + + public ILogger() + { + m_Commands = new Dictionary() + { + { 0, Log } + }; + } + + public long Log(ServiceCtx Context) + { + byte[] LogBuffer = Context.Memory.ReadBytes( + Context.Request.PtrBuff[0].Position, + Context.Request.PtrBuff[0].Size); + + using (MemoryStream MS = new MemoryStream(LogBuffer)) + { + BinaryReader Reader = new BinaryReader(MS); + + long Pid = Reader.ReadInt64(); + long ThreadContext = Reader.ReadInt64(); + short Flags = Reader.ReadInt16(); + byte Level = Reader.ReadByte(); + byte Verbosity = Reader.ReadByte(); + int PayloadLength = Reader.ReadInt32(); + + StringBuilder SB = new StringBuilder(); + + SB.AppendLine("Guest log:"); + + while (MS.Position < MS.Length) + { + byte Type = Reader.ReadByte(); + byte Size = Reader.ReadByte(); + + LmLogField Field = (LmLogField)Type; + + string FieldStr = string.Empty; + + if (Field == LmLogField.Skip) + { + Reader.ReadByte(); + + continue; + } + else if (Field == LmLogField.Line) + { + FieldStr = Field + ": " + Reader.ReadInt32(); + } + else + { + FieldStr = Field + ": \"" + Encoding.UTF8.GetString(Reader.ReadBytes(Size)) + "\""; + } + + SB.AppendLine(" " + FieldStr); + } + + string Text = SB.ToString(); + + switch((LmLogLevel)Level) + { + case LmLogLevel.Trace: Context.Device.Log.PrintDebug (LogClass.ServiceLm, Text); break; + case LmLogLevel.Info: Context.Device.Log.PrintInfo (LogClass.ServiceLm, Text); break; + case LmLogLevel.Warning: Context.Device.Log.PrintWarning(LogClass.ServiceLm, Text); break; + case LmLogLevel.Error: Context.Device.Log.PrintError (LogClass.ServiceLm, Text); break; + case LmLogLevel.Critical: Context.Device.Log.PrintError (LogClass.ServiceLm, Text); break; + } + } + + return 0; + } + } +} diff --git a/Ryujinx.HLE/HOS/Services/Lm/LmLogField.cs b/Ryujinx.HLE/HOS/Services/Lm/LmLogField.cs new file mode 100644 index 00000000..bd8c8e88 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Lm/LmLogField.cs @@ -0,0 +1,13 @@ +namespace Ryujinx.HLE.HOS.Services.Lm +{ + enum LmLogField + { + Skip = 1, + Message = 2, + Line = 3, + Filename = 4, + Function = 5, + Module = 6, + Thread = 7 + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Lm/LmLogLevel.cs b/Ryujinx.HLE/HOS/Services/Lm/LmLogLevel.cs new file mode 100644 index 00000000..70554c42 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Lm/LmLogLevel.cs @@ -0,0 +1,11 @@ +namespace Ryujinx.HLE.HOS.Services.Lm +{ + enum LmLogLevel + { + Trace, + Info, + Warning, + Error, + Critical + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Mm/IRequest.cs b/Ryujinx.HLE/HOS/Services/Mm/IRequest.cs new file mode 100644 index 00000000..e65ef086 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Mm/IRequest.cs @@ -0,0 +1,46 @@ +using Ryujinx.HLE.HOS.Ipc; +using Ryujinx.HLE.Logging; +using System.Collections.Generic; + +namespace Ryujinx.HLE.HOS.Services.Mm +{ + class IRequest : IpcService + { + private Dictionary m_Commands; + + public override IReadOnlyDictionary Commands => m_Commands; + + public IRequest() + { + m_Commands = new Dictionary() + { + { 4, Initialize }, + { 6, SetAndWait }, + { 7, Get } + }; + } + + public long Initialize(ServiceCtx Context) + { + Context.Device.Log.PrintStub(LogClass.ServiceMm, "Stubbed."); + + return 0; + } + + public long SetAndWait(ServiceCtx Context) + { + Context.Device.Log.PrintStub(LogClass.ServiceMm, "Stubbed."); + + return 0; + } + + public long Get(ServiceCtx Context) + { + Context.ResponseData.Write(0); + + Context.Device.Log.PrintStub(LogClass.ServiceMm, "Stubbed."); + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nfp/DeviceState.cs b/Ryujinx.HLE/HOS/Services/Nfp/DeviceState.cs new file mode 100644 index 00000000..04527893 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nfp/DeviceState.cs @@ -0,0 +1,7 @@ +namespace Ryujinx.HLE.HOS.Services.Nfp +{ + enum DeviceState + { + Initialized = 0 + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nfp/IUser.cs b/Ryujinx.HLE/HOS/Services/Nfp/IUser.cs new file mode 100644 index 00000000..eac90da4 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nfp/IUser.cs @@ -0,0 +1,114 @@ +using Ryujinx.HLE.HOS.Ipc; +using Ryujinx.HLE.HOS.Kernel; +using Ryujinx.HLE.Input; +using Ryujinx.HLE.Logging; +using System.Collections.Generic; + +namespace Ryujinx.HLE.HOS.Services.Nfp +{ + class IUser : IpcService + { + private Dictionary m_Commands; + + public override IReadOnlyDictionary Commands => m_Commands; + + private const HidControllerId NpadId = HidControllerId.CONTROLLER_PLAYER_1; + + private State State = State.NonInitialized; + + private DeviceState DeviceState = DeviceState.Initialized; + + private KEvent ActivateEvent; + + private KEvent DeactivateEvent; + + private KEvent AvailabilityChangeEvent; + + public IUser() + { + m_Commands = new Dictionary() + { + { 0, Initialize }, + { 17, AttachActivateEvent }, + { 18, AttachDeactivateEvent }, + { 19, GetState }, + { 20, GetDeviceState }, + { 21, GetNpadId }, + { 23, AttachAvailabilityChangeEvent } + }; + + ActivateEvent = new KEvent(); + DeactivateEvent = new KEvent(); + AvailabilityChangeEvent = new KEvent(); + } + + public long Initialize(ServiceCtx Context) + { + Context.Device.Log.PrintStub(LogClass.ServiceNfp, "Stubbed."); + + State = State.Initialized; + + return 0; + } + + public long AttachActivateEvent(ServiceCtx Context) + { + Context.Device.Log.PrintStub(LogClass.ServiceNfp, "Stubbed."); + + int Handle = Context.Process.HandleTable.OpenHandle(ActivateEvent); + + Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle);; + + return 0; + } + + public long AttachDeactivateEvent(ServiceCtx Context) + { + Context.Device.Log.PrintStub(LogClass.ServiceNfp, "Stubbed."); + + int Handle = Context.Process.HandleTable.OpenHandle(DeactivateEvent); + + Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle); + + return 0; + } + + public long GetState(ServiceCtx Context) + { + Context.ResponseData.Write((int)State); + + Context.Device.Log.PrintStub(LogClass.ServiceNfp, "Stubbed."); + + return 0; + } + + public long GetDeviceState(ServiceCtx Context) + { + Context.ResponseData.Write((int)DeviceState); + + Context.Device.Log.PrintStub(LogClass.ServiceNfp, "Stubbed."); + + return 0; + } + + public long GetNpadId(ServiceCtx Context) + { + Context.ResponseData.Write((int)NpadId); + + Context.Device.Log.PrintStub(LogClass.ServiceNfp, "Stubbed."); + + return 0; + } + + public long AttachAvailabilityChangeEvent(ServiceCtx Context) + { + Context.Device.Log.PrintStub(LogClass.ServiceNfp, "Stubbed."); + + int Handle = Context.Process.HandleTable.OpenHandle(AvailabilityChangeEvent); + + Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle); + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nfp/IUserManager.cs b/Ryujinx.HLE/HOS/Services/Nfp/IUserManager.cs new file mode 100644 index 00000000..770f0341 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nfp/IUserManager.cs @@ -0,0 +1,27 @@ +using Ryujinx.HLE.HOS.Ipc; +using System.Collections.Generic; + +namespace Ryujinx.HLE.HOS.Services.Nfp +{ + class IUserManager : IpcService + { + private Dictionary m_Commands; + + public override IReadOnlyDictionary Commands => m_Commands; + + public IUserManager() + { + m_Commands = new Dictionary() + { + { 0, GetUserInterface } + }; + } + + public long GetUserInterface(ServiceCtx Context) + { + MakeObject(Context, new IUser()); + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nfp/State.cs b/Ryujinx.HLE/HOS/Services/Nfp/State.cs new file mode 100644 index 00000000..0b4b3c1b --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nfp/State.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Nfp +{ + enum State + { + NonInitialized = 0, + Initialized = 1 + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nifm/IGeneralService.cs b/Ryujinx.HLE/HOS/Services/Nifm/IGeneralService.cs new file mode 100644 index 00000000..ec68247b --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nifm/IGeneralService.cs @@ -0,0 +1,58 @@ +using Ryujinx.HLE.HOS.Ipc; +using Ryujinx.HLE.Logging; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Net.NetworkInformation; +using System.Net.Sockets; + +using static Ryujinx.HLE.HOS.ErrorCode; + +namespace Ryujinx.HLE.HOS.Services.Nifm +{ + class IGeneralService : IpcService + { + private Dictionary m_Commands; + + public override IReadOnlyDictionary Commands => m_Commands; + + public IGeneralService() + { + m_Commands = new Dictionary() + { + { 4, CreateRequest }, + { 12, GetCurrentIpAddress } + }; + } + + public long CreateRequest(ServiceCtx Context) + { + int Unknown = Context.RequestData.ReadInt32(); + + MakeObject(Context, new IRequest()); + + Context.Device.Log.PrintStub(LogClass.ServiceNifm, "Stubbed."); + + return 0; + } + + public long GetCurrentIpAddress(ServiceCtx Context) + { + if (!NetworkInterface.GetIsNetworkAvailable()) + { + return MakeError(ErrorModule.Nifm, NifmErr.NoInternetConnection); + } + + IPHostEntry Host = Dns.GetHostEntry(Dns.GetHostName()); + + IPAddress Address = Host.AddressList.FirstOrDefault(A => A.AddressFamily == AddressFamily.InterNetwork); + + Context.ResponseData.Write(BitConverter.ToUInt32(Address.GetAddressBytes())); + + Context.Device.Log.PrintInfo(LogClass.ServiceNifm, $"Console's local IP is \"{Address}\"."); + + return 0; + } + } +} diff --git a/Ryujinx.HLE/HOS/Services/Nifm/IRequest.cs b/Ryujinx.HLE/HOS/Services/Nifm/IRequest.cs new file mode 100644 index 00000000..7bd30ff9 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nifm/IRequest.cs @@ -0,0 +1,95 @@ +using Ryujinx.HLE.HOS.Ipc; +using Ryujinx.HLE.HOS.Kernel; +using Ryujinx.HLE.Logging; +using System; +using System.Collections.Generic; + +namespace Ryujinx.HLE.HOS.Services.Nifm +{ + class IRequest : IpcService, IDisposable + { + private Dictionary m_Commands; + + public override IReadOnlyDictionary Commands => m_Commands; + + private KEvent Event0; + private KEvent Event1; + + public IRequest() + { + m_Commands = new Dictionary() + { + { 0, GetRequestState }, + { 1, GetResult }, + { 2, GetSystemEventReadableHandles }, + { 3, Cancel }, + { 4, Submit }, + { 11, SetConnectionConfirmationOption } + }; + + Event0 = new KEvent(); + Event1 = new KEvent(); + } + + public long GetRequestState(ServiceCtx Context) + { + Context.ResponseData.Write(1); + + Context.Device.Log.PrintStub(LogClass.ServiceNifm, "Stubbed."); + + return 0; + } + + public long GetResult(ServiceCtx Context) + { + Context.Device.Log.PrintStub(LogClass.ServiceNifm, "Stubbed."); + + return 0; + } + + public long GetSystemEventReadableHandles(ServiceCtx Context) + { + int Handle0 = Context.Process.HandleTable.OpenHandle(Event0); + int Handle1 = Context.Process.HandleTable.OpenHandle(Event1); + + Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle0, Handle1); + + return 0; + } + + public long Cancel(ServiceCtx Context) + { + Context.Device.Log.PrintStub(LogClass.ServiceNifm, "Stubbed."); + + return 0; + } + + public long Submit(ServiceCtx Context) + { + Context.Device.Log.PrintStub(LogClass.ServiceNifm, "Stubbed."); + + return 0; + } + + public long SetConnectionConfirmationOption(ServiceCtx Context) + { + Context.Device.Log.PrintStub(LogClass.ServiceNifm, "Stubbed."); + + return 0; + } + + public void Dispose() + { + Dispose(true); + } + + protected virtual void Dispose(bool Disposing) + { + if (Disposing) + { + Event0.Dispose(); + Event1.Dispose(); + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nifm/IStaticService.cs b/Ryujinx.HLE/HOS/Services/Nifm/IStaticService.cs new file mode 100644 index 00000000..19e7d247 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nifm/IStaticService.cs @@ -0,0 +1,35 @@ +using Ryujinx.HLE.HOS.Ipc; +using System.Collections.Generic; + +namespace Ryujinx.HLE.HOS.Services.Nifm +{ + class IStaticService : IpcService + { + private Dictionary m_Commands; + + public override IReadOnlyDictionary Commands => m_Commands; + + public IStaticService() + { + m_Commands = new Dictionary() + { + { 4, CreateGeneralServiceOld }, + { 5, CreateGeneralService } + }; + } + + public long CreateGeneralServiceOld(ServiceCtx Context) + { + MakeObject(Context, new IGeneralService()); + + return 0; + } + + public long CreateGeneralService(ServiceCtx Context) + { + MakeObject(Context, new IGeneralService()); + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nifm/NifmErr.cs b/Ryujinx.HLE/HOS/Services/Nifm/NifmErr.cs new file mode 100644 index 00000000..3abeb838 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nifm/NifmErr.cs @@ -0,0 +1,7 @@ +namespace Ryujinx.HLE.HOS.Services.Nifm +{ + static class NifmErr + { + public const int NoInternetConnection = 300; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Ns/IAddOnContentManager.cs b/Ryujinx.HLE/HOS/Services/Ns/IAddOnContentManager.cs new file mode 100644 index 00000000..b8455d41 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Ns/IAddOnContentManager.cs @@ -0,0 +1,42 @@ +using Ryujinx.HLE.HOS.Ipc; +using Ryujinx.HLE.Logging; +using System.Collections.Generic; + +namespace Ryujinx.HLE.HOS.Services.Ns +{ + class IAddOnContentManager : IpcService + { + private Dictionary m_Commands; + + public override IReadOnlyDictionary Commands => m_Commands; + + public IAddOnContentManager() + { + m_Commands = new Dictionary() + { + { 2, CountAddOnContent }, + { 3, ListAddOnContent } + }; + } + + public static long CountAddOnContent(ServiceCtx Context) + { + Context.ResponseData.Write(0); + + Context.Device.Log.PrintStub(LogClass.ServiceNs, "Stubbed."); + + return 0; + } + + public static long ListAddOnContent(ServiceCtx Context) + { + Context.Device.Log.PrintStub(LogClass.ServiceNs, "Stubbed."); + + //TODO: This is supposed to write a u32 array aswell. + //It's unknown what it contains. + Context.ResponseData.Write(0); + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Ns/IServiceGetterInterface.cs b/Ryujinx.HLE/HOS/Services/Ns/IServiceGetterInterface.cs new file mode 100644 index 00000000..a27cfe60 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Ns/IServiceGetterInterface.cs @@ -0,0 +1,20 @@ +using Ryujinx.HLE.HOS.Ipc; +using System.Collections.Generic; + +namespace Ryujinx.HLE.HOS.Services.Ns +{ + class IServiceGetterInterface : IpcService + { + private Dictionary m_Commands; + + public override IReadOnlyDictionary Commands => m_Commands; + + public IServiceGetterInterface() + { + m_Commands = new Dictionary() + { + //... + }; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Ns/ISystemUpdateInterface.cs b/Ryujinx.HLE/HOS/Services/Ns/ISystemUpdateInterface.cs new file mode 100644 index 00000000..6ade8865 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Ns/ISystemUpdateInterface.cs @@ -0,0 +1,20 @@ +using Ryujinx.HLE.HOS.Ipc; +using System.Collections.Generic; + +namespace Ryujinx.HLE.HOS.Services.Ns +{ + class ISystemUpdateInterface : IpcService + { + private Dictionary m_Commands; + + public override IReadOnlyDictionary Commands => m_Commands; + + public ISystemUpdateInterface() + { + m_Commands = new Dictionary() + { + //... + }; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Ns/IVulnerabilityManagerInterface.cs b/Ryujinx.HLE/HOS/Services/Ns/IVulnerabilityManagerInterface.cs new file mode 100644 index 00000000..cff334c0 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Ns/IVulnerabilityManagerInterface.cs @@ -0,0 +1,20 @@ +using Ryujinx.HLE.HOS.Ipc; +using System.Collections.Generic; + +namespace Ryujinx.HLE.HOS.Services.Ns +{ + class IVulnerabilityManagerInterface : IpcService + { + private Dictionary m_Commands; + + public override IReadOnlyDictionary Commands => m_Commands; + + public IVulnerabilityManagerInterface() + { + m_Commands = new Dictionary() + { + //... + }; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/INvDrvServices.cs b/Ryujinx.HLE/HOS/Services/Nv/INvDrvServices.cs new file mode 100644 index 00000000..bfc76931 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/INvDrvServices.cs @@ -0,0 +1,231 @@ +using ChocolArm64.Memory; +using Ryujinx.HLE.HOS.Ipc; +using Ryujinx.HLE.HOS.Kernel; +using Ryujinx.HLE.HOS.Services.Nv.NvGpuAS; +using Ryujinx.HLE.HOS.Services.Nv.NvGpuGpu; +using Ryujinx.HLE.HOS.Services.Nv.NvHostChannel; +using Ryujinx.HLE.HOS.Services.Nv.NvHostCtrl; +using Ryujinx.HLE.HOS.Services.Nv.NvMap; +using Ryujinx.HLE.Logging; +using System; +using System.Collections.Generic; + +namespace Ryujinx.HLE.HOS.Services.Nv +{ + class INvDrvServices : IpcService, IDisposable + { + private delegate int IoctlProcessor(ServiceCtx Context, int Cmd); + + private Dictionary m_Commands; + + public override IReadOnlyDictionary Commands => m_Commands; + + private static Dictionary IoctlProcessors = + new Dictionary() + { + { "/dev/nvhost-as-gpu", ProcessIoctlNvGpuAS }, + { "/dev/nvhost-ctrl", ProcessIoctlNvHostCtrl }, + { "/dev/nvhost-ctrl-gpu", ProcessIoctlNvGpuGpu }, + { "/dev/nvhost-gpu", ProcessIoctlNvHostGpu }, + { "/dev/nvmap", ProcessIoctlNvMap } + }; + + public static GlobalStateTable Fds { get; private set; } + + private KEvent Event; + + public INvDrvServices() + { + m_Commands = new Dictionary() + { + { 0, Open }, + { 1, Ioctl }, + { 2, Close }, + { 3, Initialize }, + { 4, QueryEvent }, + { 8, SetClientPid }, + { 11, Ioctl }, + { 13, FinishInitialize } + }; + + Event = new KEvent(); + } + + static INvDrvServices() + { + Fds = new GlobalStateTable(); + } + + public long Open(ServiceCtx Context) + { + long NamePtr = Context.Request.SendBuff[0].Position; + + string Name = AMemoryHelper.ReadAsciiString(Context.Memory, NamePtr); + + int Fd = Fds.Add(Context.Process, new NvFd(Name)); + + Context.ResponseData.Write(Fd); + Context.ResponseData.Write(0); + + return 0; + } + + public long Ioctl(ServiceCtx Context) + { + int Fd = Context.RequestData.ReadInt32(); + int Cmd = Context.RequestData.ReadInt32(); + + NvFd FdData = Fds.GetData(Context.Process, Fd); + + int Result; + + if (IoctlProcessors.TryGetValue(FdData.Name, out IoctlProcessor Process)) + { + Result = Process(Context, Cmd); + } + else + { + throw new NotImplementedException($"{FdData.Name} {Cmd:x4}"); + } + + //TODO: Verify if the error codes needs to be translated. + Context.ResponseData.Write(Result); + + return 0; + } + + public long Close(ServiceCtx Context) + { + int Fd = Context.RequestData.ReadInt32(); + + Fds.Delete(Context.Process, Fd); + + Context.ResponseData.Write(0); + + return 0; + } + + public long Initialize(ServiceCtx Context) + { + long TransferMemSize = Context.RequestData.ReadInt64(); + int TransferMemHandle = Context.Request.HandleDesc.ToCopy[0]; + + NvMapIoctl.InitializeNvMap(Context); + + Context.ResponseData.Write(0); + + return 0; + } + + public long QueryEvent(ServiceCtx Context) + { + int Fd = Context.RequestData.ReadInt32(); + int EventId = Context.RequestData.ReadInt32(); + + //TODO: Use Fd/EventId, different channels have different events. + int Handle = Context.Process.HandleTable.OpenHandle(Event); + + Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle); + + Context.ResponseData.Write(0); + + return 0; + } + + public long SetClientPid(ServiceCtx Context) + { + long Pid = Context.RequestData.ReadInt64(); + + Context.ResponseData.Write(0); + + return 0; + } + + public long FinishInitialize(ServiceCtx Context) + { + Context.Device.Log.PrintStub(LogClass.ServiceNv, "Stubbed."); + + return 0; + } + + private static int ProcessIoctlNvGpuAS(ServiceCtx Context, int Cmd) + { + return ProcessIoctl(Context, Cmd, NvGpuASIoctl.ProcessIoctl); + } + + private static int ProcessIoctlNvHostCtrl(ServiceCtx Context, int Cmd) + { + return ProcessIoctl(Context, Cmd, NvHostCtrlIoctl.ProcessIoctl); + } + + private static int ProcessIoctlNvGpuGpu(ServiceCtx Context, int Cmd) + { + return ProcessIoctl(Context, Cmd, NvGpuGpuIoctl.ProcessIoctl); + } + + private static int ProcessIoctlNvHostGpu(ServiceCtx Context, int Cmd) + { + return ProcessIoctl(Context, Cmd, NvHostChannelIoctl.ProcessIoctlGpu); + } + + private static int ProcessIoctlNvMap(ServiceCtx Context, int Cmd) + { + return ProcessIoctl(Context, Cmd, NvMapIoctl.ProcessIoctl); + } + + private static int ProcessIoctl(ServiceCtx Context, int Cmd, IoctlProcessor Processor) + { + if (CmdIn(Cmd) && Context.Request.GetBufferType0x21().Position == 0) + { + Context.Device.Log.PrintError(LogClass.ServiceNv, "Input buffer is null!"); + + return NvResult.InvalidInput; + } + + if (CmdOut(Cmd) && Context.Request.GetBufferType0x22().Position == 0) + { + Context.Device.Log.PrintError(LogClass.ServiceNv, "Output buffer is null!"); + + return NvResult.InvalidInput; + } + + return Processor(Context, Cmd); + } + + private static bool CmdIn(int Cmd) + { + return ((Cmd >> 30) & 1) != 0; + } + + private static bool CmdOut(int Cmd) + { + return ((Cmd >> 31) & 1) != 0; + } + + public static void UnloadProcess(Process Process) + { + Fds.DeleteProcess(Process); + + NvGpuASIoctl.UnloadProcess(Process); + + NvHostChannelIoctl.UnloadProcess(Process); + + NvHostCtrlIoctl.UnloadProcess(Process); + + NvMapIoctl.UnloadProcess(Process); + } + + public void Dispose() + { + Dispose(true); + } + + protected virtual void Dispose(bool Disposing) + { + if (Disposing) + { + Event.Dispose(); + } + } + } +} diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvFd.cs b/Ryujinx.HLE/HOS/Services/Nv/NvFd.cs new file mode 100644 index 00000000..96f97f41 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvFd.cs @@ -0,0 +1,12 @@ +namespace Ryujinx.HLE.HOS.Services.Nv +{ + class NvFd + { + public string Name { get; private set; } + + public NvFd(string Name) + { + this.Name = Name; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvGpuAS/NvGpuASAllocSpace.cs b/Ryujinx.HLE/HOS/Services/Nv/NvGpuAS/NvGpuASAllocSpace.cs new file mode 100644 index 00000000..bca2f9f4 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvGpuAS/NvGpuASAllocSpace.cs @@ -0,0 +1,11 @@ +namespace Ryujinx.HLE.HOS.Services.Nv.NvGpuAS +{ + struct NvGpuASAllocSpace + { + public int Pages; + public int PageSize; + public int Flags; + public int Padding; + public long Offset; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvGpuAS/NvGpuASCtx.cs b/Ryujinx.HLE/HOS/Services/Nv/NvGpuAS/NvGpuASCtx.cs new file mode 100644 index 00000000..d69ec719 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvGpuAS/NvGpuASCtx.cs @@ -0,0 +1,197 @@ +using Ryujinx.HLE.Gpu.Memory; +using System.Collections.Generic; + +namespace Ryujinx.HLE.HOS.Services.Nv.NvGpuAS +{ + class NvGpuASCtx + { + public NvGpuVmm Vmm { get; private set; } + + private class Range + { + public ulong Start { get; private set; } + public ulong End { get; private set; } + + public Range(long Position, long Size) + { + Start = (ulong)Position; + End = (ulong)Size + Start; + } + } + + private class MappedMemory : Range + { + public long PhysicalAddress { get; private set; } + public bool VaAllocated { get; private set; } + + public MappedMemory( + long Position, + long Size, + long PhysicalAddress, + bool VaAllocated) : base(Position, Size) + { + this.PhysicalAddress = PhysicalAddress; + this.VaAllocated = VaAllocated; + } + } + + private SortedList Maps; + private SortedList Reservations; + + public NvGpuASCtx(ServiceCtx Context) + { + Vmm = new NvGpuVmm(Context.Memory); + + Maps = new SortedList(); + Reservations = new SortedList(); + } + + public bool ValidateFixedBuffer(long Position, long Size) + { + long MapEnd = Position + Size; + + //Check if size is valid (0 is also not allowed). + if ((ulong)MapEnd <= (ulong)Position) + { + return false; + } + + //Check if address is page aligned. + if ((Position & NvGpuVmm.PageMask) != 0) + { + return false; + } + + //Check if region is reserved. + if (BinarySearch(Reservations, Position) == null) + { + return false; + } + + //Check for overlap with already mapped buffers. + Range Map = BinarySearchLt(Maps, MapEnd); + + if (Map != null && Map.End > (ulong)Position) + { + return false; + } + + return true; + } + + public void AddMap( + long Position, + long Size, + long PhysicalAddress, + bool VaAllocated) + { + Maps.Add(Position, new MappedMemory(Position, Size, PhysicalAddress, VaAllocated)); + } + + public bool RemoveMap(long Position, out long Size) + { + Size = 0; + + if (Maps.Remove(Position, out Range Value)) + { + MappedMemory Map = (MappedMemory)Value; + + if (Map.VaAllocated) + { + Size = (long)(Map.End - Map.Start); + } + + return true; + } + + return false; + } + + public bool TryGetMapPhysicalAddress(long Position, out long PhysicalAddress) + { + Range Map = BinarySearch(Maps, Position); + + if (Map != null) + { + PhysicalAddress = ((MappedMemory)Map).PhysicalAddress; + + return true; + } + + PhysicalAddress = 0; + + return false; + } + + public void AddReservation(long Position, long Size) + { + Reservations.Add(Position, new Range(Position, Size)); + } + + public bool RemoveReservation(long Position) + { + return Reservations.Remove(Position); + } + + private Range BinarySearch(SortedList Lst, long Position) + { + int Left = 0; + int Right = Lst.Count - 1; + + while (Left <= Right) + { + int Size = Right - Left; + + int Middle = Left + (Size >> 1); + + Range Rg = Lst.Values[Middle]; + + if ((ulong)Position >= Rg.Start && (ulong)Position < Rg.End) + { + return Rg; + } + + if ((ulong)Position < Rg.Start) + { + Right = Middle - 1; + } + else + { + Left = Middle + 1; + } + } + + return null; + } + + private Range BinarySearchLt(SortedList Lst, long Position) + { + Range LtRg = null; + + int Left = 0; + int Right = Lst.Count - 1; + + while (Left <= Right) + { + int Size = Right - Left; + + int Middle = Left + (Size >> 1); + + Range Rg = Lst.Values[Middle]; + + if ((ulong)Position < Rg.Start) + { + Right = Middle - 1; + } + else + { + Left = Middle + 1; + + LtRg = Rg; + } + } + + return LtRg; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvGpuAS/NvGpuASIoctl.cs b/Ryujinx.HLE/HOS/Services/Nv/NvGpuAS/NvGpuASIoctl.cs new file mode 100644 index 00000000..c9be18ea --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvGpuAS/NvGpuASIoctl.cs @@ -0,0 +1,329 @@ +using ChocolArm64.Memory; +using Ryujinx.HLE.Gpu.Memory; +using Ryujinx.HLE.HOS.Services.Nv.NvMap; +using Ryujinx.HLE.Logging; +using System; +using System.Collections.Concurrent; + +namespace Ryujinx.HLE.HOS.Services.Nv.NvGpuAS +{ + class NvGpuASIoctl + { + private const int FlagFixedOffset = 1; + + private const int FlagRemapSubRange = 0x100; + + private static ConcurrentDictionary ASCtxs; + + static NvGpuASIoctl() + { + ASCtxs = new ConcurrentDictionary(); + } + + public static int ProcessIoctl(ServiceCtx Context, int Cmd) + { + switch (Cmd & 0xffff) + { + case 0x4101: return BindChannel (Context); + case 0x4102: return AllocSpace (Context); + case 0x4103: return FreeSpace (Context); + case 0x4105: return UnmapBuffer (Context); + case 0x4106: return MapBufferEx (Context); + case 0x4108: return GetVaRegions(Context); + case 0x4109: return InitializeEx(Context); + case 0x4114: return Remap (Context, Cmd); + } + + throw new NotImplementedException(Cmd.ToString("x8")); + } + + private static int BindChannel(ServiceCtx Context) + { + long InputPosition = Context.Request.GetBufferType0x21().Position; + long OutputPosition = Context.Request.GetBufferType0x22().Position; + + Context.Device.Log.PrintStub(LogClass.ServiceNv, "Stubbed."); + + return NvResult.Success; + } + + private static int AllocSpace(ServiceCtx Context) + { + long InputPosition = Context.Request.GetBufferType0x21().Position; + long OutputPosition = Context.Request.GetBufferType0x22().Position; + + NvGpuASAllocSpace Args = AMemoryHelper.Read(Context.Memory, InputPosition); + + NvGpuASCtx ASCtx = GetASCtx(Context); + + ulong Size = (ulong)Args.Pages * + (ulong)Args.PageSize; + + int Result = NvResult.Success; + + lock (ASCtx) + { + //Note: When the fixed offset flag is not set, + //the Offset field holds the alignment size instead. + if ((Args.Flags & FlagFixedOffset) != 0) + { + Args.Offset = ASCtx.Vmm.ReserveFixed(Args.Offset, (long)Size); + } + else + { + Args.Offset = ASCtx.Vmm.Reserve((long)Size, Args.Offset); + } + + if (Args.Offset < 0) + { + Args.Offset = 0; + + Context.Device.Log.PrintWarning(LogClass.ServiceNv, $"Failed to allocate size {Size:x16}!"); + + Result = NvResult.OutOfMemory; + } + else + { + ASCtx.AddReservation(Args.Offset, (long)Size); + } + } + + AMemoryHelper.Write(Context.Memory, OutputPosition, Args); + + return Result; + } + + private static int FreeSpace(ServiceCtx Context) + { + long InputPosition = Context.Request.GetBufferType0x21().Position; + long OutputPosition = Context.Request.GetBufferType0x22().Position; + + NvGpuASAllocSpace Args = AMemoryHelper.Read(Context.Memory, InputPosition); + + NvGpuASCtx ASCtx = GetASCtx(Context); + + int Result = NvResult.Success; + + lock (ASCtx) + { + ulong Size = (ulong)Args.Pages * + (ulong)Args.PageSize; + + if (ASCtx.RemoveReservation(Args.Offset)) + { + ASCtx.Vmm.Free(Args.Offset, (long)Size); + } + else + { + Context.Device.Log.PrintWarning(LogClass.ServiceNv, + $"Failed to free offset 0x{Args.Offset:x16} size 0x{Size:x16}!"); + + Result = NvResult.InvalidInput; + } + } + + return Result; + } + + private static int UnmapBuffer(ServiceCtx Context) + { + long InputPosition = Context.Request.GetBufferType0x21().Position; + long OutputPosition = Context.Request.GetBufferType0x22().Position; + + NvGpuASUnmapBuffer Args = AMemoryHelper.Read(Context.Memory, InputPosition); + + NvGpuASCtx ASCtx = GetASCtx(Context); + + lock (ASCtx) + { + if (ASCtx.RemoveMap(Args.Offset, out long Size)) + { + if (Size != 0) + { + ASCtx.Vmm.Free(Args.Offset, Size); + } + } + else + { + Context.Device.Log.PrintWarning(LogClass.ServiceNv, $"Invalid buffer offset {Args.Offset:x16}!"); + } + } + + return NvResult.Success; + } + + private static int MapBufferEx(ServiceCtx Context) + { + const string MapErrorMsg = "Failed to map fixed buffer with offset 0x{0:x16} and size 0x{1:x16}!"; + + long InputPosition = Context.Request.GetBufferType0x21().Position; + long OutputPosition = Context.Request.GetBufferType0x22().Position; + + NvGpuASMapBufferEx Args = AMemoryHelper.Read(Context.Memory, InputPosition); + + NvGpuASCtx ASCtx = GetASCtx(Context); + + NvMapHandle Map = NvMapIoctl.GetNvMapWithFb(Context, Args.NvMapHandle); + + if (Map == null) + { + Context.Device.Log.PrintWarning(LogClass.ServiceNv, $"Invalid NvMap handle 0x{Args.NvMapHandle:x8}!"); + + return NvResult.InvalidInput; + } + + long PA; + + if ((Args.Flags & FlagRemapSubRange) != 0) + { + lock (ASCtx) + { + if (ASCtx.TryGetMapPhysicalAddress(Args.Offset, out PA)) + { + long VA = Args.Offset + Args.BufferOffset; + + PA += Args.BufferOffset; + + if (ASCtx.Vmm.Map(PA, VA, Args.MappingSize) < 0) + { + string Msg = string.Format(MapErrorMsg, VA, Args.MappingSize); + + Context.Device.Log.PrintWarning(LogClass.ServiceNv, Msg); + + return NvResult.InvalidInput; + } + + return NvResult.Success; + } + else + { + Context.Device.Log.PrintWarning(LogClass.ServiceNv, $"Address 0x{Args.Offset:x16} not mapped!"); + + return NvResult.InvalidInput; + } + } + } + + PA = Map.Address + Args.BufferOffset; + + long Size = Args.MappingSize; + + if (Size == 0) + { + Size = (uint)Map.Size; + } + + int Result = NvResult.Success; + + lock (ASCtx) + { + //Note: When the fixed offset flag is not set, + //the Offset field holds the alignment size instead. + bool VaAllocated = (Args.Flags & FlagFixedOffset) == 0; + + if (!VaAllocated) + { + if (ASCtx.ValidateFixedBuffer(Args.Offset, Size)) + { + Args.Offset = ASCtx.Vmm.Map(PA, Args.Offset, Size); + } + else + { + string Msg = string.Format(MapErrorMsg, Args.Offset, Size); + + Context.Device.Log.PrintWarning(LogClass.ServiceNv, Msg); + + Result = NvResult.InvalidInput; + } + } + else + { + Args.Offset = ASCtx.Vmm.Map(PA, Size); + } + + if (Args.Offset < 0) + { + Args.Offset = 0; + + Context.Device.Log.PrintWarning(LogClass.ServiceNv, $"Failed to map size 0x{Size:x16}!"); + + Result = NvResult.InvalidInput; + } + else + { + ASCtx.AddMap(Args.Offset, Size, PA, VaAllocated); + } + } + + AMemoryHelper.Write(Context.Memory, OutputPosition, Args); + + return Result; + } + + private static int GetVaRegions(ServiceCtx Context) + { + long InputPosition = Context.Request.GetBufferType0x21().Position; + long OutputPosition = Context.Request.GetBufferType0x22().Position; + + Context.Device.Log.PrintStub(LogClass.ServiceNv, "Stubbed."); + + return NvResult.Success; + } + + private static int InitializeEx(ServiceCtx Context) + { + long InputPosition = Context.Request.GetBufferType0x21().Position; + long OutputPosition = Context.Request.GetBufferType0x22().Position; + + Context.Device.Log.PrintStub(LogClass.ServiceNv, "Stubbed."); + + return NvResult.Success; + } + + private static int Remap(ServiceCtx Context, int Cmd) + { + int Count = ((Cmd >> 16) & 0xff) / 0x14; + + long InputPosition = Context.Request.GetBufferType0x21().Position; + + for (int Index = 0; Index < Count; Index++, InputPosition += 0x14) + { + NvGpuASRemap Args = AMemoryHelper.Read(Context.Memory, InputPosition); + + NvGpuVmm Vmm = GetASCtx(Context).Vmm; + + NvMapHandle Map = NvMapIoctl.GetNvMapWithFb(Context, Args.NvMapHandle); + + if (Map == null) + { + Context.Device.Log.PrintWarning(LogClass.ServiceNv, $"Invalid NvMap handle 0x{Args.NvMapHandle:x8}!"); + + return NvResult.InvalidInput; + } + + long Result = Vmm.Map(Map.Address, (long)(uint)Args.Offset << 16, + (long)(uint)Args.Pages << 16); + + if (Result < 0) + { + Context.Device.Log.PrintWarning(LogClass.ServiceNv, + $"Page 0x{Args.Offset:x16} size 0x{Args.Pages:x16} not allocated!"); + + return NvResult.InvalidInput; + } + } + + return NvResult.Success; + } + + public static NvGpuASCtx GetASCtx(ServiceCtx Context) + { + return ASCtxs.GetOrAdd(Context.Process, (Key) => new NvGpuASCtx(Context)); + } + + public static void UnloadProcess(Process Process) + { + ASCtxs.TryRemove(Process, out _); + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvGpuAS/NvGpuASMapBufferEx.cs b/Ryujinx.HLE/HOS/Services/Nv/NvGpuAS/NvGpuASMapBufferEx.cs new file mode 100644 index 00000000..4bdb4bf7 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvGpuAS/NvGpuASMapBufferEx.cs @@ -0,0 +1,13 @@ +namespace Ryujinx.HLE.HOS.Services.Nv.NvGpuAS +{ + struct NvGpuASMapBufferEx + { + public int Flags; + public int Kind; + public int NvMapHandle; + public int PageSize; + public long BufferOffset; + public long MappingSize; + public long Offset; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvGpuAS/NvGpuASRemap.cs b/Ryujinx.HLE/HOS/Services/Nv/NvGpuAS/NvGpuASRemap.cs new file mode 100644 index 00000000..a24221ba --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvGpuAS/NvGpuASRemap.cs @@ -0,0 +1,12 @@ +namespace Ryujinx.HLE.HOS.Services.Nv.NvGpuAS +{ + struct NvGpuASRemap + { + public short Flags; + public short Kind; + public int NvMapHandle; + public int Padding; + public int Offset; + public int Pages; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvGpuAS/NvGpuASUnmapBuffer.cs b/Ryujinx.HLE/HOS/Services/Nv/NvGpuAS/NvGpuASUnmapBuffer.cs new file mode 100644 index 00000000..beb07fe2 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvGpuAS/NvGpuASUnmapBuffer.cs @@ -0,0 +1,7 @@ +namespace Ryujinx.HLE.HOS.Services.Nv.NvGpuAS +{ + struct NvGpuASUnmapBuffer + { + public long Offset; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvGpuGpu/NvGpuGpuGetActiveSlotMask.cs b/Ryujinx.HLE/HOS/Services/Nv/NvGpuGpu/NvGpuGpuGetActiveSlotMask.cs new file mode 100644 index 00000000..e20d21f9 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvGpuGpu/NvGpuGpuGetActiveSlotMask.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Nv.NvGpuGpu +{ + struct NvGpuGpuGetActiveSlotMask + { + public int Slot; + public int Mask; + } +} diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvGpuGpu/NvGpuGpuGetCharacteristics.cs b/Ryujinx.HLE/HOS/Services/Nv/NvGpuGpu/NvGpuGpuGetCharacteristics.cs new file mode 100644 index 00000000..9a925138 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvGpuGpu/NvGpuGpuGetCharacteristics.cs @@ -0,0 +1,43 @@ +namespace Ryujinx.HLE.HOS.Services.Nv.NvGpuGpu +{ + struct NvGpuGpuGetCharacteristics + { + public long BufferSize; + public long BufferAddress; + public int Arch; + public int Impl; + public int Rev; + public int NumGpc; + public long L2CacheSize; + public long OnBoardVideoMemorySize; + public int NumTpcPerGpc; + public int BusType; + public int BigPageSize; + public int CompressionPageSize; + public int PdeCoverageBitCount; + public int AvailableBigPageSizes; + public int GpcMask; + public int SmArchSmVersion; + public int SmArchSpaVersion; + public int SmArchWarpCount; + public int GpuVaBitCount; + public int Reserved; + public long Flags; + public int TwodClass; + public int ThreedClass; + public int ComputeClass; + public int GpfifoClass; + public int InlineToMemoryClass; + public int DmaCopyClass; + public int MaxFbpsCount; + public int FbpEnMask; + public int MaxLtcPerFbp; + public int MaxLtsPerLtc; + public int MaxTexPerTpc; + public int MaxGpcCount; + public int RopL2EnMask0; + public int RopL2EnMask1; + public long ChipName; + public long GrCompbitStoreBaseHw; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvGpuGpu/NvGpuGpuGetTpcMasks.cs b/Ryujinx.HLE/HOS/Services/Nv/NvGpuGpu/NvGpuGpuGetTpcMasks.cs new file mode 100644 index 00000000..751363c6 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvGpuGpu/NvGpuGpuGetTpcMasks.cs @@ -0,0 +1,11 @@ +namespace Ryujinx.HLE.HOS.Services.Nv.NvGpuGpu +{ + struct NvGpuGpuGetTpcMasks + { + public int MaskBufferSize; + public int Reserved; + public long MaskBufferAddress; + public int TpcMask; + public int Padding; + } +} diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvGpuGpu/NvGpuGpuIoctl.cs b/Ryujinx.HLE/HOS/Services/Nv/NvGpuGpu/NvGpuGpuIoctl.cs new file mode 100644 index 00000000..5ae45c1e --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvGpuGpu/NvGpuGpuIoctl.cs @@ -0,0 +1,187 @@ +using ChocolArm64.Memory; +using Ryujinx.HLE.Logging; +using System; +using System.Diagnostics; + +namespace Ryujinx.HLE.HOS.Services.Nv.NvGpuGpu +{ + class NvGpuGpuIoctl + { + private static Stopwatch PTimer; + + private static double TicksToNs; + + static NvGpuGpuIoctl() + { + PTimer = new Stopwatch(); + + PTimer.Start(); + + TicksToNs = (1.0 / Stopwatch.Frequency) * 1_000_000_000; + } + + public static int ProcessIoctl(ServiceCtx Context, int Cmd) + { + switch (Cmd & 0xffff) + { + case 0x4701: return ZcullGetCtxSize (Context); + case 0x4702: return ZcullGetInfo (Context); + case 0x4703: return ZbcSetTable (Context); + case 0x4705: return GetCharacteristics(Context); + case 0x4706: return GetTpcMasks (Context); + case 0x4714: return GetActiveSlotMask (Context); + case 0x471c: return GetGpuTime (Context); + } + + throw new NotImplementedException(Cmd.ToString("x8")); + } + + private static int ZcullGetCtxSize(ServiceCtx Context) + { + long OutputPosition = Context.Request.GetBufferType0x22().Position; + + NvGpuGpuZcullGetCtxSize Args = new NvGpuGpuZcullGetCtxSize(); + + Args.Size = 1; + + AMemoryHelper.Write(Context.Memory, OutputPosition, Args); + + Context.Device.Log.PrintStub(LogClass.ServiceNv, "Stubbed."); + + return NvResult.Success; + } + + private static int ZcullGetInfo(ServiceCtx Context) + { + long OutputPosition = Context.Request.GetBufferType0x22().Position; + + NvGpuGpuZcullGetInfo Args = new NvGpuGpuZcullGetInfo(); + + Args.WidthAlignPixels = 0x20; + Args.HeightAlignPixels = 0x20; + Args.PixelSquaresByAliquots = 0x400; + Args.AliquotTotal = 0x800; + Args.RegionByteMultiplier = 0x20; + Args.RegionHeaderSize = 0x20; + Args.SubregionHeaderSize = 0xc0; + Args.SubregionWidthAlignPixels = 0x20; + Args.SubregionHeightAlignPixels = 0x40; + Args.SubregionCount = 0x10; + + AMemoryHelper.Write(Context.Memory, OutputPosition, Args); + + Context.Device.Log.PrintStub(LogClass.ServiceNv, "Stubbed."); + + return NvResult.Success; + } + + private static int ZbcSetTable(ServiceCtx Context) + { + long InputPosition = Context.Request.GetBufferType0x21().Position; + long OutputPosition = Context.Request.GetBufferType0x22().Position; + + Context.Device.Log.PrintStub(LogClass.ServiceNv, "Stubbed."); + + return NvResult.Success; + } + + private static int GetCharacteristics(ServiceCtx Context) + { + long InputPosition = Context.Request.GetBufferType0x21().Position; + long OutputPosition = Context.Request.GetBufferType0x22().Position; + + NvGpuGpuGetCharacteristics Args = AMemoryHelper.Read(Context.Memory, InputPosition); + + Args.BufferSize = 0xa0; + + Args.Arch = 0x120; + Args.Impl = 0xb; + Args.Rev = 0xa1; + Args.NumGpc = 0x1; + Args.L2CacheSize = 0x40000; + Args.OnBoardVideoMemorySize = 0x0; + Args.NumTpcPerGpc = 0x2; + Args.BusType = 0x20; + Args.BigPageSize = 0x20000; + Args.CompressionPageSize = 0x20000; + Args.PdeCoverageBitCount = 0x1b; + Args.AvailableBigPageSizes = 0x30000; + Args.GpcMask = 0x1; + Args.SmArchSmVersion = 0x503; + Args.SmArchSpaVersion = 0x503; + Args.SmArchWarpCount = 0x80; + Args.GpuVaBitCount = 0x28; + Args.Reserved = 0x0; + Args.Flags = 0x55; + Args.TwodClass = 0x902d; + Args.ThreedClass = 0xb197; + Args.ComputeClass = 0xb1c0; + Args.GpfifoClass = 0xb06f; + Args.InlineToMemoryClass = 0xa140; + Args.DmaCopyClass = 0xb0b5; + Args.MaxFbpsCount = 0x1; + Args.FbpEnMask = 0x0; + Args.MaxLtcPerFbp = 0x2; + Args.MaxLtsPerLtc = 0x1; + Args.MaxTexPerTpc = 0x0; + Args.MaxGpcCount = 0x1; + Args.RopL2EnMask0 = 0x21d70; + Args.RopL2EnMask1 = 0x0; + Args.ChipName = 0x6230326d67; + Args.GrCompbitStoreBaseHw = 0x0; + + AMemoryHelper.Write(Context.Memory, OutputPosition, Args); + + return NvResult.Success; + } + + private static int GetTpcMasks(ServiceCtx Context) + { + long InputPosition = Context.Request.GetBufferType0x21().Position; + long OutputPosition = Context.Request.GetBufferType0x22().Position; + + NvGpuGpuGetTpcMasks Args = AMemoryHelper.Read(Context.Memory, InputPosition); + + if (Args.MaskBufferSize != 0) + { + Args.TpcMask = 3; + } + + AMemoryHelper.Write(Context.Memory, OutputPosition, Args); + + return NvResult.Success; + } + + private static int GetActiveSlotMask(ServiceCtx Context) + { + long OutputPosition = Context.Request.GetBufferType0x22().Position; + + NvGpuGpuGetActiveSlotMask Args = new NvGpuGpuGetActiveSlotMask(); + + Args.Slot = 0x07; + Args.Mask = 0x01; + + AMemoryHelper.Write(Context.Memory, OutputPosition, Args); + + Context.Device.Log.PrintStub(LogClass.ServiceNv, "Stubbed."); + + return NvResult.Success; + } + + private static int GetGpuTime(ServiceCtx Context) + { + long OutputPosition = Context.Request.GetBufferType0x22().Position; + + Context.Memory.WriteInt64(OutputPosition, GetPTimerNanoSeconds()); + + return NvResult.Success; + } + + private static long GetPTimerNanoSeconds() + { + double Ticks = PTimer.ElapsedTicks; + + return (long)(Ticks * TicksToNs) & 0xff_ffff_ffff_ffff; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvGpuGpu/NvGpuGpuZcullGetCtxSize.cs b/Ryujinx.HLE/HOS/Services/Nv/NvGpuGpu/NvGpuGpuZcullGetCtxSize.cs new file mode 100644 index 00000000..3ac9f92b --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvGpuGpu/NvGpuGpuZcullGetCtxSize.cs @@ -0,0 +1,7 @@ +namespace Ryujinx.HLE.HOS.Services.Nv.NvGpuGpu +{ + struct NvGpuGpuZcullGetCtxSize + { + public int Size; + } +} diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvGpuGpu/NvGpuGpuZcullGetInfo.cs b/Ryujinx.HLE/HOS/Services/Nv/NvGpuGpu/NvGpuGpuZcullGetInfo.cs new file mode 100644 index 00000000..4a7cafd5 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvGpuGpu/NvGpuGpuZcullGetInfo.cs @@ -0,0 +1,16 @@ +namespace Ryujinx.HLE.HOS.Services.Nv.NvGpuGpu +{ + struct NvGpuGpuZcullGetInfo + { + public int WidthAlignPixels; + public int HeightAlignPixels; + public int PixelSquaresByAliquots; + public int AliquotTotal; + public int RegionByteMultiplier; + public int RegionHeaderSize; + public int SubregionHeaderSize; + public int SubregionWidthAlignPixels; + public int SubregionHeightAlignPixels; + public int SubregionCount; + } +} diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvHelper.cs b/Ryujinx.HLE/HOS/Services/Nv/NvHelper.cs new file mode 100644 index 00000000..d9a1c452 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvHelper.cs @@ -0,0 +1,10 @@ +namespace Ryujinx.HLE.HOS.Services.Nv +{ + static class NvHelper + { + public static void Crash() + { + + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvHostChannel/NvChannel.cs b/Ryujinx.HLE/HOS/Services/Nv/NvHostChannel/NvChannel.cs new file mode 100644 index 00000000..54e709f9 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvHostChannel/NvChannel.cs @@ -0,0 +1,7 @@ +namespace Ryujinx.HLE.HOS.Services.Nv.NvHostChannel +{ + class NvChannel + { + public int Timeout; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvHostChannel/NvChannelName.cs b/Ryujinx.HLE/HOS/Services/Nv/NvHostChannel/NvChannelName.cs new file mode 100644 index 00000000..a2b5ea4c --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvHostChannel/NvChannelName.cs @@ -0,0 +1,7 @@ +namespace Ryujinx.HLE.HOS.Services.Nv.NvHostChannel +{ + enum NvChannelName + { + Gpu + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvHostChannel/NvHostChannelIoctl.cs b/Ryujinx.HLE/HOS/Services/Nv/NvHostChannel/NvHostChannelIoctl.cs new file mode 100644 index 00000000..842447f3 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvHostChannel/NvHostChannelIoctl.cs @@ -0,0 +1,210 @@ +using ChocolArm64.Memory; +using Ryujinx.HLE.Gpu.Memory; +using Ryujinx.HLE.HOS.Services.Nv.NvGpuAS; +using Ryujinx.HLE.Logging; +using System; +using System.Collections.Concurrent; + +namespace Ryujinx.HLE.HOS.Services.Nv.NvHostChannel +{ + class NvHostChannelIoctl + { + private class ChannelsPerProcess + { + public ConcurrentDictionary Channels { get; private set; } + + public ChannelsPerProcess() + { + Channels = new ConcurrentDictionary(); + + Channels.TryAdd(NvChannelName.Gpu, new NvChannel()); + } + } + + private static ConcurrentDictionary Channels; + + static NvHostChannelIoctl() + { + Channels = new ConcurrentDictionary(); + } + + public static int ProcessIoctlGpu(ServiceCtx Context, int Cmd) + { + return ProcessIoctl(Context, NvChannelName.Gpu, Cmd); + } + + public static int ProcessIoctl(ServiceCtx Context, NvChannelName Channel, int Cmd) + { + switch (Cmd & 0xffff) + { + case 0x4714: return SetUserData (Context); + case 0x4801: return SetNvMap (Context); + case 0x4803: return SetTimeout (Context, Channel); + case 0x4808: return SubmitGpfifo (Context); + case 0x4809: return AllocObjCtx (Context); + case 0x480b: return ZcullBind (Context); + case 0x480c: return SetErrorNotifier (Context); + case 0x480d: return SetPriority (Context); + case 0x481a: return AllocGpfifoEx2 (Context); + case 0x481b: return KickoffPbWithAttr(Context); + } + + throw new NotImplementedException(Cmd.ToString("x8")); + } + + private static int SetUserData(ServiceCtx Context) + { + long InputPosition = Context.Request.GetBufferType0x21().Position; + long OutputPosition = Context.Request.GetBufferType0x22().Position; + + Context.Device.Log.PrintStub(LogClass.ServiceNv, "Stubbed."); + + return NvResult.Success; + } + + private static int SetNvMap(ServiceCtx Context) + { + long InputPosition = Context.Request.GetBufferType0x21().Position; + long OutputPosition = Context.Request.GetBufferType0x22().Position; + + Context.Device.Log.PrintStub(LogClass.ServiceNv, "Stubbed."); + + return NvResult.Success; + } + + private static int SetTimeout(ServiceCtx Context, NvChannelName Channel) + { + long InputPosition = Context.Request.GetBufferType0x21().Position; + + GetChannel(Context, Channel).Timeout = Context.Memory.ReadInt32(InputPosition); + + return NvResult.Success; + } + + private static int SubmitGpfifo(ServiceCtx Context) + { + long InputPosition = Context.Request.GetBufferType0x21().Position; + long OutputPosition = Context.Request.GetBufferType0x22().Position; + + NvHostChannelSubmitGpfifo Args = AMemoryHelper.Read(Context.Memory, InputPosition); + + NvGpuVmm Vmm = NvGpuASIoctl.GetASCtx(Context).Vmm;; + + for (int Index = 0; Index < Args.NumEntries; Index++) + { + long Gpfifo = Context.Memory.ReadInt64(InputPosition + 0x18 + Index * 8); + + PushGpfifo(Context, Vmm, Gpfifo); + } + + Args.SyncptId = 0; + Args.SyncptValue = 0; + + AMemoryHelper.Write(Context.Memory, OutputPosition, Args); + + return NvResult.Success; + } + + private static int AllocObjCtx(ServiceCtx Context) + { + long InputPosition = Context.Request.GetBufferType0x21().Position; + long OutputPosition = Context.Request.GetBufferType0x22().Position; + + Context.Device.Log.PrintStub(LogClass.ServiceNv, "Stubbed."); + + return NvResult.Success; + } + + private static int ZcullBind(ServiceCtx Context) + { + long InputPosition = Context.Request.GetBufferType0x21().Position; + long OutputPosition = Context.Request.GetBufferType0x22().Position; + + Context.Device.Log.PrintStub(LogClass.ServiceNv, "Stubbed."); + + return NvResult.Success; + } + + private static int SetErrorNotifier(ServiceCtx Context) + { + long InputPosition = Context.Request.GetBufferType0x21().Position; + long OutputPosition = Context.Request.GetBufferType0x22().Position; + + Context.Device.Log.PrintStub(LogClass.ServiceNv, "Stubbed."); + + return NvResult.Success; + } + + private static int SetPriority(ServiceCtx Context) + { + long InputPosition = Context.Request.GetBufferType0x21().Position; + long OutputPosition = Context.Request.GetBufferType0x22().Position; + + Context.Device.Log.PrintStub(LogClass.ServiceNv, "Stubbed."); + + return NvResult.Success; + } + + private static int AllocGpfifoEx2(ServiceCtx Context) + { + long InputPosition = Context.Request.GetBufferType0x21().Position; + long OutputPosition = Context.Request.GetBufferType0x22().Position; + + Context.Device.Log.PrintStub(LogClass.ServiceNv, "Stubbed."); + + return NvResult.Success; + } + + private static int KickoffPbWithAttr(ServiceCtx Context) + { + long InputPosition = Context.Request.GetBufferType0x21().Position; + long OutputPosition = Context.Request.GetBufferType0x22().Position; + + NvHostChannelSubmitGpfifo Args = AMemoryHelper.Read(Context.Memory, InputPosition); + + NvGpuVmm Vmm = NvGpuASIoctl.GetASCtx(Context).Vmm;; + + for (int Index = 0; Index < Args.NumEntries; Index++) + { + long Gpfifo = Context.Memory.ReadInt64(Args.Address + Index * 8); + + PushGpfifo(Context, Vmm, Gpfifo); + } + + Args.SyncptId = 0; + Args.SyncptValue = 0; + + AMemoryHelper.Write(Context.Memory, OutputPosition, Args); + + return NvResult.Success; + } + + private static void PushGpfifo(ServiceCtx Context, NvGpuVmm Vmm, long Gpfifo) + { + long VA = Gpfifo & 0xff_ffff_ffff; + + int Size = (int)(Gpfifo >> 40) & 0x7ffffc; + + byte[] Data = Vmm.ReadBytes(VA, Size); + + NvGpuPBEntry[] PushBuffer = NvGpuPushBuffer.Decode(Data); + + Context.Device.Gpu.Fifo.PushBuffer(Vmm, PushBuffer); + } + + public static NvChannel GetChannel(ServiceCtx Context, NvChannelName Channel) + { + ChannelsPerProcess Cpp = Channels.GetOrAdd(Context.Process, (Key) => + { + return new ChannelsPerProcess(); + }); + + return Cpp.Channels[Channel]; + } + + public static void UnloadProcess(Process Process) + { + Channels.TryRemove(Process, out _); + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvHostChannel/NvHostChannelSubmitGpfifo.cs b/Ryujinx.HLE/HOS/Services/Nv/NvHostChannel/NvHostChannelSubmitGpfifo.cs new file mode 100644 index 00000000..edebcfeb --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvHostChannel/NvHostChannelSubmitGpfifo.cs @@ -0,0 +1,11 @@ +namespace Ryujinx.HLE.HOS.Services.Nv.NvHostChannel +{ + struct NvHostChannelSubmitGpfifo + { + public long Address; + public int NumEntries; + public int Flags; + public int SyncptId; + public int SyncptValue; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvHostCtrl/NvHostCtrlIoctl.cs b/Ryujinx.HLE/HOS/Services/Nv/NvHostCtrl/NvHostCtrlIoctl.cs new file mode 100644 index 00000000..2bfe8882 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvHostCtrl/NvHostCtrlIoctl.cs @@ -0,0 +1,398 @@ +using ChocolArm64.Memory; +using Ryujinx.HLE.Logging; +using System; +using System.Collections.Concurrent; +using System.Text; +using System.Threading; + +namespace Ryujinx.HLE.HOS.Services.Nv.NvHostCtrl +{ + class NvHostCtrlIoctl + { + private static ConcurrentDictionary UserCtxs; + + private static bool IsProductionMode = true; + + static NvHostCtrlIoctl() + { + UserCtxs = new ConcurrentDictionary(); + + if (Set.NxSettings.Settings.TryGetValue("nv!rmos_set_production_mode", out object ProductionModeSetting)) + { + IsProductionMode = ((string)ProductionModeSetting) != "0"; // Default value is "" + } + } + + public static int ProcessIoctl(ServiceCtx Context, int Cmd) + { + switch (Cmd & 0xffff) + { + case 0x0014: return SyncptRead (Context); + case 0x0015: return SyncptIncr (Context); + case 0x0016: return SyncptWait (Context); + case 0x0019: return SyncptWaitEx (Context); + case 0x001a: return SyncptReadMax (Context); + case 0x001b: return GetConfig (Context); + case 0x001d: return EventWait (Context); + case 0x001e: return EventWaitAsync(Context); + case 0x001f: return EventRegister (Context); + } + + throw new NotImplementedException(Cmd.ToString("x8")); + } + + private static int SyncptRead(ServiceCtx Context) + { + return SyncptReadMinOrMax(Context, Max: false); + } + + private static int SyncptIncr(ServiceCtx Context) + { + long InputPosition = Context.Request.GetBufferType0x21().Position; + + int Id = Context.Memory.ReadInt32(InputPosition); + + if ((uint)Id >= NvHostSyncpt.SyncptsCount) + { + return NvResult.InvalidInput; + } + + GetUserCtx(Context).Syncpt.Increment(Id); + + return NvResult.Success; + } + + private static int SyncptWait(ServiceCtx Context) + { + return SyncptWait(Context, Extended: false); + } + + private static int SyncptWaitEx(ServiceCtx Context) + { + return SyncptWait(Context, Extended: true); + } + + private static int SyncptReadMax(ServiceCtx Context) + { + return SyncptReadMinOrMax(Context, Max: true); + } + + private static int GetConfig(ServiceCtx Context) + { + if (!IsProductionMode) + { + long InputPosition = Context.Request.GetBufferType0x21().Position; + long OutputPosition = Context.Request.GetBufferType0x22().Position; + + string Domain = AMemoryHelper.ReadAsciiString(Context.Memory, InputPosition + 0, 0x41); + string Name = AMemoryHelper.ReadAsciiString(Context.Memory, InputPosition + 0x41, 0x41); + + if (Set.NxSettings.Settings.TryGetValue($"{Domain}!{Name}", out object NvSetting)) + { + byte[] SettingBuffer = new byte[0x101]; + + if (NvSetting is string StringValue) + { + if (StringValue.Length > 0x100) + { + Context.Device.Log.PrintError(Logging.LogClass.ServiceNv, $"{Domain}!{Name} String value size is too big!"); + } + else + { + SettingBuffer = Encoding.ASCII.GetBytes(StringValue + "\0"); + } + } + + if (NvSetting is int IntValue) + { + SettingBuffer = BitConverter.GetBytes(IntValue); + } + else if (NvSetting is bool BoolValue) + { + SettingBuffer[0] = BoolValue ? (byte)1 : (byte)0; + } + else + { + throw new NotImplementedException(NvSetting.GetType().Name); + } + + Context.Memory.WriteBytes(OutputPosition + 0x82, SettingBuffer); + + Context.Device.Log.PrintDebug(Logging.LogClass.ServiceNv, $"Got setting {Domain}!{Name}"); + } + + return NvResult.Success; + } + + return NvResult.NotAvailableInProduction; + } + + private static int EventWait(ServiceCtx Context) + { + return EventWait(Context, Async: false); + } + + private static int EventWaitAsync(ServiceCtx Context) + { + return EventWait(Context, Async: true); + } + + private static int EventRegister(ServiceCtx Context) + { + long InputPosition = Context.Request.GetBufferType0x21().Position; + long OutputPosition = Context.Request.GetBufferType0x22().Position; + + int EventId = Context.Memory.ReadInt32(InputPosition); + + Context.Device.Log.PrintStub(LogClass.ServiceNv, "Stubbed."); + + return NvResult.Success; + } + + private static int SyncptReadMinOrMax(ServiceCtx Context, bool Max) + { + long InputPosition = Context.Request.GetBufferType0x21().Position; + long OutputPosition = Context.Request.GetBufferType0x22().Position; + + NvHostCtrlSyncptRead Args = AMemoryHelper.Read(Context.Memory, InputPosition); + + if ((uint)Args.Id >= NvHostSyncpt.SyncptsCount) + { + return NvResult.InvalidInput; + } + + if (Max) + { + Args.Value = GetUserCtx(Context).Syncpt.GetMax(Args.Id); + } + else + { + Args.Value = GetUserCtx(Context).Syncpt.GetMin(Args.Id); + } + + AMemoryHelper.Write(Context.Memory, OutputPosition, Args); + + return NvResult.Success; + } + + private static int SyncptWait(ServiceCtx Context, bool Extended) + { + long InputPosition = Context.Request.GetBufferType0x21().Position; + long OutputPosition = Context.Request.GetBufferType0x22().Position; + + NvHostCtrlSyncptWait Args = AMemoryHelper.Read(Context.Memory, InputPosition); + + NvHostSyncpt Syncpt = GetUserCtx(Context).Syncpt; + + if ((uint)Args.Id >= NvHostSyncpt.SyncptsCount) + { + return NvResult.InvalidInput; + } + + int Result; + + if (Syncpt.MinCompare(Args.Id, Args.Thresh)) + { + Result = NvResult.Success; + } + else if (Args.Timeout == 0) + { + Result = NvResult.TryAgain; + } + else + { + Context.Device.Log.PrintDebug(LogClass.ServiceNv, "Waiting syncpt with timeout of " + Args.Timeout + "ms..."); + + using (ManualResetEvent WaitEvent = new ManualResetEvent(false)) + { + Syncpt.AddWaiter(Args.Thresh, WaitEvent); + + //Note: Negative (> INT_MAX) timeouts aren't valid on .NET, + //in this case we just use the maximum timeout possible. + int Timeout = Args.Timeout; + + if (Timeout < -1) + { + Timeout = int.MaxValue; + } + + if (Timeout == -1) + { + WaitEvent.WaitOne(); + + Result = NvResult.Success; + } + else if (WaitEvent.WaitOne(Timeout)) + { + Result = NvResult.Success; + } + else + { + Result = NvResult.TimedOut; + } + } + + Context.Device.Log.PrintDebug(LogClass.ServiceNv, "Resuming..."); + } + + if (Extended) + { + Context.Memory.WriteInt32(OutputPosition + 0xc, Syncpt.GetMin(Args.Id)); + } + + return Result; + } + + private static int EventWait(ServiceCtx Context, bool Async) + { + long InputPosition = Context.Request.GetBufferType0x21().Position; + long OutputPosition = Context.Request.GetBufferType0x22().Position; + + NvHostCtrlSyncptWaitEx Args = AMemoryHelper.Read(Context.Memory, InputPosition); + + if ((uint)Args.Id >= NvHostSyncpt.SyncptsCount) + { + return NvResult.InvalidInput; + } + + void WriteArgs() + { + AMemoryHelper.Write(Context.Memory, OutputPosition, Args); + } + + NvHostSyncpt Syncpt = GetUserCtx(Context).Syncpt; + + if (Syncpt.MinCompare(Args.Id, Args.Thresh)) + { + Args.Value = Syncpt.GetMin(Args.Id); + + WriteArgs(); + + return NvResult.Success; + } + + if (!Async) + { + Args.Value = 0; + } + + if (Args.Timeout == 0) + { + WriteArgs(); + + return NvResult.TryAgain; + } + + NvHostEvent Event; + + int Result, EventIndex; + + if (Async) + { + EventIndex = Args.Value; + + if ((uint)EventIndex >= NvHostCtrlUserCtx.EventsCount) + { + return NvResult.InvalidInput; + } + + Event = GetUserCtx(Context).Events[EventIndex]; + } + else + { + Event = GetFreeEvent(Context, Syncpt, Args.Id, out EventIndex); + } + + if (Event != null && + (Event.State == NvHostEventState.Registered || + Event.State == NvHostEventState.Free)) + { + Event.Id = Args.Id; + Event.Thresh = Args.Thresh; + + Event.State = NvHostEventState.Waiting; + + if (!Async) + { + Args.Value = ((Args.Id & 0xfff) << 16) | 0x10000000; + } + else + { + Args.Value = Args.Id << 4; + } + + Args.Value |= EventIndex; + + Result = NvResult.TryAgain; + } + else + { + Result = NvResult.InvalidInput; + } + + WriteArgs(); + + return Result; + } + + private static NvHostEvent GetFreeEvent( + ServiceCtx Context, + NvHostSyncpt Syncpt, + int Id, + out int EventIndex) + { + NvHostEvent[] Events = GetUserCtx(Context).Events; + + EventIndex = NvHostCtrlUserCtx.EventsCount; + + int NullIndex = NvHostCtrlUserCtx.EventsCount; + + for (int Index = 0; Index < NvHostCtrlUserCtx.EventsCount; Index++) + { + NvHostEvent Event = Events[Index]; + + if (Event != null) + { + if (Event.State == NvHostEventState.Registered || + Event.State == NvHostEventState.Free) + { + EventIndex = Index; + + if (Event.Id == Id) + { + return Event; + } + } + } + else if (NullIndex == NvHostCtrlUserCtx.EventsCount) + { + NullIndex = Index; + } + } + + if (NullIndex < NvHostCtrlUserCtx.EventsCount) + { + EventIndex = NullIndex; + + return Events[NullIndex] = new NvHostEvent(); + } + + if (EventIndex < NvHostCtrlUserCtx.EventsCount) + { + return Events[EventIndex]; + } + + return null; + } + + public static NvHostCtrlUserCtx GetUserCtx(ServiceCtx Context) + { + return UserCtxs.GetOrAdd(Context.Process, (Key) => new NvHostCtrlUserCtx()); + } + + public static void UnloadProcess(Process Process) + { + UserCtxs.TryRemove(Process, out _); + } + } +} diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvHostCtrl/NvHostCtrlSyncPtRead.cs b/Ryujinx.HLE/HOS/Services/Nv/NvHostCtrl/NvHostCtrlSyncPtRead.cs new file mode 100644 index 00000000..275b6132 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvHostCtrl/NvHostCtrlSyncPtRead.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Nv.NvHostCtrl +{ + struct NvHostCtrlSyncptRead + { + public int Id; + public int Value; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvHostCtrl/NvHostCtrlSyncPtWait.cs b/Ryujinx.HLE/HOS/Services/Nv/NvHostCtrl/NvHostCtrlSyncPtWait.cs new file mode 100644 index 00000000..96e2f968 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvHostCtrl/NvHostCtrlSyncPtWait.cs @@ -0,0 +1,9 @@ +namespace Ryujinx.HLE.HOS.Services.Nv.NvHostCtrl +{ + struct NvHostCtrlSyncptWait + { + public int Id; + public int Thresh; + public int Timeout; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvHostCtrl/NvHostCtrlSyncPtWaitEx.cs b/Ryujinx.HLE/HOS/Services/Nv/NvHostCtrl/NvHostCtrlSyncPtWaitEx.cs new file mode 100644 index 00000000..6aaa4718 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvHostCtrl/NvHostCtrlSyncPtWaitEx.cs @@ -0,0 +1,10 @@ +namespace Ryujinx.HLE.HOS.Services.Nv.NvHostCtrl +{ + struct NvHostCtrlSyncptWaitEx + { + public int Id; + public int Thresh; + public int Timeout; + public int Value; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvHostCtrl/NvHostCtrlUserCtx.cs b/Ryujinx.HLE/HOS/Services/Nv/NvHostCtrl/NvHostCtrlUserCtx.cs new file mode 100644 index 00000000..fcb80836 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvHostCtrl/NvHostCtrlUserCtx.cs @@ -0,0 +1,19 @@ +namespace Ryujinx.HLE.HOS.Services.Nv.NvHostCtrl +{ + class NvHostCtrlUserCtx + { + public const int LocksCount = 16; + public const int EventsCount = 64; + + public NvHostSyncpt Syncpt { get; private set; } + + public NvHostEvent[] Events { get; private set; } + + public NvHostCtrlUserCtx() + { + Syncpt = new NvHostSyncpt(); + + Events = new NvHostEvent[EventsCount]; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvHostCtrl/NvHostEvent.cs b/Ryujinx.HLE/HOS/Services/Nv/NvHostCtrl/NvHostEvent.cs new file mode 100644 index 00000000..71e5f1e6 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvHostCtrl/NvHostEvent.cs @@ -0,0 +1,10 @@ +namespace Ryujinx.HLE.HOS.Services.Nv.NvHostCtrl +{ + class NvHostEvent + { + public int Id; + public int Thresh; + + public NvHostEventState State; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvHostCtrl/NvHostEventState.cs b/Ryujinx.HLE/HOS/Services/Nv/NvHostCtrl/NvHostEventState.cs new file mode 100644 index 00000000..61870c7f --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvHostCtrl/NvHostEventState.cs @@ -0,0 +1,10 @@ +namespace Ryujinx.HLE.HOS.Services.Nv.NvHostCtrl +{ + enum NvHostEventState + { + Registered = 0, + Waiting = 1, + Busy = 2, + Free = 5 + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvHostCtrl/NvHostSyncPt.cs b/Ryujinx.HLE/HOS/Services/Nv/NvHostCtrl/NvHostSyncPt.cs new file mode 100644 index 00000000..9ffa93f2 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvHostCtrl/NvHostSyncPt.cs @@ -0,0 +1,107 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Threading; + +namespace Ryujinx.HLE.HOS.Services.Nv.NvHostCtrl +{ + class NvHostSyncpt + { + public const int SyncptsCount = 192; + + private int[] CounterMin; + private int[] CounterMax; + + private long EventMask; + + private ConcurrentDictionary Waiters; + + public NvHostSyncpt() + { + CounterMin = new int[SyncptsCount]; + CounterMax = new int[SyncptsCount]; + + Waiters = new ConcurrentDictionary(); + } + + public int GetMin(int Id) + { + return CounterMin[Id]; + } + + public int GetMax(int Id) + { + return CounterMax[Id]; + } + + public int Increment(int Id) + { + if (((EventMask >> Id) & 1) != 0) + { + Interlocked.Increment(ref CounterMax[Id]); + } + + return IncrementMin(Id); + } + + public int IncrementMin(int Id) + { + int Value = Interlocked.Increment(ref CounterMin[Id]); + + WakeUpWaiters(Id, Value); + + return Value; + } + + public int IncrementMax(int Id) + { + return Interlocked.Increment(ref CounterMax[Id]); + } + + public void AddWaiter(int Threshold, EventWaitHandle WaitEvent) + { + if (!Waiters.TryAdd(WaitEvent, Threshold)) + { + throw new InvalidOperationException(); + } + } + + public bool RemoveWaiter(EventWaitHandle WaitEvent) + { + return Waiters.TryRemove(WaitEvent, out _); + } + + private void WakeUpWaiters(int Id, int NewValue) + { + foreach (KeyValuePair KV in Waiters) + { + if (MinCompare(Id, NewValue, CounterMax[Id], KV.Value)) + { + KV.Key.Set(); + + Waiters.TryRemove(KV.Key, out _); + } + } + } + + public bool MinCompare(int Id, int Threshold) + { + return MinCompare(Id, CounterMin[Id], CounterMax[Id], Threshold); + } + + private bool MinCompare(int Id, int Min, int Max, int Threshold) + { + int MinDiff = Min - Threshold; + int MaxDiff = Max - Threshold; + + if (((EventMask >> Id) & 1) != 0) + { + return MinDiff >= 0; + } + else + { + return (uint)MaxDiff >= (uint)MinDiff; + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapAlloc.cs b/Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapAlloc.cs new file mode 100644 index 00000000..bc61baad --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapAlloc.cs @@ -0,0 +1,12 @@ +namespace Ryujinx.HLE.HOS.Services.Nv.NvMap +{ + struct NvMapAlloc + { + public int Handle; + public int HeapMask; + public int Flags; + public int Align; + public long Kind; + public long Address; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapCreate.cs b/Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapCreate.cs new file mode 100644 index 00000000..dd4bff98 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapCreate.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Nv.NvMap +{ + struct NvMapCreate + { + public int Size; + public int Handle; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapFree.cs b/Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapFree.cs new file mode 100644 index 00000000..d946987e --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapFree.cs @@ -0,0 +1,11 @@ +namespace Ryujinx.HLE.HOS.Services.Nv.NvMap +{ + struct NvMapFree + { + public int Handle; + public int Padding; + public long Address; + public int Size; + public int Flags; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapFromId.cs b/Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapFromId.cs new file mode 100644 index 00000000..e49257ea --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapFromId.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Nv.NvMap +{ + struct NvMapFromId + { + public int Id; + public int Handle; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapGetId.cs b/Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapGetId.cs new file mode 100644 index 00000000..1f4f3290 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapGetId.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Nv.NvMap +{ + struct NvMapGetId + { + public int Id; + public int Handle; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapHandle.cs b/Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapHandle.cs new file mode 100644 index 00000000..3f8a1517 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapHandle.cs @@ -0,0 +1,37 @@ +using System.Threading; + +namespace Ryujinx.HLE.HOS.Services.Nv.NvMap +{ + class NvMapHandle + { + public int Handle; + public int Id; + public int Size; + public int Align; + public int Kind; + public long Address; + public bool Allocated; + + private long Dupes; + + public NvMapHandle() + { + Dupes = 1; + } + + public NvMapHandle(int Size) : this() + { + this.Size = Size; + } + + public void IncrementRefCount() + { + Interlocked.Increment(ref Dupes); + } + + public long DecrementRefCount() + { + return Interlocked.Decrement(ref Dupes); + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapHandleParam.cs b/Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapHandleParam.cs new file mode 100644 index 00000000..b360343c --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapHandleParam.cs @@ -0,0 +1,12 @@ +namespace Ryujinx.HLE.HOS.Services.Nv.NvMap +{ + enum NvMapHandleParam + { + Size = 1, + Align = 2, + Base = 3, + Heap = 4, + Kind = 5, + Compr = 6 + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapIoctl.cs b/Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapIoctl.cs new file mode 100644 index 00000000..782f7b80 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapIoctl.cs @@ -0,0 +1,302 @@ +using ChocolArm64.Memory; +using Ryujinx.HLE.Gpu.Memory; +using Ryujinx.HLE.Logging; +using Ryujinx.HLE.Utilities; +using System.Collections.Concurrent; + +namespace Ryujinx.HLE.HOS.Services.Nv.NvMap +{ + class NvMapIoctl + { + private const int FlagNotFreedYet = 1; + + private static ConcurrentDictionary Maps; + + static NvMapIoctl() + { + Maps = new ConcurrentDictionary(); + } + + public static int ProcessIoctl(ServiceCtx Context, int Cmd) + { + switch (Cmd & 0xffff) + { + case 0x0101: return Create(Context); + case 0x0103: return FromId(Context); + case 0x0104: return Alloc (Context); + case 0x0105: return Free (Context); + case 0x0109: return Param (Context); + case 0x010e: return GetId (Context); + } + + Context.Device.Log.PrintWarning(LogClass.ServiceNv, $"Unsupported Ioctl command 0x{Cmd:x8}!"); + + return NvResult.NotSupported; + } + + private static int Create(ServiceCtx Context) + { + long InputPosition = Context.Request.GetBufferType0x21().Position; + long OutputPosition = Context.Request.GetBufferType0x22().Position; + + NvMapCreate Args = AMemoryHelper.Read(Context.Memory, InputPosition); + + if (Args.Size == 0) + { + Context.Device.Log.PrintWarning(LogClass.ServiceNv, $"Invalid size 0x{Args.Size:x8}!"); + + return NvResult.InvalidInput; + } + + int Size = IntUtils.AlignUp(Args.Size, NvGpuVmm.PageSize); + + Args.Handle = AddNvMap(Context, new NvMapHandle(Size)); + + Context.Device.Log.PrintInfo(LogClass.ServiceNv, $"Created map {Args.Handle} with size 0x{Size:x8}!"); + + AMemoryHelper.Write(Context.Memory, OutputPosition, Args); + + return NvResult.Success; + } + + private static int FromId(ServiceCtx Context) + { + long InputPosition = Context.Request.GetBufferType0x21().Position; + long OutputPosition = Context.Request.GetBufferType0x22().Position; + + NvMapFromId Args = AMemoryHelper.Read(Context.Memory, InputPosition); + + NvMapHandle Map = GetNvMap(Context, Args.Id); + + if (Map == null) + { + Context.Device.Log.PrintWarning(LogClass.ServiceNv, $"Invalid handle 0x{Args.Handle:x8}!"); + + return NvResult.InvalidInput; + } + + Map.IncrementRefCount(); + + Args.Handle = Args.Id; + + AMemoryHelper.Write(Context.Memory, OutputPosition, Args); + + return NvResult.Success; + } + + private static int Alloc(ServiceCtx Context) + { + long InputPosition = Context.Request.GetBufferType0x21().Position; + long OutputPosition = Context.Request.GetBufferType0x22().Position; + + NvMapAlloc Args = AMemoryHelper.Read(Context.Memory, InputPosition); + + NvMapHandle Map = GetNvMap(Context, Args.Handle); + + if (Map == null) + { + Context.Device.Log.PrintWarning(LogClass.ServiceNv, $"Invalid handle 0x{Args.Handle:x8}!"); + + return NvResult.InvalidInput; + } + + if ((Args.Align & (Args.Align - 1)) != 0) + { + Context.Device.Log.PrintWarning(LogClass.ServiceNv, $"Invalid alignment 0x{Args.Align:x8}!"); + + return NvResult.InvalidInput; + } + + if ((uint)Args.Align < NvGpuVmm.PageSize) + { + Args.Align = NvGpuVmm.PageSize; + } + + int Result = NvResult.Success; + + if (!Map.Allocated) + { + Map.Allocated = true; + + Map.Align = Args.Align; + Map.Kind = (byte)Args.Kind; + + int Size = IntUtils.AlignUp(Map.Size, NvGpuVmm.PageSize); + + long Address = Args.Address; + + if (Address == 0) + { + //When the address is zero, we need to allocate + //our own backing memory for the NvMap. + //TODO: Is this allocation inside the transfer memory? + if (!Context.Device.Memory.Allocator.TryAllocate((uint)Size, out Address)) + { + Result = NvResult.OutOfMemory; + } + } + + if (Result == NvResult.Success) + { + Map.Size = Size; + Map.Address = Address; + } + } + + AMemoryHelper.Write(Context.Memory, OutputPosition, Args); + + return Result; + } + + private static int Free(ServiceCtx Context) + { + long InputPosition = Context.Request.GetBufferType0x21().Position; + long OutputPosition = Context.Request.GetBufferType0x22().Position; + + NvMapFree Args = AMemoryHelper.Read(Context.Memory, InputPosition); + + NvMapHandle Map = GetNvMap(Context, Args.Handle); + + if (Map == null) + { + Context.Device.Log.PrintWarning(LogClass.ServiceNv, $"Invalid handle 0x{Args.Handle:x8}!"); + + return NvResult.InvalidInput; + } + + if (Map.DecrementRefCount() <= 0) + { + DeleteNvMap(Context, Args.Handle); + + Context.Device.Log.PrintInfo(LogClass.ServiceNv, $"Deleted map {Args.Handle}!"); + + Args.Address = Map.Address; + Args.Flags = 0; + } + else + { + Args.Address = 0; + Args.Flags = FlagNotFreedYet; + } + + Args.Size = Map.Size; + + AMemoryHelper.Write(Context.Memory, OutputPosition, Args); + + return NvResult.Success; + } + + private static int Param(ServiceCtx Context) + { + long InputPosition = Context.Request.GetBufferType0x21().Position; + long OutputPosition = Context.Request.GetBufferType0x22().Position; + + NvMapParam Args = AMemoryHelper.Read(Context.Memory, InputPosition); + + NvMapHandle Map = GetNvMap(Context, Args.Handle); + + if (Map == null) + { + Context.Device.Log.PrintWarning(LogClass.ServiceNv, $"Invalid handle 0x{Args.Handle:x8}!"); + + return NvResult.InvalidInput; + } + + switch ((NvMapHandleParam)Args.Param) + { + case NvMapHandleParam.Size: Args.Result = Map.Size; break; + case NvMapHandleParam.Align: Args.Result = Map.Align; break; + case NvMapHandleParam.Heap: Args.Result = 0x40000000; break; + case NvMapHandleParam.Kind: Args.Result = Map.Kind; break; + case NvMapHandleParam.Compr: Args.Result = 0; break; + + //Note: Base is not supported and returns an error. + //Any other value also returns an error. + default: return NvResult.InvalidInput; + } + + AMemoryHelper.Write(Context.Memory, OutputPosition, Args); + + return NvResult.Success; + } + + private static int GetId(ServiceCtx Context) + { + long InputPosition = Context.Request.GetBufferType0x21().Position; + long OutputPosition = Context.Request.GetBufferType0x22().Position; + + NvMapGetId Args = AMemoryHelper.Read(Context.Memory, InputPosition); + + NvMapHandle Map = GetNvMap(Context, Args.Handle); + + if (Map == null) + { + Context.Device.Log.PrintWarning(LogClass.ServiceNv, $"Invalid handle 0x{Args.Handle:x8}!"); + + return NvResult.InvalidInput; + } + + Args.Id = Args.Handle; + + AMemoryHelper.Write(Context.Memory, OutputPosition, Args); + + return NvResult.Success; + } + + private static int AddNvMap(ServiceCtx Context, NvMapHandle Map) + { + IdDictionary Dict = Maps.GetOrAdd(Context.Process, (Key) => + { + IdDictionary NewDict = new IdDictionary(); + + NewDict.Add(0, new NvMapHandle()); + + return NewDict; + }); + + return Dict.Add(Map); + } + + private static bool DeleteNvMap(ServiceCtx Context, int Handle) + { + if (Maps.TryGetValue(Context.Process, out IdDictionary Dict)) + { + return Dict.Delete(Handle) != null; + } + + return false; + } + + public static void InitializeNvMap(ServiceCtx Context) + { + IdDictionary Dict = Maps.GetOrAdd(Context.Process, (Key) =>new IdDictionary()); + + Dict.Add(0, new NvMapHandle()); + } + + public static NvMapHandle GetNvMapWithFb(ServiceCtx Context, int Handle) + { + if (Maps.TryGetValue(Context.Process, out IdDictionary Dict)) + { + return Dict.GetData(Handle); + } + + return null; + } + + public static NvMapHandle GetNvMap(ServiceCtx Context, int Handle) + { + if (Handle != 0 && Maps.TryGetValue(Context.Process, out IdDictionary Dict)) + { + return Dict.GetData(Handle); + } + + return null; + } + + public static void UnloadProcess(Process Process) + { + Maps.TryRemove(Process, out _); + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapParam.cs b/Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapParam.cs new file mode 100644 index 00000000..b5213efe --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapParam.cs @@ -0,0 +1,9 @@ +namespace Ryujinx.HLE.HOS.Services.Nv.NvMap +{ + struct NvMapParam + { + public int Handle; + public int Param; + public int Result; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvResult.cs b/Ryujinx.HLE/HOS/Services/Nv/NvResult.cs new file mode 100644 index 00000000..86ecd975 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvResult.cs @@ -0,0 +1,14 @@ +namespace Ryujinx.HLE.HOS.Services.Nv +{ + static class NvResult + { + public const int NotAvailableInProduction = 196614; + public const int Success = 0; + public const int TryAgain = -11; + public const int OutOfMemory = -12; + public const int InvalidInput = -22; + public const int NotSupported = -25; + public const int Restart = -85; + public const int TimedOut = -110; + } +} diff --git a/Ryujinx.HLE/HOS/Services/Pctl/IParentalControlService.cs b/Ryujinx.HLE/HOS/Services/Pctl/IParentalControlService.cs new file mode 100644 index 00000000..d484d312 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Pctl/IParentalControlService.cs @@ -0,0 +1,41 @@ +using Ryujinx.HLE.HOS.Ipc; +using Ryujinx.HLE.Logging; +using System.Collections.Generic; + +namespace Ryujinx.HLE.HOS.Services.Pctl +{ + class IParentalControlService : IpcService + { + private Dictionary m_Commands; + + public override IReadOnlyDictionary Commands => m_Commands; + + private bool Initialized = false; + + private bool NeedInitialize; + + public IParentalControlService(bool NeedInitialize = true) + { + m_Commands = new Dictionary() + { + { 1, Initialize } + }; + + this.NeedInitialize = NeedInitialize; + } + + public long Initialize(ServiceCtx Context) + { + if (NeedInitialize && !Initialized) + { + Initialized = true; + } + else + { + Context.Device.Log.PrintWarning(LogClass.ServicePctl, "Service is already initialized!"); + } + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Pctl/IParentalControlServiceFactory.cs b/Ryujinx.HLE/HOS/Services/Pctl/IParentalControlServiceFactory.cs new file mode 100644 index 00000000..157d594d --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Pctl/IParentalControlServiceFactory.cs @@ -0,0 +1,35 @@ +using Ryujinx.HLE.HOS.Ipc; +using System.Collections.Generic; + +namespace Ryujinx.HLE.HOS.Services.Pctl +{ + class IParentalControlServiceFactory : IpcService + { + private Dictionary m_Commands; + + public override IReadOnlyDictionary Commands => m_Commands; + + public IParentalControlServiceFactory() + { + m_Commands = new Dictionary() + { + { 0, CreateService }, + { 1, CreateServiceWithoutInitialize } + }; + } + + public long CreateService(ServiceCtx Context) + { + MakeObject(Context, new IParentalControlService()); + + return 0; + } + + public long CreateServiceWithoutInitialize(ServiceCtx Context) + { + MakeObject(Context, new IParentalControlService(false)); + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Pl/ISharedFontManager.cs b/Ryujinx.HLE/HOS/Services/Pl/ISharedFontManager.cs new file mode 100644 index 00000000..92821217 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Pl/ISharedFontManager.cs @@ -0,0 +1,125 @@ +using Ryujinx.HLE.HOS.Font; +using Ryujinx.HLE.HOS.Ipc; +using System.Collections.Generic; + +namespace Ryujinx.HLE.HOS.Services.Pl +{ + class ISharedFontManager : IpcService + { + private Dictionary m_Commands; + + public override IReadOnlyDictionary Commands => m_Commands; + + public ISharedFontManager() + { + m_Commands = new Dictionary() + { + { 0, RequestLoad }, + { 1, GetLoadState }, + { 2, GetFontSize }, + { 3, GetSharedMemoryAddressOffset }, + { 4, GetSharedMemoryNativeHandle }, + { 5, GetSharedFontInOrderOfPriority } + }; + } + + public long RequestLoad(ServiceCtx Context) + { + SharedFontType FontType = (SharedFontType)Context.RequestData.ReadInt32(); + + //We don't need to do anything here because we do lazy initialization + //on SharedFontManager (the font is loaded when necessary). + return 0; + } + + public long GetLoadState(ServiceCtx Context) + { + SharedFontType FontType = (SharedFontType)Context.RequestData.ReadInt32(); + + //1 (true) indicates that the font is already loaded. + //All fonts are already loaded. + Context.ResponseData.Write(1); + + return 0; + } + + public long GetFontSize(ServiceCtx Context) + { + SharedFontType FontType = (SharedFontType)Context.RequestData.ReadInt32(); + + Context.ResponseData.Write(Context.Device.System.Font.GetFontSize(FontType)); + + return 0; + } + + public long GetSharedMemoryAddressOffset(ServiceCtx Context) + { + SharedFontType FontType = (SharedFontType)Context.RequestData.ReadInt32(); + + Context.ResponseData.Write(Context.Device.System.Font.GetSharedMemoryAddressOffset(FontType)); + + return 0; + } + + public long GetSharedMemoryNativeHandle(ServiceCtx Context) + { + Context.Device.System.Font.EnsureInitialized(); + + int Handle = Context.Process.HandleTable.OpenHandle(Context.Device.System.FontSharedMem); + + Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle); + + return 0; + } + + public long GetSharedFontInOrderOfPriority(ServiceCtx Context) + { + long LanguageCode = Context.RequestData.ReadInt64(); + int LoadedCount = 0; + + for (SharedFontType Type = 0; Type < SharedFontType.Count; Type++) + { + int Offset = (int)Type * 4; + + if (!AddFontToOrderOfPriorityList(Context, (SharedFontType)Type, Offset)) + { + break; + } + + LoadedCount++; + } + + Context.ResponseData.Write(LoadedCount); + Context.ResponseData.Write((int)SharedFontType.Count); + + return 0; + } + + private bool AddFontToOrderOfPriorityList(ServiceCtx Context, SharedFontType FontType, int Offset) + { + long TypesPosition = Context.Request.ReceiveBuff[0].Position; + long TypesSize = Context.Request.ReceiveBuff[0].Size; + + long OffsetsPosition = Context.Request.ReceiveBuff[1].Position; + long OffsetsSize = Context.Request.ReceiveBuff[1].Size; + + long FontSizeBufferPosition = Context.Request.ReceiveBuff[2].Position; + long FontSizeBufferSize = Context.Request.ReceiveBuff[2].Size; + + if ((uint)Offset + 4 > (uint)TypesSize || + (uint)Offset + 4 > (uint)OffsetsSize || + (uint)Offset + 4 > (uint)FontSizeBufferSize) + { + return false; + } + + Context.Memory.WriteInt32(TypesPosition + Offset, (int)FontType); + + Context.Memory.WriteInt32(OffsetsPosition + Offset, Context.Device.System.Font.GetSharedMemoryAddressOffset(FontType)); + + Context.Memory.WriteInt32(FontSizeBufferPosition + Offset, Context.Device.System.Font.GetFontSize(FontType)); + + return true; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Prepo/IPrepoService.cs b/Ryujinx.HLE/HOS/Services/Prepo/IPrepoService.cs new file mode 100644 index 00000000..fa39854d --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Prepo/IPrepoService.cs @@ -0,0 +1,28 @@ +using Ryujinx.HLE.HOS.Ipc; +using Ryujinx.HLE.Logging; +using System.Collections.Generic; + +namespace Ryujinx.HLE.HOS.Services.Prepo +{ + class IPrepoService : IpcService + { + private Dictionary m_Commands; + + public override IReadOnlyDictionary Commands => m_Commands; + + public IPrepoService() + { + m_Commands = new Dictionary() + { + { 10101, SaveReportWithUser } + }; + } + + public static long SaveReportWithUser(ServiceCtx Context) + { + Context.Device.Log.PrintStub(LogClass.ServicePrepo, "Stubbed."); + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/ServiceFactory.cs b/Ryujinx.HLE/HOS/Services/ServiceFactory.cs new file mode 100644 index 00000000..babceb7d --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/ServiceFactory.cs @@ -0,0 +1,181 @@ +using Ryujinx.HLE.HOS.Services.Acc; +using Ryujinx.HLE.HOS.Services.Am; +using Ryujinx.HLE.HOS.Services.Apm; +using Ryujinx.HLE.HOS.Services.Aud; +using Ryujinx.HLE.HOS.Services.Bsd; +using Ryujinx.HLE.HOS.Services.Caps; +using Ryujinx.HLE.HOS.Services.FspSrv; +using Ryujinx.HLE.HOS.Services.Hid; +using Ryujinx.HLE.HOS.Services.Lm; +using Ryujinx.HLE.HOS.Services.Mm; +using Ryujinx.HLE.HOS.Services.Nfp; +using Ryujinx.HLE.HOS.Services.Ns; +using Ryujinx.HLE.HOS.Services.Nv; +using Ryujinx.HLE.HOS.Services.Pctl; +using Ryujinx.HLE.HOS.Services.Pl; +using Ryujinx.HLE.HOS.Services.Prepo; +using Ryujinx.HLE.HOS.Services.Set; +using Ryujinx.HLE.HOS.Services.Sfdnsres; +using Ryujinx.HLE.HOS.Services.Sm; +using Ryujinx.HLE.HOS.Services.Spl; +using Ryujinx.HLE.HOS.Services.Ssl; +using Ryujinx.HLE.HOS.Services.Vi; +using System; + +namespace Ryujinx.HLE.HOS.Services +{ + static class ServiceFactory + { + public static IpcService MakeService(string Name) + { + switch (Name) + { + case "acc:u0": + return new IAccountServiceForApplication(); + + case "aoc:u": + return new IAddOnContentManager(); + + case "apm": + return new IManager(); + + case "apm:p": + return new IManager(); + + case "appletAE": + return new IAllSystemAppletProxiesService(); + + case "appletOE": + return new IApplicationProxyService(); + + case "audout:u": + return new IAudioOutManager(); + + case "audren:u": + return new IAudioRendererManager(); + + case "bcat:a": + return new Bcat.IServiceCreator(); + + case "bcat:m": + return new Bcat.IServiceCreator(); + + case "bcat:u": + return new Bcat.IServiceCreator(); + + case "bcat:s": + return new Bcat.IServiceCreator(); + + case "bsd:s": + return new IClient(); + + case "bsd:u": + return new IClient(); + + case "caps:a": + return new IAlbumAccessorService(); + + case "caps:ss": + return new IScreenshotService(); + + case "csrng": + return new IRandomInterface(); + + case "friend:a": + return new Friend.IServiceCreator(); + + case "friend:u": + return new Friend.IServiceCreator(); + + case "fsp-srv": + return new IFileSystemProxy(); + + case "hid": + return new IHidServer(); + + case "lm": + return new ILogService(); + + case "mm:u": + return new IRequest(); + + case "nfp:user": + return new IUserManager(); + + case "nifm:u": + return new Nifm.IStaticService(); + + case "ns:ec": + return new IServiceGetterInterface(); + + case "ns:su": + return new ISystemUpdateInterface(); + + case "ns:vm": + return new IVulnerabilityManagerInterface(); + + case "nvdrv": + return new INvDrvServices(); + + case "nvdrv:a": + return new INvDrvServices(); + + case "pctl:s": + return new IParentalControlServiceFactory(); + + case "pctl:r": + return new IParentalControlServiceFactory(); + + case "pctl:a": + return new IParentalControlServiceFactory(); + + case "pctl": + return new IParentalControlServiceFactory(); + + case "pl:u": + return new ISharedFontManager(); + + case "prepo:a": + return new IPrepoService(); + + case "prepo:u": + return new IPrepoService(); + + case "set": + return new ISettingsServer(); + + case "set:sys": + return new ISystemSettingsServer(); + + case "sfdnsres": + return new IResolver(); + + case "sm:": + return new IUserInterface(); + + case "ssl": + return new ISslService(); + + case "time:a": + return new Time.IStaticService(); + + case "time:s": + return new Time.IStaticService(); + + case "time:u": + return new Time.IStaticService(); + + case "vi:m": + return new IManagerRootService(); + + case "vi:s": + return new ISystemRootService(); + + case "vi:u": + return new IApplicationRootService(); + } + + throw new NotImplementedException(Name); + } + } +} diff --git a/Ryujinx.HLE/HOS/Services/Set/ISettingsServer.cs b/Ryujinx.HLE/HOS/Services/Set/ISettingsServer.cs new file mode 100644 index 00000000..690d6de9 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Set/ISettingsServer.cs @@ -0,0 +1,79 @@ +using Ryujinx.HLE.HOS.Ipc; +using Ryujinx.HLE.HOS.SystemState; +using System.Collections.Generic; + +namespace Ryujinx.HLE.HOS.Services.Set +{ + class ISettingsServer : IpcService + { + private Dictionary m_Commands; + + public override IReadOnlyDictionary Commands => m_Commands; + + public ISettingsServer() + { + m_Commands = new Dictionary() + { + { 0, GetLanguageCode }, + { 1, GetAvailableLanguageCodes }, + { 3, GetAvailableLanguageCodeCount }, + { 5, GetAvailableLanguageCodes2 } + }; + } + + public static long GetLanguageCode(ServiceCtx Context) + { + Context.ResponseData.Write(Context.Device.System.State.DesiredLanguageCode); + + return 0; + } + + public static long GetAvailableLanguageCodes(ServiceCtx Context) + { + GetAvailableLanguagesCodesImpl( + Context, + Context.Request.RecvListBuff[0].Position, + Context.Request.RecvListBuff[0].Size); + + return 0; + } + + public static long GetAvailableLanguageCodeCount(ServiceCtx Context) + { + Context.ResponseData.Write(SystemStateMgr.LanguageCodes.Length); + + return 0; + } + + public static long GetAvailableLanguageCodes2(ServiceCtx Context) + { + GetAvailableLanguagesCodesImpl( + Context, + Context.Request.ReceiveBuff[0].Position, + Context.Request.ReceiveBuff[0].Size); + + return 0; + } + + public static long GetAvailableLanguagesCodesImpl(ServiceCtx Context, long Position, long Size) + { + int Count = (int)(Size / 8); + + if (Count > SystemStateMgr.LanguageCodes.Length) + { + Count = SystemStateMgr.LanguageCodes.Length; + } + + for (int Index = 0; Index < Count; Index++) + { + Context.Memory.WriteInt64(Position, SystemStateMgr.GetLanguageCode(Index)); + + Position += 8; + } + + Context.ResponseData.Write(Count); + + return 0; + } + } +} diff --git a/Ryujinx.HLE/HOS/Services/Set/ISystemSettingsServer.cs b/Ryujinx.HLE/HOS/Services/Set/ISystemSettingsServer.cs new file mode 100644 index 00000000..dc146967 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Set/ISystemSettingsServer.cs @@ -0,0 +1,151 @@ +using Ryujinx.HLE.HOS.Ipc; +using Ryujinx.HLE.HOS.SystemState; +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; + +namespace Ryujinx.HLE.HOS.Services.Set +{ + class ISystemSettingsServer : IpcService + { + private Dictionary m_Commands; + + public override IReadOnlyDictionary Commands => m_Commands; + + public ISystemSettingsServer() + { + m_Commands = new Dictionary() + { + { 4, GetFirmwareVersion2 }, + { 23, GetColorSetId }, + { 24, SetColorSetId }, + { 38, GetSettingsItemValue } + }; + } + + public static long GetFirmwareVersion2(ServiceCtx Context) + { + long ReplyPos = Context.Request.RecvListBuff[0].Position; + long ReplySize = Context.Request.RecvListBuff[0].Size; + + const byte MajorFWVersion = 0x03; + const byte MinorFWVersion = 0x00; + const byte MicroFWVersion = 0x00; + const byte Unknown = 0x00; //Build? + + const int RevisionNumber = 0x0A; + + const string Platform = "NX"; + const string UnknownHex = "7fbde2b0bba4d14107bf836e4643043d9f6c8e47"; + const string Version = "3.0.0"; + const string Build = "NintendoSDK Firmware for NX 3.0.0-10.0"; + + //http://switchbrew.org/index.php?title=System_Version_Title + using (MemoryStream MS = new MemoryStream(0x100)) + { + BinaryWriter Writer = new BinaryWriter(MS); + + Writer.Write(MajorFWVersion); + Writer.Write(MinorFWVersion); + Writer.Write(MicroFWVersion); + Writer.Write(Unknown); + + Writer.Write(RevisionNumber); + + Writer.Write(Encoding.ASCII.GetBytes(Platform)); + + MS.Seek(0x28, SeekOrigin.Begin); + + Writer.Write(Encoding.ASCII.GetBytes(UnknownHex)); + + MS.Seek(0x68, SeekOrigin.Begin); + + Writer.Write(Encoding.ASCII.GetBytes(Version)); + + MS.Seek(0x80, SeekOrigin.Begin); + + Writer.Write(Encoding.ASCII.GetBytes(Build)); + + Context.Memory.WriteBytes(ReplyPos, MS.ToArray()); + } + + return 0; + } + + public static long GetColorSetId(ServiceCtx Context) + { + Context.ResponseData.Write((int)Context.Device.System.State.ThemeColor); + + return 0; + } + + public static long SetColorSetId(ServiceCtx Context) + { + int ColorSetId = Context.RequestData.ReadInt32(); + + Context.Device.System.State.ThemeColor = (ColorSet)ColorSetId; + + return 0; + } + + public static long GetSettingsItemValue(ServiceCtx Context) + { + long ClassPos = Context.Request.PtrBuff[0].Position; + long ClassSize = Context.Request.PtrBuff[0].Size; + + long NamePos = Context.Request.PtrBuff[1].Position; + long NameSize = Context.Request.PtrBuff[1].Size; + + long ReplyPos = Context.Request.ReceiveBuff[0].Position; + long ReplySize = Context.Request.ReceiveBuff[0].Size; + + byte[] Class = Context.Memory.ReadBytes(ClassPos, ClassSize); + byte[] Name = Context.Memory.ReadBytes(NamePos, NameSize); + + string AskedSetting = Encoding.ASCII.GetString(Class).Trim('\0') + "!" + Encoding.ASCII.GetString(Name).Trim('\0'); + + NxSettings.Settings.TryGetValue(AskedSetting, out object NxSetting); + + if (NxSetting != null) + { + byte[] SettingBuffer = new byte[ReplySize]; + + if (NxSetting is string StringValue) + { + if (StringValue.Length + 1 > ReplySize) + { + Context.Device.Log.PrintError(Logging.LogClass.ServiceSet, $"{AskedSetting} String value size is too big!"); + } + else + { + SettingBuffer = Encoding.ASCII.GetBytes(StringValue + "\0"); + } + } + + if (NxSetting is int IntValue) + { + SettingBuffer = BitConverter.GetBytes(IntValue); + } + else if (NxSetting is bool BoolValue) + { + SettingBuffer[0] = BoolValue ? (byte)1 : (byte)0; + } + else + { + throw new NotImplementedException(NxSetting.GetType().Name); + } + + Context.Memory.WriteBytes(ReplyPos, SettingBuffer); + + Context.Device.Log.PrintDebug(Logging.LogClass.ServiceSet, $"{AskedSetting} set value: {NxSetting} as {NxSetting.GetType()}"); + } + else + { + Context.Device.Log.PrintError(Logging.LogClass.ServiceSet, $"{AskedSetting} not found!"); + } + + return 0; + } + } +} diff --git a/Ryujinx.HLE/HOS/Services/Set/NxSettings.cs b/Ryujinx.HLE/HOS/Services/Set/NxSettings.cs new file mode 100644 index 00000000..7d1dd2ed --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Set/NxSettings.cs @@ -0,0 +1,1711 @@ +using System.Collections.Generic; + +namespace Ryujinx.HLE.HOS.Services.Set +{ + static class NxSettings + { + //Generated automatically from a Switch 3.0 config file (Tid: 0100000000000818). + public static Dictionary Settings = new Dictionary() + { + { "account!na_required_for_network_service", true }, + { "account.daemon!background_awaking_periodicity", 10800 }, + { "account.daemon!schedule_periodicity", 3600 }, + { "account.daemon!profile_sync_interval", 18000 }, + { "account.daemon!na_info_refresh_interval", 46800 }, + { "am.display!transition_layer_enabled", true }, + { "am.gpu!gpu_scheduling_enabled", true }, + { "am.gpu!gpu_scheduling_frame_time_us", 116666 }, + { "am.gpu!gpu_scheduling_fg_app_us", 116166 }, + { "am.gpu!gpu_scheduling_bg_app_us", 104500 }, + { "am.gpu!gpu_scheduling_oa_us", 500 }, + { "am.gpu!gpu_scheduling_fg_sa_us", 11666 }, + { "am.gpu!gpu_scheduling_bg_sa_us", 0 }, + { "am.gpu!gpu_scheduling_fg_la_us", 11666 }, + { "am.gpu!gpu_scheduling_partial_fg_la_us", 2000 }, + { "am.gpu!gpu_scheduling_bg_la_us", 0 }, + { "audio!audren_log_enabled", false }, + { "audio!audout_log_enabled", false }, + { "audio!audin_log_enabled", false }, + { "audio!hwopus_log_enabled", false }, + { "audio!adsp_log_enabled", false }, + { "audio!suspend_for_debugger_enabled", false }, + { "audio!uac_speaker_enabled", false }, + { "bgtc!enable_halfawake", 1 }, + { "bgtc!enable_battery_saver", 1 }, + { "bgtc!leaving_halfawake_margin", 3 }, + { "bgtc!battery_threshold_save", 20 }, + { "bgtc!battery_threshold_stop", 20 }, + { "bgtc!minimum_interval_normal", 1800 }, + { "bgtc!minimum_interval_save", 86400 }, + { "boot!force_maintenance", false }, + { "capsrv!screenshot_layerstack", "screenshot" }, + { "capsrv!enable_album_screenshot_filedata_verification", true }, + { "devmenu!enable_application_update", true }, + { "devmenu!enable_exhibition_mode", false }, + { "eclct!analytics_override", false }, + { "eclct!analytics_pollperiod", 86400 }, + { "err!applet_auto_close", false }, + { "friends!background_processing", true }, + { "htc!disconnection_emulation", false }, + { "idle!dim_level_percent_lcd", 10 }, + { "idle!dim_level_percent_tv", 70 }, + { "lbl!force_disable_als", false }, + { "lm!enable_sd_card_logging", false }, + { "lm!sd_card_log_output_directory", "NxBinLogs" }, + { "mii!is_db_test_mode_enabled", false }, + { "news!system_version", 2 }, + { "nfp!not_locked_tag", true }, + { "nfp!play_report", false }, + { "nifm!is_communication_control_enabled_for_test", false }, + { "nifm!connection_test_timeout", 45000 }, + { "nifm!apply_config_timeout", 30000 }, + { "nifm!ethernet_adapter_standby_time", 10000 }, + { "nim.install!prefer_delta_evenif_inefficient", false }, + { "nim.install!apply_delta_stress_storage", 0 }, + { "ns.notification!retry_interval", 60 }, + { "ns.notification!enable_network_update", true }, + { "ns.notification!enable_download_task_list", true }, + { "ns.notification!enable_version_list", true }, + { "ns.notification!enable_random_wait", true }, + { "ns.notification!debug_waiting_limit", 0 }, + { "ns.notification!enable_request_on_cold_boot", true }, + { "ns.sdcard!mount_sdcard", true }, + { "ns.sdcard!compare_sdcard", 0 }, + { "ns.gamecard!mount_gamecard_result_value", 0 }, + { "ns.gamecard!try_gamecard_access_result_value", 0 }, + { "nv!00008600", "" }, + { "nv!0007b25e", "" }, + { "nv!0083e1", "" }, + { "nv!01621887", "" }, + { "nv!03134743", "" }, + { "nv!0356afd0", "" }, + { "nv!0356afd1", "" }, + { "nv!0356afd2", "" }, + { "nv!0356afd3", "" }, + { "nv!094313", "" }, + { "nv!0x04dc09", "" }, + { "nv!0x111133", "" }, + { "nv!0x1aa483", "" }, + { "nv!0x1cb1cf", "" }, + { "nv!0x1cb1d0", "" }, + { "nv!0x1e3221", "" }, + { "nv!0x300fc8", "" }, + { "nv!0x301fc8", "" }, + { "nv!0x302fc8", "" }, + { "nv!0x3eec59", "" }, + { "nv!0x46b3ed", "" }, + { "nv!0x523dc0", "" }, + { "nv!0x523dc1", "" }, + { "nv!0x523dc2", "" }, + { "nv!0x523dc3", "" }, + { "nv!0x523dc4", "" }, + { "nv!0x523dc5", "" }, + { "nv!0x523dc6", "" }, + { "nv!0x523dd0", "" }, + { "nv!0x523dd1", "" }, + { "nv!0x523dd3", "" }, + { "nv!0x5344bb", "" }, + { "nv!0x555237", "" }, + { "nv!0x58a234", "" }, + { "nv!0x7b4428", "" }, + { "nv!0x923dc0", "" }, + { "nv!0x923dc1", "" }, + { "nv!0x923dc2", "" }, + { "nv!0x923dc3", "" }, + { "nv!0x923dc4", "" }, + { "nv!0x923dd3", "" }, + { "nv!0x9abdc5", "" }, + { "nv!0x9abdc6", "" }, + { "nv!0xaaa36c", "" }, + { "nv!0xb09da0", "" }, + { "nv!0xb09da1", "" }, + { "nv!0xb09da2", "" }, + { "nv!0xb09da3", "" }, + { "nv!0xb09da4", "" }, + { "nv!0xb09da5", "" }, + { "nv!0xb0b348", "" }, + { "nv!0xb0b349", "" }, + { "nv!0xbb558f", "" }, + { "nv!0xbd10fb", "" }, + { "nv!0xc32ad3", "" }, + { "nv!0xce2348", "" }, + { "nv!0xcfd81f", "" }, + { "nv!0xe0036b", "" }, + { "nv!0xe01f2d", "" }, + { "nv!0xe17212", "" }, + { "nv!0xeae966", "" }, + { "nv!0xed4f82", "" }, + { "nv!0xf12335", "" }, + { "nv!0xf12336", "" }, + { "nv!10261989", "" }, + { "nv!1042d483", "" }, + { "nv!10572898", "" }, + { "nv!115631", "" }, + { "nv!12950094", "" }, + { "nv!1314f311", "" }, + { "nv!1314f312", "" }, + { "nv!13279512", "" }, + { "nv!13813496", "" }, + { "nv!14507179", "" }, + { "nv!15694569", "" }, + { "nv!16936964", "" }, + { "nv!17aa230c", "" }, + { "nv!182054", "" }, + { "nv!18273275", "" }, + { "nv!18273276", "" }, + { "nv!1854d03b", "" }, + { "nv!18add00d", "" }, + { "nv!19156670", "" }, + { "nv!19286545", "" }, + { "nv!1a298e9f", "" }, + { "nv!1acf43fe", "" }, + { "nv!1bda43fe", "" }, + { "nv!1c3b92", "" }, + { "nv!21509920", "" }, + { "nv!215323457", "" }, + { "nv!2165ad", "" }, + { "nv!2165ae", "" }, + { "nv!21be9c", "" }, + { "nv!233264316", "" }, + { "nv!234557580", "" }, + { "nv!23cd0e", "" }, + { "nv!24189123", "" }, + { "nv!2443266", "" }, + { "nv!25025519", "" }, + { "nv!255e39", "" }, + { "nv!2583364", "" }, + { "nv!2888c1", "" }, + { "nv!28ca3e", "" }, + { "nv!29871243", "" }, + { "nv!2a1f64", "" }, + { "nv!2dc432", "" }, + { "nv!2de437", "" }, + { "nv!2f3bb89c", "" }, + { "nv!2fd652", "" }, + { "nv!3001ac", "" }, + { "nv!31298772", "" }, + { "nv!313233", "" }, + { "nv!31f7d603", "" }, + { "nv!320ce4", "" }, + { "nv!32153248", "" }, + { "nv!32153249", "" }, + { "nv!335bca", "" }, + { "nv!342abb", "" }, + { "nv!34dfe6", "" }, + { "nv!34dfe7", "" }, + { "nv!34dfe8", "" }, + { "nv!34dfe9", "" }, + { "nv!35201578", "" }, + { "nv!359278", "" }, + { "nv!37f53a", "" }, + { "nv!38144972", "" }, + { "nv!38542646", "" }, + { "nv!3b74c9", "" }, + { "nv!3c136f", "" }, + { "nv!3cf72823", "" }, + { "nv!3d7af029", "" }, + { "nv!3ff34782", "" }, + { "nv!4129618", "" }, + { "nv!4189fac3", "" }, + { "nv!420bd4", "" }, + { "nv!42a699", "" }, + { "nv!441369", "" }, + { "nv!4458713e", "" }, + { "nv!4554b6", "" }, + { "nv!457425", "" }, + { "nv!4603b207", "" }, + { "nv!46574957", "" }, + { "nv!46574958", "" }, + { "nv!46813529", "" }, + { "nv!46f1e13d", "" }, + { "nv!47534c43", "" }, + { "nv!48550336", "" }, + { "nv!48576893", "" }, + { "nv!48576894", "" }, + { "nv!4889ac02", "" }, + { "nv!49005740", "" }, + { "nv!49867584", "" }, + { "nv!49960973", "" }, + { "nv!4a5341", "" }, + { "nv!4f4e48", "" }, + { "nv!4f8a0a", "" }, + { "nv!50299698", "" }, + { "nv!50299699", "" }, + { "nv!50361291", "" }, + { "nv!5242ae", "" }, + { "nv!53d30c", "" }, + { "nv!56347a", "" }, + { "nv!563a95f1", "" }, + { "nv!573823", "" }, + { "nv!58027529", "" }, + { "nv!5d2d63", "" }, + { "nv!5f7e3b", "" }, + { "nv!60461793", "" }, + { "nv!60d355", "" }, + { "nv!616627aa", "" }, + { "nv!62317182", "" }, + { "nv!6253fa2e", "" }, + { "nv!64100768", "" }, + { "nv!64100769", "" }, + { "nv!64100770", "" }, + { "nv!647395", "" }, + { "nv!66543234", "" }, + { "nv!67674763", "" }, + { "nv!67739784", "" }, + { "nv!68fb9c", "" }, + { "nv!69801276", "" }, + { "nv!6af9fa2f", "" }, + { "nv!6af9fa3f", "" }, + { "nv!6af9fa4f", "" }, + { "nv!6bd8c7", "" }, + { "nv!6c7691", "" }, + { "nv!6d4296ce", "" }, + { "nv!6dd7e7", "" }, + { "nv!6dd7e8", "" }, + { "nv!6fe11ec1", "" }, + { "nv!716511763", "" }, + { "nv!72504593", "" }, + { "nv!73304097", "" }, + { "nv!73314098", "" }, + { "nv!74095213", "" }, + { "nv!74095213a", "" }, + { "nv!74095213b", "" }, + { "nv!74095214", "" }, + { "nv!748f9649", "" }, + { "nv!75494732", "" }, + { "nv!78452832", "" }, + { "nv!784561", "" }, + { "nv!78e16b9c", "" }, + { "nv!79251225", "" }, + { "nv!7c128b", "" }, + { "nv!7ccd93", "" }, + { "nv!7df8d1", "" }, + { "nv!800c2310", "" }, + { "nv!80546710", "" }, + { "nv!80772310", "" }, + { "nv!808ee280", "" }, + { "nv!81131154", "" }, + { "nv!81274457", "" }, + { "nv!8292291f", "" }, + { "nv!83498426", "" }, + { "nv!84993794", "" }, + { "nv!84995585", "" }, + { "nv!84a0a0", "" }, + { "nv!852142", "" }, + { "nv!85612309", "" }, + { "nv!85612310", "" }, + { "nv!85612311", "" }, + { "nv!85612312", "" }, + { "nv!8623ff27", "" }, + { "nv!87364952", "" }, + { "nv!87f6275666", "" }, + { "nv!886748", "" }, + { "nv!89894423", "" }, + { "nv!8ad8a75", "" }, + { "nv!8ad8ad00", "" }, + { "nv!8bb815", "" }, + { "nv!8bb817", "" }, + { "nv!8bb818", "" }, + { "nv!8bb819", "" }, + { "nv!8e640cd1", "" }, + { "nv!8f34971a", "" }, + { "nv!8f773984", "" }, + { "nv!8f7a7d", "" }, + { "nv!902486209", "" }, + { "nv!90482571", "" }, + { "nv!91214835", "" }, + { "nv!912848290", "" }, + { "nv!915e56", "" }, + { "nv!92179063", "" }, + { "nv!92179064", "" }, + { "nv!92179065", "" }, + { "nv!92179066", "" }, + { "nv!92350358", "" }, + { "nv!92809063", "" }, + { "nv!92809064", "" }, + { "nv!92809065", "" }, + { "nv!92809066", "" }, + { "nv!92920143", "" }, + { "nv!93a89b12", "" }, + { "nv!93a89c0b", "" }, + { "nv!94812574", "" }, + { "nv!95282304", "" }, + { "nv!95394027", "" }, + { "nv!959b1f", "" }, + { "nv!9638af", "" }, + { "nv!96fd59", "" }, + { "nv!97f6275666", "" }, + { "nv!97f6275667", "" }, + { "nv!97f6275668", "" }, + { "nv!97f6275669", "" }, + { "nv!97f627566a", "" }, + { "nv!97f627566b", "" }, + { "nv!97f627566d", "" }, + { "nv!97f627566e", "" }, + { "nv!97f627566f", "" }, + { "nv!97f6275670", "" }, + { "nv!97f6275671", "" }, + { "nv!97f727566e", "" }, + { "nv!98480775", "" }, + { "nv!98480776", "" }, + { "nv!98480777", "" }, + { "nv!992431", "" }, + { "nv!9aa29065", "" }, + { "nv!9af32c", "" }, + { "nv!9af32d", "" }, + { "nv!9af32e", "" }, + { "nv!9c108b71", "" }, + { "nv!9f279065", "" }, + { "nv!a01bc728", "" }, + { "nv!a13b46c80", "" }, + { "nv!a22eb0", "" }, + { "nv!a2fb451e", "" }, + { "nv!a3456abe", "" }, + { "nv!a7044887", "" }, + { "nv!a7149200", "" }, + { "nv!a766215670", "" }, + { "nv!aac_drc_boost", "" }, + { "nv!aac_drc_cut", "" }, + { "nv!aac_drc_enc_target_level", "" }, + { "nv!aac_drc_heavy", "" }, + { "nv!aac_drc_reference_level", "" }, + { "nv!aalinegamma", "" }, + { "nv!aalinetweaks", "" }, + { "nv!ab34ee01", "" }, + { "nv!ab34ee02", "" }, + { "nv!ab34ee03", "" }, + { "nv!ac0274", "" }, + { "nv!af73c63e", "" }, + { "nv!af73c63f", "" }, + { "nv!af9927", "" }, + { "nv!afoverride", "" }, + { "nv!allocdeviceevents", "" }, + { "nv!applicationkey", "" }, + { "nv!appreturnonlybasicglsltype", "" }, + { "nv!app_softimage", "" }, + { "nv!app_supportbits2", "" }, + { "nv!assumetextureismipmappedatcreation", "" }, + { "nv!b1fb0f01", "" }, + { "nv!b3edd5", "" }, + { "nv!b40d9e03d", "" }, + { "nv!b7f6275666", "" }, + { "nv!b812c1", "" }, + { "nv!ba14ba1a", "" }, + { "nv!ba14ba1b", "" }, + { "nv!bd7559", "" }, + { "nv!bd755a", "" }, + { "nv!bd755c", "" }, + { "nv!bd755d", "" }, + { "nv!be58bb", "" }, + { "nv!be92cb", "" }, + { "nv!beefcba3", "" }, + { "nv!beefcba4", "" }, + { "nv!c023777f", "" }, + { "nv!c09dc8", "" }, + { "nv!c0d340", "" }, + { "nv!c2ff374c", "" }, + { "nv!c5e9d7a3", "" }, + { "nv!c5e9d7a4", "" }, + { "nv!c5e9d7b4", "" }, + { "nv!c618f9", "" }, + { "nv!ca345840", "" }, + { "nv!cachedisable", "" }, + { "nv!cast.on", "" }, + { "nv!cde", "" }, + { "nv!channelpriorityoverride", "" }, + { "nv!cleardatastorevidmem", "" }, + { "nv!cmdbufmemoryspaceenables", "" }, + { "nv!cmdbufminwords", "" }, + { "nv!cmdbufsizewords", "" }, + { "nv!conformantblitframebufferscissor", "" }, + { "nv!conformantincompletetextures", "" }, + { "nv!copybuffermethod", "" }, + { "nv!cubemapaniso", "" }, + { "nv!cubemapfiltering", "" }, + { "nv!d0e9a4d7", "" }, + { "nv!d13733f12", "" }, + { "nv!d1b399", "" }, + { "nv!d2983c32", "" }, + { "nv!d2983c33", "" }, + { "nv!d2e71b", "" }, + { "nv!d377dc", "" }, + { "nv!d377dd", "" }, + { "nv!d489f4", "" }, + { "nv!d4bce1", "" }, + { "nv!d518cb", "" }, + { "nv!d518cd", "" }, + { "nv!d518ce", "" }, + { "nv!d518d0", "" }, + { "nv!d518d1", "" }, + { "nv!d518d2", "" }, + { "nv!d518d3", "" }, + { "nv!d518d4", "" }, + { "nv!d518d5", "" }, + { "nv!d59eda", "" }, + { "nv!d83cbd", "" }, + { "nv!d8e777", "" }, + { "nv!debug_level", "" }, + { "nv!debug_mask", "" }, + { "nv!debug_options", "" }, + { "nv!devshmpageableallocations", "" }, + { "nv!df1f9812", "" }, + { "nv!df783c", "" }, + { "nv!diagenable", "" }, + { "nv!disallowcemask", "" }, + { "nv!disallowz16", "" }, + { "nv!dlmemoryspaceenables", "" }, + { "nv!e0bfec", "" }, + { "nv!e433456d", "" }, + { "nv!e435563f", "" }, + { "nv!e4cd9c", "" }, + { "nv!e5c972", "" }, + { "nv!e639ef", "" }, + { "nv!e802af", "" }, + { "nv!eae964", "" }, + { "nv!earlytexturehwallocation", "" }, + { "nv!eb92a3", "" }, + { "nv!ebca56", "" }, + { "nv!enable-noaud", "" }, + { "nv!enable-noavs", "" }, + { "nv!enable-prof", "" }, + { "nv!enable-sxesmode", "" }, + { "nv!enable-ulld", "" }, + { "nv!expert_detail_level", "" }, + { "nv!expert_output_mask", "" }, + { "nv!expert_report_mask", "" }, + { "nv!extensionstringnvarch", "" }, + { "nv!extensionstringversion", "" }, + { "nv!f00f1938", "" }, + { "nv!f10736", "" }, + { "nv!f1846870", "" }, + { "nv!f33bc370", "" }, + { "nv!f392a874", "" }, + { "nv!f49ae8", "" }, + { "nv!fa345cce", "" }, + { "nv!fa35cc4", "" }, + { "nv!faa14a", "" }, + { "nv!faf8a723", "" }, + { "nv!fastgs", "" }, + { "nv!fbf4ac45", "" }, + { "nv!fbo_blit_ignore_srgb", "" }, + { "nv!fc64c7", "" }, + { "nv!ff54ec97", "" }, + { "nv!ff54ec98", "" }, + { "nv!forceexitprocessdetach", "" }, + { "nv!forcerequestedesversion", "" }, + { "nv!__gl_", "" }, + { "nv!__gl_00008600", "" }, + { "nv!__gl_0007b25e", "" }, + { "nv!__gl_0083e1", "" }, + { "nv!__gl_01621887", "" }, + { "nv!__gl_03134743", "" }, + { "nv!__gl_0356afd0", "" }, + { "nv!__gl_0356afd1", "" }, + { "nv!__gl_0356afd2", "" }, + { "nv!__gl_0356afd3", "" }, + { "nv!__gl_094313", "" }, + { "nv!__gl_0x04dc09", "" }, + { "nv!__gl_0x111133", "" }, + { "nv!__gl_0x1aa483", "" }, + { "nv!__gl_0x1cb1cf", "" }, + { "nv!__gl_0x1cb1d0", "" }, + { "nv!__gl_0x1e3221", "" }, + { "nv!__gl_0x300fc8", "" }, + { "nv!__gl_0x301fc8", "" }, + { "nv!__gl_0x302fc8", "" }, + { "nv!__gl_0x3eec59", "" }, + { "nv!__gl_0x46b3ed", "" }, + { "nv!__gl_0x523dc0", "" }, + { "nv!__gl_0x523dc1", "" }, + { "nv!__gl_0x523dc2", "" }, + { "nv!__gl_0x523dc3", "" }, + { "nv!__gl_0x523dc4", "" }, + { "nv!__gl_0x523dc5", "" }, + { "nv!__gl_0x523dc6", "" }, + { "nv!__gl_0x523dd0", "" }, + { "nv!__gl_0x523dd1", "" }, + { "nv!__gl_0x523dd3", "" }, + { "nv!__gl_0x5344bb", "" }, + { "nv!__gl_0x555237", "" }, + { "nv!__gl_0x58a234", "" }, + { "nv!__gl_0x7b4428", "" }, + { "nv!__gl_0x923dc0", "" }, + { "nv!__gl_0x923dc1", "" }, + { "nv!__gl_0x923dc2", "" }, + { "nv!__gl_0x923dc3", "" }, + { "nv!__gl_0x923dc4", "" }, + { "nv!__gl_0x923dd3", "" }, + { "nv!__gl_0x9abdc5", "" }, + { "nv!__gl_0x9abdc6", "" }, + { "nv!__gl_0xaaa36c", "" }, + { "nv!__gl_0xb09da0", "" }, + { "nv!__gl_0xb09da1", "" }, + { "nv!__gl_0xb09da2", "" }, + { "nv!__gl_0xb09da3", "" }, + { "nv!__gl_0xb09da4", "" }, + { "nv!__gl_0xb09da5", "" }, + { "nv!__gl_0xb0b348", "" }, + { "nv!__gl_0xb0b349", "" }, + { "nv!__gl_0xbb558f", "" }, + { "nv!__gl_0xbd10fb", "" }, + { "nv!__gl_0xc32ad3", "" }, + { "nv!__gl_0xce2348", "" }, + { "nv!__gl_0xcfd81f", "" }, + { "nv!__gl_0xe0036b", "" }, + { "nv!__gl_0xe01f2d", "" }, + { "nv!__gl_0xe17212", "" }, + { "nv!__gl_0xeae966", "" }, + { "nv!__gl_0xed4f82", "" }, + { "nv!__gl_0xf12335", "" }, + { "nv!__gl_0xf12336", "" }, + { "nv!__gl_10261989", "" }, + { "nv!__gl_1042d483", "" }, + { "nv!__gl_10572898", "" }, + { "nv!__gl_115631", "" }, + { "nv!__gl_12950094", "" }, + { "nv!__gl_1314f311", "" }, + { "nv!__gl_1314f312", "" }, + { "nv!__gl_13279512", "" }, + { "nv!__gl_13813496", "" }, + { "nv!__gl_14507179", "" }, + { "nv!__gl_15694569", "" }, + { "nv!__gl_16936964", "" }, + { "nv!__gl_17aa230c", "" }, + { "nv!__gl_182054", "" }, + { "nv!__gl_18273275", "" }, + { "nv!__gl_18273276", "" }, + { "nv!__gl_1854d03b", "" }, + { "nv!__gl_18add00d", "" }, + { "nv!__gl_19156670", "" }, + { "nv!__gl_19286545", "" }, + { "nv!__gl_1a298e9f", "" }, + { "nv!__gl_1acf43fe", "" }, + { "nv!__gl_1bda43fe", "" }, + { "nv!__gl_1c3b92", "" }, + { "nv!__gl_21509920", "" }, + { "nv!__gl_215323457", "" }, + { "nv!__gl_2165ad", "" }, + { "nv!__gl_2165ae", "" }, + { "nv!__gl_21be9c", "" }, + { "nv!__gl_233264316", "" }, + { "nv!__gl_234557580", "" }, + { "nv!__gl_23cd0e", "" }, + { "nv!__gl_24189123", "" }, + { "nv!__gl_2443266", "" }, + { "nv!__gl_25025519", "" }, + { "nv!__gl_255e39", "" }, + { "nv!__gl_2583364", "" }, + { "nv!__gl_2888c1", "" }, + { "nv!__gl_28ca3e", "" }, + { "nv!__gl_29871243", "" }, + { "nv!__gl_2a1f64", "" }, + { "nv!__gl_2dc432", "" }, + { "nv!__gl_2de437", "" }, + { "nv!__gl_2f3bb89c", "" }, + { "nv!__gl_2fd652", "" }, + { "nv!__gl_3001ac", "" }, + { "nv!__gl_31298772", "" }, + { "nv!__gl_313233", "" }, + { "nv!__gl_31f7d603", "" }, + { "nv!__gl_320ce4", "" }, + { "nv!__gl_32153248", "" }, + { "nv!__gl_32153249", "" }, + { "nv!__gl_335bca", "" }, + { "nv!__gl_342abb", "" }, + { "nv!__gl_34dfe6", "" }, + { "nv!__gl_34dfe7", "" }, + { "nv!__gl_34dfe8", "" }, + { "nv!__gl_34dfe9", "" }, + { "nv!__gl_35201578", "" }, + { "nv!__gl_359278", "" }, + { "nv!__gl_37f53a", "" }, + { "nv!__gl_38144972", "" }, + { "nv!__gl_38542646", "" }, + { "nv!__gl_3b74c9", "" }, + { "nv!__gl_3c136f", "" }, + { "nv!__gl_3cf72823", "" }, + { "nv!__gl_3d7af029", "" }, + { "nv!__gl_3ff34782", "" }, + { "nv!__gl_4129618", "" }, + { "nv!__gl_4189fac3", "" }, + { "nv!__gl_420bd4", "" }, + { "nv!__gl_42a699", "" }, + { "nv!__gl_441369", "" }, + { "nv!__gl_4458713e", "" }, + { "nv!__gl_4554b6", "" }, + { "nv!__gl_457425", "" }, + { "nv!__gl_4603b207", "" }, + { "nv!__gl_46574957", "" }, + { "nv!__gl_46574958", "" }, + { "nv!__gl_46813529", "" }, + { "nv!__gl_46f1e13d", "" }, + { "nv!__gl_47534c43", "" }, + { "nv!__gl_48550336", "" }, + { "nv!__gl_48576893", "" }, + { "nv!__gl_48576894", "" }, + { "nv!__gl_4889ac02", "" }, + { "nv!__gl_49005740", "" }, + { "nv!__gl_49867584", "" }, + { "nv!__gl_49960973", "" }, + { "nv!__gl_4a5341", "" }, + { "nv!__gl_4f4e48", "" }, + { "nv!__gl_4f8a0a", "" }, + { "nv!__gl_50299698", "" }, + { "nv!__gl_50299699", "" }, + { "nv!__gl_50361291", "" }, + { "nv!__gl_5242ae", "" }, + { "nv!__gl_53d30c", "" }, + { "nv!__gl_56347a", "" }, + { "nv!__gl_563a95f1", "" }, + { "nv!__gl_573823", "" }, + { "nv!__gl_58027529", "" }, + { "nv!__gl_5d2d63", "" }, + { "nv!__gl_5f7e3b", "" }, + { "nv!__gl_60461793", "" }, + { "nv!__gl_60d355", "" }, + { "nv!__gl_616627aa", "" }, + { "nv!__gl_62317182", "" }, + { "nv!__gl_6253fa2e", "" }, + { "nv!__gl_64100768", "" }, + { "nv!__gl_64100769", "" }, + { "nv!__gl_64100770", "" }, + { "nv!__gl_647395", "" }, + { "nv!__gl_66543234", "" }, + { "nv!__gl_67674763", "" }, + { "nv!__gl_67739784", "" }, + { "nv!__gl_68fb9c", "" }, + { "nv!__gl_69801276", "" }, + { "nv!__gl_6af9fa2f", "" }, + { "nv!__gl_6af9fa3f", "" }, + { "nv!__gl_6af9fa4f", "" }, + { "nv!__gl_6bd8c7", "" }, + { "nv!__gl_6c7691", "" }, + { "nv!__gl_6d4296ce", "" }, + { "nv!__gl_6dd7e7", "" }, + { "nv!__gl_6dd7e8", "" }, + { "nv!__gl_6fe11ec1", "" }, + { "nv!__gl_716511763", "" }, + { "nv!__gl_72504593", "" }, + { "nv!__gl_73304097", "" }, + { "nv!__gl_73314098", "" }, + { "nv!__gl_74095213", "" }, + { "nv!__gl_74095213a", "" }, + { "nv!__gl_74095213b", "" }, + { "nv!__gl_74095214", "" }, + { "nv!__gl_748f9649", "" }, + { "nv!__gl_75494732", "" }, + { "nv!__gl_78452832", "" }, + { "nv!__gl_784561", "" }, + { "nv!__gl_78e16b9c", "" }, + { "nv!__gl_79251225", "" }, + { "nv!__gl_7c128b", "" }, + { "nv!__gl_7ccd93", "" }, + { "nv!__gl_7df8d1", "" }, + { "nv!__gl_800c2310", "" }, + { "nv!__gl_80546710", "" }, + { "nv!__gl_80772310", "" }, + { "nv!__gl_808ee280", "" }, + { "nv!__gl_81131154", "" }, + { "nv!__gl_81274457", "" }, + { "nv!__gl_8292291f", "" }, + { "nv!__gl_83498426", "" }, + { "nv!__gl_84993794", "" }, + { "nv!__gl_84995585", "" }, + { "nv!__gl_84a0a0", "" }, + { "nv!__gl_852142", "" }, + { "nv!__gl_85612309", "" }, + { "nv!__gl_85612310", "" }, + { "nv!__gl_85612311", "" }, + { "nv!__gl_85612312", "" }, + { "nv!__gl_8623ff27", "" }, + { "nv!__gl_87364952", "" }, + { "nv!__gl_87f6275666", "" }, + { "nv!__gl_886748", "" }, + { "nv!__gl_89894423", "" }, + { "nv!__gl_8ad8a75", "" }, + { "nv!__gl_8ad8ad00", "" }, + { "nv!__gl_8bb815", "" }, + { "nv!__gl_8bb817", "" }, + { "nv!__gl_8bb818", "" }, + { "nv!__gl_8bb819", "" }, + { "nv!__gl_8e640cd1", "" }, + { "nv!__gl_8f34971a", "" }, + { "nv!__gl_8f773984", "" }, + { "nv!__gl_8f7a7d", "" }, + { "nv!__gl_902486209", "" }, + { "nv!__gl_90482571", "" }, + { "nv!__gl_91214835", "" }, + { "nv!__gl_912848290", "" }, + { "nv!__gl_915e56", "" }, + { "nv!__gl_92179063", "" }, + { "nv!__gl_92179064", "" }, + { "nv!__gl_92179065", "" }, + { "nv!__gl_92179066", "" }, + { "nv!__gl_92350358", "" }, + { "nv!__gl_92809063", "" }, + { "nv!__gl_92809064", "" }, + { "nv!__gl_92809065", "" }, + { "nv!__gl_92809066", "" }, + { "nv!__gl_92920143", "" }, + { "nv!__gl_93a89b12", "" }, + { "nv!__gl_93a89c0b", "" }, + { "nv!__gl_94812574", "" }, + { "nv!__gl_95282304", "" }, + { "nv!__gl_95394027", "" }, + { "nv!__gl_959b1f", "" }, + { "nv!__gl_9638af", "" }, + { "nv!__gl_96fd59", "" }, + { "nv!__gl_97f6275666", "" }, + { "nv!__gl_97f6275667", "" }, + { "nv!__gl_97f6275668", "" }, + { "nv!__gl_97f6275669", "" }, + { "nv!__gl_97f627566a", "" }, + { "nv!__gl_97f627566b", "" }, + { "nv!__gl_97f627566d", "" }, + { "nv!__gl_97f627566e", "" }, + { "nv!__gl_97f627566f", "" }, + { "nv!__gl_97f6275670", "" }, + { "nv!__gl_97f6275671", "" }, + { "nv!__gl_97f727566e", "" }, + { "nv!__gl_98480775", "" }, + { "nv!__gl_98480776", "" }, + { "nv!__gl_98480777", "" }, + { "nv!__gl_992431", "" }, + { "nv!__gl_9aa29065", "" }, + { "nv!__gl_9af32c", "" }, + { "nv!__gl_9af32d", "" }, + { "nv!__gl_9af32e", "" }, + { "nv!__gl_9c108b71", "" }, + { "nv!__gl_9f279065", "" }, + { "nv!__gl_a01bc728", "" }, + { "nv!__gl_a13b46c80", "" }, + { "nv!__gl_a22eb0", "" }, + { "nv!__gl_a2fb451e", "" }, + { "nv!__gl_a3456abe", "" }, + { "nv!__gl_a7044887", "" }, + { "nv!__gl_a7149200", "" }, + { "nv!__gl_a766215670", "" }, + { "nv!__gl_aalinegamma", "" }, + { "nv!__gl_aalinetweaks", "" }, + { "nv!__gl_ab34ee01", "" }, + { "nv!__gl_ab34ee02", "" }, + { "nv!__gl_ab34ee03", "" }, + { "nv!__gl_ac0274", "" }, + { "nv!__gl_af73c63e", "" }, + { "nv!__gl_af73c63f", "" }, + { "nv!__gl_af9927", "" }, + { "nv!__gl_afoverride", "" }, + { "nv!__gl_allocdeviceevents", "" }, + { "nv!__gl_applicationkey", "" }, + { "nv!__gl_appreturnonlybasicglsltype", "" }, + { "nv!__gl_app_softimage", "" }, + { "nv!__gl_app_supportbits2", "" }, + { "nv!__gl_assumetextureismipmappedatcreation", "" }, + { "nv!__gl_b1fb0f01", "" }, + { "nv!__gl_b3edd5", "" }, + { "nv!__gl_b40d9e03d", "" }, + { "nv!__gl_b7f6275666", "" }, + { "nv!__gl_b812c1", "" }, + { "nv!__gl_ba14ba1a", "" }, + { "nv!__gl_ba14ba1b", "" }, + { "nv!__gl_bd7559", "" }, + { "nv!__gl_bd755a", "" }, + { "nv!__gl_bd755c", "" }, + { "nv!__gl_bd755d", "" }, + { "nv!__gl_be58bb", "" }, + { "nv!__gl_be92cb", "" }, + { "nv!__gl_beefcba3", "" }, + { "nv!__gl_beefcba4", "" }, + { "nv!__gl_c023777f", "" }, + { "nv!__gl_c09dc8", "" }, + { "nv!__gl_c0d340", "" }, + { "nv!__gl_c2ff374c", "" }, + { "nv!__gl_c5e9d7a3", "" }, + { "nv!__gl_c5e9d7a4", "" }, + { "nv!__gl_c5e9d7b4", "" }, + { "nv!__gl_c618f9", "" }, + { "nv!__gl_ca345840", "" }, + { "nv!__gl_cachedisable", "" }, + { "nv!__gl_channelpriorityoverride", "" }, + { "nv!__gl_cleardatastorevidmem", "" }, + { "nv!__gl_cmdbufmemoryspaceenables", "" }, + { "nv!__gl_cmdbufminwords", "" }, + { "nv!__gl_cmdbufsizewords", "" }, + { "nv!__gl_conformantblitframebufferscissor", "" }, + { "nv!__gl_conformantincompletetextures", "" }, + { "nv!__gl_copybuffermethod", "" }, + { "nv!__gl_cubemapaniso", "" }, + { "nv!__gl_cubemapfiltering", "" }, + { "nv!__gl_d0e9a4d7", "" }, + { "nv!__gl_d13733f12", "" }, + { "nv!__gl_d1b399", "" }, + { "nv!__gl_d2983c32", "" }, + { "nv!__gl_d2983c33", "" }, + { "nv!__gl_d2e71b", "" }, + { "nv!__gl_d377dc", "" }, + { "nv!__gl_d377dd", "" }, + { "nv!__gl_d489f4", "" }, + { "nv!__gl_d4bce1", "" }, + { "nv!__gl_d518cb", "" }, + { "nv!__gl_d518cd", "" }, + { "nv!__gl_d518ce", "" }, + { "nv!__gl_d518d0", "" }, + { "nv!__gl_d518d1", "" }, + { "nv!__gl_d518d2", "" }, + { "nv!__gl_d518d3", "" }, + { "nv!__gl_d518d4", "" }, + { "nv!__gl_d518d5", "" }, + { "nv!__gl_d59eda", "" }, + { "nv!__gl_d83cbd", "" }, + { "nv!__gl_d8e777", "" }, + { "nv!__gl_debug_level", "" }, + { "nv!__gl_debug_mask", "" }, + { "nv!__gl_debug_options", "" }, + { "nv!__gl_devshmpageableallocations", "" }, + { "nv!__gl_df1f9812", "" }, + { "nv!__gl_df783c", "" }, + { "nv!__gl_diagenable", "" }, + { "nv!__gl_disallowcemask", "" }, + { "nv!__gl_disallowz16", "" }, + { "nv!__gl_dlmemoryspaceenables", "" }, + { "nv!__gl_e0bfec", "" }, + { "nv!__gl_e433456d", "" }, + { "nv!__gl_e435563f", "" }, + { "nv!__gl_e4cd9c", "" }, + { "nv!__gl_e5c972", "" }, + { "nv!__gl_e639ef", "" }, + { "nv!__gl_e802af", "" }, + { "nv!__gl_eae964", "" }, + { "nv!__gl_earlytexturehwallocation", "" }, + { "nv!__gl_eb92a3", "" }, + { "nv!__gl_ebca56", "" }, + { "nv!__gl_expert_detail_level", "" }, + { "nv!__gl_expert_output_mask", "" }, + { "nv!__gl_expert_report_mask", "" }, + { "nv!__gl_extensionstringnvarch", "" }, + { "nv!__gl_extensionstringversion", "" }, + { "nv!__gl_f00f1938", "" }, + { "nv!__gl_f10736", "" }, + { "nv!__gl_f1846870", "" }, + { "nv!__gl_f33bc370", "" }, + { "nv!__gl_f392a874", "" }, + { "nv!__gl_f49ae8", "" }, + { "nv!__gl_fa345cce", "" }, + { "nv!__gl_fa35cc4", "" }, + { "nv!__gl_faa14a", "" }, + { "nv!__gl_faf8a723", "" }, + { "nv!__gl_fastgs", "" }, + { "nv!__gl_fbf4ac45", "" }, + { "nv!__gl_fbo_blit_ignore_srgb", "" }, + { "nv!__gl_fc64c7", "" }, + { "nv!__gl_ff54ec97", "" }, + { "nv!__gl_ff54ec98", "" }, + { "nv!__gl_forceexitprocessdetach", "" }, + { "nv!__gl_forcerequestedesversion", "" }, + { "nv!__gl_glsynctovblank", "" }, + { "nv!__gl_gvitimeoutcontrol", "" }, + { "nv!__gl_hcctrl", "" }, + { "nv!__gl_hwstate_per_ctx", "" }, + { "nv!__gl_machinecachelimit", "" }, + { "nv!__gl_maxframesallowed", "" }, + { "nv!__gl_memmgrcachedalloclimit", "" }, + { "nv!__gl_memmgrcachedalloclimitratio", "" }, + { "nv!__gl_memmgrsysheapalloclimit", "" }, + { "nv!__gl_memmgrsysheapalloclimitratio", "" }, + { "nv!__gl_memmgrvidheapalloclimit", "" }, + { "nv!__gl_mosaic_clip_to_subdev", "" }, + { "nv!__gl_mosaic_clip_to_subdev_h_overlap", "" }, + { "nv!__gl_mosaic_clip_to_subdev_v_overlap", "" }, + { "nv!__gl_overlaymergeblittimerms", "" }, + { "nv!__gl_perfmon_mode", "" }, + { "nv!__gl_pixbar_mode", "" }, + { "nv!__gl_qualityenhancements", "" }, + { "nv!__gl_r27s18q28", "" }, + { "nv!__gl_r2d7c1d8", "" }, + { "nv!__gl_renderer", "" }, + { "nv!__gl_renderqualityflags", "" }, + { "nv!__gl_s3tcquality", "" }, + { "nv!__gl_shaderatomics", "" }, + { "nv!__gl_shadercacheinitsize", "" }, + { "nv!__gl_shader_disk_cache_path", "" }, + { "nv!__gl_shader_disk_cache_read_only", "" }, + { "nv!__gl_shaderobjects", "" }, + { "nv!__gl_shaderportabilitywarnings", "" }, + { "nv!__gl_shaderwarningsaserrors", "" }, + { "nv!__gl_skiptexturehostcopies", "" }, + { "nv!__glslc_debug_level", "" }, + { "nv!__glslc_debug_mask", "" }, + { "nv!__glslc_debug_options", "" }, + { "nv!__glslc_debug_filename", "" }, + { "nv!__gl_sli_dli_control", "" }, + { "nv!__gl_sparsetexture", "" }, + { "nv!__gl_spinlooptimeout", "" }, + { "nv!__gl_sync_to_vblank", "" }, + { "nv!glsynctovblank", "" }, + { "nv!__gl_sysheapreuseratio", "" }, + { "nv!__gl_sysmemtexturepromotion", "" }, + { "nv!__gl_targetflushcount", "" }, + { "nv!__gl_tearingfreeswappresent", "" }, + { "nv!__gl_texclampbehavior", "" }, + { "nv!__gl_texlodbias", "" }, + { "nv!__gl_texmemoryspaceenables", "" }, + { "nv!__gl_textureprecache", "" }, + { "nv!__gl_threadcontrol", "" }, + { "nv!__gl_threadcontrol2", "" }, + { "nv!__gl_usegvievents", "" }, + { "nv!__gl_vbomemoryspaceenables", "" }, + { "nv!__gl_vertexlimit", "" }, + { "nv!__gl_vidheapreuseratio", "" }, + { "nv!__gl_vpipe", "" }, + { "nv!__gl_vpipeformatbloatlimit", "" }, + { "nv!__gl_wglmessageboxonabort", "" }, + { "nv!__gl_writeinfolog", "" }, + { "nv!__gl_writeprogramobjectassembly", "" }, + { "nv!__gl_writeprogramobjectsource", "" }, + { "nv!__gl_xnvadapterpresent", "" }, + { "nv!__gl_yield", "" }, + { "nv!__gl_yieldfunction", "" }, + { "nv!__gl_yieldfunctionfast", "" }, + { "nv!__gl_yieldfunctionslow", "" }, + { "nv!__gl_yieldfunctionwaitfordcqueue", "" }, + { "nv!__gl_yieldfunctionwaitforframe", "" }, + { "nv!__gl_yieldfunctionwaitforgpu", "" }, + { "nv!__gl_zbctableaddhysteresis", "" }, + { "nv!gpu_debug_mode", "" }, + { "nv!gpu_stay_on", "" }, + { "nv!gpu_timeout_ms_max", "" }, + { "nv!gvitimeoutcontrol", "" }, + { "nv!hcctrl", "" }, + { "nv!hwstate_per_ctx", "" }, + { "nv!libandroid_enable_log", "" }, + { "nv!machinecachelimit", "" }, + { "nv!maxframesallowed", "" }, + { "nv!media.aac_51_output_enabled", "" }, + { "nv!memmgrcachedalloclimit", "" }, + { "nv!memmgrcachedalloclimitratio", "" }, + { "nv!memmgrsysheapalloclimit", "" }, + { "nv!memmgrsysheapalloclimitratio", "" }, + { "nv!memmgrvidheapalloclimit", "" }, + { "nv!mosaic_clip_to_subdev", "" }, + { "nv!mosaic_clip_to_subdev_h_overlap", "" }, + { "nv!mosaic_clip_to_subdev_v_overlap", "" }, + { "nv!nvblit.dump", "" }, + { "nv!nvblit.profile", "" }, + { "nv!nvblit.twod", "" }, + { "nv!nvblit.vic", "" }, + { "nv!nvddk_vic_prevent_use", "" }, + { "nv!nv_decompression", "" }, + { "nv!nvdisp_bl_ctrl", "0" }, + { "nv!nvdisp_debug_mask", "" }, + { "nv!nvdisp_enable_ts", "0" }, + { "nv!nvhdcp_timeout_ms", "12000" }, + { "nv!nvhdcp_max_retries", "5" }, + { "nv!nv_emc_dvfs_test", "" }, + { "nv!nv_emc_init_rate_hz", "" }, + { "nv!nv_gmmu_va_page_split", "" }, + { "nv!nv_gmmu_va_range", "" }, + { "nv!nvhost_debug_mask", "" }, + { "nv!nvidia.hwc.dump_config", "" }, + { "nv!nvidia.hwc.dump_layerlist", "" }, + { "nv!nvidia.hwc.dump_windows", "" }, + { "nv!nvidia.hwc.enable_disp_trans", "" }, + { "nv!nvidia.hwc.ftrace_enable", "" }, + { "nv!nvidia.hwc.hdcp_enable", "" }, + { "nv!nvidia.hwc.hidden_window_mask0", "" }, + { "nv!nvidia.hwc.hidden_window_mask1", "" }, + { "nv!nvidia.hwc.immediate_modeset", "" }, + { "nv!nvidia.hwc.imp_enable", "" }, + { "nv!nvidia.hwc.no_egl", "" }, + { "nv!nvidia.hwc.no_scratchblit", "" }, + { "nv!nvidia.hwc.no_vic", "" }, + { "nv!nvidia.hwc.null_display", "" }, + { "nv!nvidia.hwc.scan_props", "" }, + { "nv!nvidia.hwc.swap_interval", "" }, + { "nv!nvidia.hwc.war_1515812", "0" }, + { "nv!nvmap_debug_mask", "" }, + { "nv!nv_memory_profiler", "" }, + { "nv!nvnflinger_enable_log", "" }, + { "nv!nvnflinger_flip_policy", "" }, + { "nv!nvnflinger_hotplug_autoswitch", "0" }, + { "nv!nvnflinger_prefer_primary_layer", "0" }, + { "nv!nvnflinger_service_priority", "" }, + { "nv!nvnflinger_service_threads", "" }, + { "nv!nvnflinger_swap_interval", "" }, + { "nv!nvnflinger_track_perf", "" }, + { "nv!nvnflinger_virtualdisplay_policy", "60hz" }, + { "nv!nvn_no_vsync_capability", false }, + { "nv!nvn_through_opengl", "" }, + { "nv!nv_pllcx_always_on", "" }, + { "nv!nv_pllcx_safe_div", "" }, + { "nv!nvrm_gpu_channel_interleave", "" }, + { "nv!nvrm_gpu_channel_priority", "" }, + { "nv!nvrm_gpu_channel_timeslice", "" }, + { "nv!nvrm_gpu_default_device_index", "" }, + { "nv!nvrm_gpu_dummy", "" }, + { "nv!nvrm_gpu_help", "" }, + { "nv!nvrm_gpu_nvgpu_disable", "" }, + { "nv!nvrm_gpu_nvgpu_do_nfa_partial_map", "" }, + { "nv!nvrm_gpu_nvgpu_ecc_overrides", "" }, + { "nv!nvrm_gpu_nvgpu_no_as_get_va_regions", "" }, + { "nv!nvrm_gpu_nvgpu_no_channel_abort", "" }, + { "nv!nvrm_gpu_nvgpu_no_cyclestats", "" }, + { "nv!nvrm_gpu_nvgpu_no_fixed", "" }, + { "nv!nvrm_gpu_nvgpu_no_gpu_characteristics", "" }, + { "nv!nvrm_gpu_nvgpu_no_ioctl_mutex", "" }, + { "nv!nvrm_gpu_nvgpu_no_map_buffer_ex", "" }, + { "nv!nvrm_gpu_nvgpu_no_robustness", "" }, + { "nv!nvrm_gpu_nvgpu_no_sparse", "" }, + { "nv!nvrm_gpu_nvgpu_no_syncpoints", "" }, + { "nv!nvrm_gpu_nvgpu_no_tsg", "" }, + { "nv!nvrm_gpu_nvgpu_no_zbc", "" }, + { "nv!nvrm_gpu_nvgpu_no_zcull", "" }, + { "nv!nvrm_gpu_nvgpu_wrap_channels_in_tsgs", "" }, + { "nv!nvrm_gpu_prevent_use", "" }, + { "nv!nvrm_gpu_trace", "" }, + { "nv!nvsched_debug_mask", "" }, + { "nv!nvsched_force_enable", "" }, + { "nv!nvsched_force_log", "" }, + { "nv!nv_usb_plls_hw_ctrl", "" }, + { "nv!nv_winsys", "" }, + { "nv!nvwsi_dump", "" }, + { "nv!nvwsi_fill", "" }, + { "nv!ogl_", "" }, + { "nv!ogl_0356afd0", "" }, + { "nv!ogl_0356afd1", "" }, + { "nv!ogl_0356afd2", "" }, + { "nv!ogl_0356afd3", "" }, + { "nv!ogl_0x923dc0", "" }, + { "nv!ogl_0x923dc1", "" }, + { "nv!ogl_0x923dc2", "" }, + { "nv!ogl_0x923dc3", "" }, + { "nv!ogl_0x923dc4", "" }, + { "nv!ogl_0x923dd3", "" }, + { "nv!ogl_0x9abdc5", "" }, + { "nv!ogl_0x9abdc6", "" }, + { "nv!ogl_0xbd10fb", "" }, + { "nv!ogl_0xce2348", "" }, + { "nv!ogl_10261989", "" }, + { "nv!ogl_1042d483", "" }, + { "nv!ogl_10572898", "" }, + { "nv!ogl_115631", "" }, + { "nv!ogl_12950094", "" }, + { "nv!ogl_1314f311", "" }, + { "nv!ogl_1314f312", "" }, + { "nv!ogl_13279512", "" }, + { "nv!ogl_13813496", "" }, + { "nv!ogl_14507179", "" }, + { "nv!ogl_15694569", "" }, + { "nv!ogl_16936964", "" }, + { "nv!ogl_17aa230c", "" }, + { "nv!ogl_182054", "" }, + { "nv!ogl_18273275", "" }, + { "nv!ogl_18273276", "" }, + { "nv!ogl_1854d03b", "" }, + { "nv!ogl_18add00d", "" }, + { "nv!ogl_19156670", "" }, + { "nv!ogl_19286545", "" }, + { "nv!ogl_1a298e9f", "" }, + { "nv!ogl_1acf43fe", "" }, + { "nv!ogl_1bda43fe", "" }, + { "nv!ogl_1c3b92", "" }, + { "nv!ogl_21509920", "" }, + { "nv!ogl_215323457", "" }, + { "nv!ogl_2165ad", "" }, + { "nv!ogl_2165ae", "" }, + { "nv!ogl_21be9c", "" }, + { "nv!ogl_233264316", "" }, + { "nv!ogl_234557580", "" }, + { "nv!ogl_23cd0e", "" }, + { "nv!ogl_24189123", "" }, + { "nv!ogl_2443266", "" }, + { "nv!ogl_25025519", "" }, + { "nv!ogl_255e39", "" }, + { "nv!ogl_2583364", "" }, + { "nv!ogl_2888c1", "" }, + { "nv!ogl_28ca3e", "" }, + { "nv!ogl_29871243", "" }, + { "nv!ogl_2a1f64", "" }, + { "nv!ogl_2dc432", "" }, + { "nv!ogl_2de437", "" }, + { "nv!ogl_2f3bb89c", "" }, + { "nv!ogl_2fd652", "" }, + { "nv!ogl_3001ac", "" }, + { "nv!ogl_31298772", "" }, + { "nv!ogl_313233", "" }, + { "nv!ogl_31f7d603", "" }, + { "nv!ogl_320ce4", "" }, + { "nv!ogl_32153248", "" }, + { "nv!ogl_32153249", "" }, + { "nv!ogl_335bca", "" }, + { "nv!ogl_342abb", "" }, + { "nv!ogl_34dfe6", "" }, + { "nv!ogl_34dfe7", "" }, + { "nv!ogl_34dfe8", "" }, + { "nv!ogl_34dfe9", "" }, + { "nv!ogl_35201578", "" }, + { "nv!ogl_359278", "" }, + { "nv!ogl_37f53a", "" }, + { "nv!ogl_38144972", "" }, + { "nv!ogl_38542646", "" }, + { "nv!ogl_3b74c9", "" }, + { "nv!ogl_3c136f", "" }, + { "nv!ogl_3cf72823", "" }, + { "nv!ogl_3d7af029", "" }, + { "nv!ogl_3ff34782", "" }, + { "nv!ogl_4129618", "" }, + { "nv!ogl_4189fac3", "" }, + { "nv!ogl_420bd4", "" }, + { "nv!ogl_42a699", "" }, + { "nv!ogl_441369", "" }, + { "nv!ogl_4458713e", "" }, + { "nv!ogl_4554b6", "" }, + { "nv!ogl_457425", "" }, + { "nv!ogl_4603b207", "" }, + { "nv!ogl_46574957", "" }, + { "nv!ogl_46574958", "" }, + { "nv!ogl_46813529", "" }, + { "nv!ogl_46f1e13d", "" }, + { "nv!ogl_47534c43", "" }, + { "nv!ogl_48550336", "" }, + { "nv!ogl_48576893", "" }, + { "nv!ogl_48576894", "" }, + { "nv!ogl_4889ac02", "" }, + { "nv!ogl_49005740", "" }, + { "nv!ogl_49867584", "" }, + { "nv!ogl_49960973", "" }, + { "nv!ogl_4a5341", "" }, + { "nv!ogl_4f4e48", "" }, + { "nv!ogl_4f8a0a", "" }, + { "nv!ogl_50299698", "" }, + { "nv!ogl_50299699", "" }, + { "nv!ogl_50361291", "" }, + { "nv!ogl_5242ae", "" }, + { "nv!ogl_53d30c", "" }, + { "nv!ogl_56347a", "" }, + { "nv!ogl_563a95f1", "" }, + { "nv!ogl_573823", "" }, + { "nv!ogl_58027529", "" }, + { "nv!ogl_5d2d63", "" }, + { "nv!ogl_5f7e3b", "" }, + { "nv!ogl_60461793", "" }, + { "nv!ogl_60d355", "" }, + { "nv!ogl_616627aa", "" }, + { "nv!ogl_62317182", "" }, + { "nv!ogl_6253fa2e", "" }, + { "nv!ogl_64100768", "" }, + { "nv!ogl_64100769", "" }, + { "nv!ogl_64100770", "" }, + { "nv!ogl_647395", "" }, + { "nv!ogl_66543234", "" }, + { "nv!ogl_67674763", "" }, + { "nv!ogl_67739784", "" }, + { "nv!ogl_68fb9c", "" }, + { "nv!ogl_69801276", "" }, + { "nv!ogl_6af9fa2f", "" }, + { "nv!ogl_6af9fa3f", "" }, + { "nv!ogl_6af9fa4f", "" }, + { "nv!ogl_6bd8c7", "" }, + { "nv!ogl_6c7691", "" }, + { "nv!ogl_6d4296ce", "" }, + { "nv!ogl_6dd7e7", "" }, + { "nv!ogl_6dd7e8", "" }, + { "nv!ogl_6fe11ec1", "" }, + { "nv!ogl_716511763", "" }, + { "nv!ogl_72504593", "" }, + { "nv!ogl_73304097", "" }, + { "nv!ogl_73314098", "" }, + { "nv!ogl_74095213", "" }, + { "nv!ogl_74095213a", "" }, + { "nv!ogl_74095213b", "" }, + { "nv!ogl_74095214", "" }, + { "nv!ogl_748f9649", "" }, + { "nv!ogl_75494732", "" }, + { "nv!ogl_78452832", "" }, + { "nv!ogl_784561", "" }, + { "nv!ogl_78e16b9c", "" }, + { "nv!ogl_79251225", "" }, + { "nv!ogl_7c128b", "" }, + { "nv!ogl_7ccd93", "" }, + { "nv!ogl_7df8d1", "" }, + { "nv!ogl_800c2310", "" }, + { "nv!ogl_80546710", "" }, + { "nv!ogl_80772310", "" }, + { "nv!ogl_808ee280", "" }, + { "nv!ogl_81131154", "" }, + { "nv!ogl_81274457", "" }, + { "nv!ogl_8292291f", "" }, + { "nv!ogl_83498426", "" }, + { "nv!ogl_84993794", "" }, + { "nv!ogl_84995585", "" }, + { "nv!ogl_84a0a0", "" }, + { "nv!ogl_852142", "" }, + { "nv!ogl_85612309", "" }, + { "nv!ogl_85612310", "" }, + { "nv!ogl_85612311", "" }, + { "nv!ogl_85612312", "" }, + { "nv!ogl_8623ff27", "" }, + { "nv!ogl_87364952", "" }, + { "nv!ogl_87f6275666", "" }, + { "nv!ogl_886748", "" }, + { "nv!ogl_89894423", "" }, + { "nv!ogl_8ad8a75", "" }, + { "nv!ogl_8ad8ad00", "" }, + { "nv!ogl_8bb815", "" }, + { "nv!ogl_8bb817", "" }, + { "nv!ogl_8bb818", "" }, + { "nv!ogl_8bb819", "" }, + { "nv!ogl_8e640cd1", "" }, + { "nv!ogl_8f34971a", "" }, + { "nv!ogl_8f773984", "" }, + { "nv!ogl_8f7a7d", "" }, + { "nv!ogl_902486209", "" }, + { "nv!ogl_90482571", "" }, + { "nv!ogl_91214835", "" }, + { "nv!ogl_912848290", "" }, + { "nv!ogl_915e56", "" }, + { "nv!ogl_92179063", "" }, + { "nv!ogl_92179064", "" }, + { "nv!ogl_92179065", "" }, + { "nv!ogl_92179066", "" }, + { "nv!ogl_92350358", "" }, + { "nv!ogl_92809063", "" }, + { "nv!ogl_92809064", "" }, + { "nv!ogl_92809065", "" }, + { "nv!ogl_92809066", "" }, + { "nv!ogl_92920143", "" }, + { "nv!ogl_93a89b12", "" }, + { "nv!ogl_93a89c0b", "" }, + { "nv!ogl_94812574", "" }, + { "nv!ogl_95282304", "" }, + { "nv!ogl_95394027", "" }, + { "nv!ogl_959b1f", "" }, + { "nv!ogl_9638af", "" }, + { "nv!ogl_96fd59", "" }, + { "nv!ogl_97f6275666", "" }, + { "nv!ogl_97f6275667", "" }, + { "nv!ogl_97f6275668", "" }, + { "nv!ogl_97f6275669", "" }, + { "nv!ogl_97f627566a", "" }, + { "nv!ogl_97f627566b", "" }, + { "nv!ogl_97f627566d", "" }, + { "nv!ogl_97f627566e", "" }, + { "nv!ogl_97f627566f", "" }, + { "nv!ogl_97f6275670", "" }, + { "nv!ogl_97f6275671", "" }, + { "nv!ogl_97f727566e", "" }, + { "nv!ogl_98480775", "" }, + { "nv!ogl_98480776", "" }, + { "nv!ogl_98480777", "" }, + { "nv!ogl_992431", "" }, + { "nv!ogl_9aa29065", "" }, + { "nv!ogl_9af32c", "" }, + { "nv!ogl_9af32d", "" }, + { "nv!ogl_9af32e", "" }, + { "nv!ogl_9c108b71", "" }, + { "nv!ogl_9f279065", "" }, + { "nv!ogl_a01bc728", "" }, + { "nv!ogl_a13b46c80", "" }, + { "nv!ogl_a22eb0", "" }, + { "nv!ogl_a2fb451e", "" }, + { "nv!ogl_a3456abe", "" }, + { "nv!ogl_a7044887", "" }, + { "nv!ogl_a7149200", "" }, + { "nv!ogl_a766215670", "" }, + { "nv!ogl_aalinegamma", "" }, + { "nv!ogl_aalinetweaks", "" }, + { "nv!ogl_ab34ee01", "" }, + { "nv!ogl_ab34ee02", "" }, + { "nv!ogl_ab34ee03", "" }, + { "nv!ogl_ac0274", "" }, + { "nv!ogl_af73c63e", "" }, + { "nv!ogl_af73c63f", "" }, + { "nv!ogl_af9927", "" }, + { "nv!ogl_afoverride", "" }, + { "nv!ogl_allocdeviceevents", "" }, + { "nv!ogl_applicationkey", "" }, + { "nv!ogl_appreturnonlybasicglsltype", "" }, + { "nv!ogl_app_softimage", "" }, + { "nv!ogl_app_supportbits2", "" }, + { "nv!ogl_assumetextureismipmappedatcreation", "" }, + { "nv!ogl_b1fb0f01", "" }, + { "nv!ogl_b3edd5", "" }, + { "nv!ogl_b40d9e03d", "" }, + { "nv!ogl_b7f6275666", "" }, + { "nv!ogl_b812c1", "" }, + { "nv!ogl_ba14ba1a", "" }, + { "nv!ogl_ba14ba1b", "" }, + { "nv!ogl_bd7559", "" }, + { "nv!ogl_bd755a", "" }, + { "nv!ogl_bd755c", "" }, + { "nv!ogl_bd755d", "" }, + { "nv!ogl_be58bb", "" }, + { "nv!ogl_be92cb", "" }, + { "nv!ogl_beefcba3", "" }, + { "nv!ogl_beefcba4", "" }, + { "nv!ogl_c023777f", "" }, + { "nv!ogl_c09dc8", "" }, + { "nv!ogl_c0d340", "" }, + { "nv!ogl_c2ff374c", "" }, + { "nv!ogl_c5e9d7a3", "" }, + { "nv!ogl_c5e9d7a4", "" }, + { "nv!ogl_c5e9d7b4", "" }, + { "nv!ogl_c618f9", "" }, + { "nv!ogl_ca345840", "" }, + { "nv!ogl_cachedisable", "" }, + { "nv!ogl_channelpriorityoverride", "" }, + { "nv!ogl_cleardatastorevidmem", "" }, + { "nv!ogl_cmdbufmemoryspaceenables", "" }, + { "nv!ogl_cmdbufminwords", "" }, + { "nv!ogl_cmdbufsizewords", "" }, + { "nv!ogl_conformantblitframebufferscissor", "" }, + { "nv!ogl_conformantincompletetextures", "" }, + { "nv!ogl_copybuffermethod", "" }, + { "nv!ogl_cubemapaniso", "" }, + { "nv!ogl_cubemapfiltering", "" }, + { "nv!ogl_d0e9a4d7", "" }, + { "nv!ogl_d13733f12", "" }, + { "nv!ogl_d1b399", "" }, + { "nv!ogl_d2983c32", "" }, + { "nv!ogl_d2983c33", "" }, + { "nv!ogl_d2e71b", "" }, + { "nv!ogl_d377dc", "" }, + { "nv!ogl_d377dd", "" }, + { "nv!ogl_d489f4", "" }, + { "nv!ogl_d4bce1", "" }, + { "nv!ogl_d518cb", "" }, + { "nv!ogl_d518cd", "" }, + { "nv!ogl_d518ce", "" }, + { "nv!ogl_d518d0", "" }, + { "nv!ogl_d518d1", "" }, + { "nv!ogl_d518d2", "" }, + { "nv!ogl_d518d3", "" }, + { "nv!ogl_d518d4", "" }, + { "nv!ogl_d518d5", "" }, + { "nv!ogl_d59eda", "" }, + { "nv!ogl_d83cbd", "" }, + { "nv!ogl_d8e777", "" }, + { "nv!ogl_debug_level", "" }, + { "nv!ogl_debug_mask", "" }, + { "nv!ogl_debug_options", "" }, + { "nv!ogl_devshmpageableallocations", "" }, + { "nv!ogl_df1f9812", "" }, + { "nv!ogl_df783c", "" }, + { "nv!ogl_diagenable", "" }, + { "nv!ogl_disallowcemask", "" }, + { "nv!ogl_disallowz16", "" }, + { "nv!ogl_dlmemoryspaceenables", "" }, + { "nv!ogl_e0bfec", "" }, + { "nv!ogl_e433456d", "" }, + { "nv!ogl_e435563f", "" }, + { "nv!ogl_e4cd9c", "" }, + { "nv!ogl_e5c972", "" }, + { "nv!ogl_e639ef", "" }, + { "nv!ogl_e802af", "" }, + { "nv!ogl_eae964", "" }, + { "nv!ogl_earlytexturehwallocation", "" }, + { "nv!ogl_eb92a3", "" }, + { "nv!ogl_ebca56", "" }, + { "nv!ogl_expert_detail_level", "" }, + { "nv!ogl_expert_output_mask", "" }, + { "nv!ogl_expert_report_mask", "" }, + { "nv!ogl_extensionstringnvarch", "" }, + { "nv!ogl_extensionstringversion", "" }, + { "nv!ogl_f00f1938", "" }, + { "nv!ogl_f10736", "" }, + { "nv!ogl_f1846870", "" }, + { "nv!ogl_f33bc370", "" }, + { "nv!ogl_f392a874", "" }, + { "nv!ogl_f49ae8", "" }, + { "nv!ogl_fa345cce", "" }, + { "nv!ogl_fa35cc4", "" }, + { "nv!ogl_faa14a", "" }, + { "nv!ogl_faf8a723", "" }, + { "nv!ogl_fastgs", "" }, + { "nv!ogl_fbf4ac45", "" }, + { "nv!ogl_fbo_blit_ignore_srgb", "" }, + { "nv!ogl_fc64c7", "" }, + { "nv!ogl_ff54ec97", "" }, + { "nv!ogl_ff54ec98", "" }, + { "nv!ogl_forceexitprocessdetach", "" }, + { "nv!ogl_forcerequestedesversion", "" }, + { "nv!ogl_glsynctovblank", "" }, + { "nv!ogl_gvitimeoutcontrol", "" }, + { "nv!ogl_hcctrl", "" }, + { "nv!ogl_hwstate_per_ctx", "" }, + { "nv!ogl_machinecachelimit", "" }, + { "nv!ogl_maxframesallowed", "" }, + { "nv!ogl_memmgrcachedalloclimit", "" }, + { "nv!ogl_memmgrcachedalloclimitratio", "" }, + { "nv!ogl_memmgrsysheapalloclimit", "" }, + { "nv!ogl_memmgrsysheapalloclimitratio", "" }, + { "nv!ogl_memmgrvidheapalloclimit", "" }, + { "nv!ogl_mosaic_clip_to_subdev", "" }, + { "nv!ogl_mosaic_clip_to_subdev_h_overlap", "" }, + { "nv!ogl_mosaic_clip_to_subdev_v_overlap", "" }, + { "nv!ogl_overlaymergeblittimerms", "" }, + { "nv!ogl_perfmon_mode", "" }, + { "nv!ogl_pixbar_mode", "" }, + { "nv!ogl_qualityenhancements", "" }, + { "nv!ogl_r27s18q28", "" }, + { "nv!ogl_r2d7c1d8", "" }, + { "nv!ogl_renderer", "" }, + { "nv!ogl_renderqualityflags", "" }, + { "nv!ogl_s3tcquality", "" }, + { "nv!ogl_shaderatomics", "" }, + { "nv!ogl_shadercacheinitsize", "" }, + { "nv!ogl_shader_disk_cache_path", "" }, + { "nv!ogl_shader_disk_cache_read_only", "" }, + { "nv!ogl_shaderobjects", "" }, + { "nv!ogl_shaderportabilitywarnings", "" }, + { "nv!ogl_shaderwarningsaserrors", "" }, + { "nv!ogl_skiptexturehostcopies", "" }, + { "nv!ogl_sli_dli_control", "" }, + { "nv!ogl_sparsetexture", "" }, + { "nv!ogl_spinlooptimeout", "" }, + { "nv!ogl_sync_to_vblank", "" }, + { "nv!ogl_sysheapreuseratio", "" }, + { "nv!ogl_sysmemtexturepromotion", "" }, + { "nv!ogl_targetflushcount", "" }, + { "nv!ogl_tearingfreeswappresent", "" }, + { "nv!ogl_texclampbehavior", "" }, + { "nv!ogl_texlodbias", "" }, + { "nv!ogl_texmemoryspaceenables", "" }, + { "nv!ogl_textureprecache", "" }, + { "nv!ogl_threadcontrol", "" }, + { "nv!ogl_threadcontrol2", "" }, + { "nv!ogl_usegvievents", "" }, + { "nv!ogl_vbomemoryspaceenables", "" }, + { "nv!ogl_vertexlimit", "" }, + { "nv!ogl_vidheapreuseratio", "" }, + { "nv!ogl_vpipe", "" }, + { "nv!ogl_vpipeformatbloatlimit", "" }, + { "nv!ogl_wglmessageboxonabort", "" }, + { "nv!ogl_writeinfolog", "" }, + { "nv!ogl_writeprogramobjectassembly", "" }, + { "nv!ogl_writeprogramobjectsource", "" }, + { "nv!ogl_xnvadapterpresent", "" }, + { "nv!ogl_yield", "" }, + { "nv!ogl_yieldfunction", "" }, + { "nv!ogl_yieldfunctionfast", "" }, + { "nv!ogl_yieldfunctionslow", "" }, + { "nv!ogl_yieldfunctionwaitfordcqueue", "" }, + { "nv!ogl_yieldfunctionwaitforframe", "" }, + { "nv!ogl_yieldfunctionwaitforgpu", "" }, + { "nv!ogl_zbctableaddhysteresis", "" }, + { "nv!overlaymergeblittimerms", "" }, + { "nv!perfmon_mode", "" }, + { "nv!persist.sys.display.resolution", "" }, + { "nv!persist.tegra.composite.fallb", "" }, + { "nv!persist.tegra.composite.policy", "" }, + { "nv!persist.tegra.composite.range", "" }, + { "nv!persist.tegra.compositor", "" }, + { "nv!persist.tegra.compositor.virt", "" }, + { "nv!persist.tegra.compression", "" }, + { "nv!persist.tegra.cursor.enable", "" }, + { "nv!persist.tegra.didim.enable", "" }, + { "nv!persist.tegra.didim.normal", "" }, + { "nv!persist.tegra.didim.video", "" }, + { "nv!persist.tegra.disp.heads", "" }, + { "nv!persist.tegra.gamma_correction", "" }, + { "nv!persist.tegra.gpu_mapping_cache", "" }, + { "nv!persist.tegra.grlayout", "" }, + { "nv!persist.tegra.hdmi.2020.10", "" }, + { "nv!persist.tegra.hdmi.2020.fake", "" }, + { "nv!persist.tegra.hdmi.2020.force", "" }, + { "nv!persist.tegra.hdmi.autorotate", "" }, + { "nv!persist.tegra.hdmi.hdr.fake", "" }, + { "nv!persist.tegra.hdmi.ignore_ratio", "" }, + { "nv!persist.tegra.hdmi.limit.clock", "" }, + { "nv!persist.tegra.hdmi.only_16_9", "" }, + { "nv!persist.tegra.hdmi.range", "" }, + { "nv!persist.tegra.hdmi.resolution", "" }, + { "nv!persist.tegra.hdmi.underscan", "" }, + { "nv!persist.tegra.hdmi.yuv.422", "" }, + { "nv!persist.tegra.hdmi.yuv.444", "" }, + { "nv!persist.tegra.hdmi.yuv.enable", "" }, + { "nv!persist.tegra.hdmi.yuv.force", "" }, + { "nv!persist.tegra.hwc.nvdc", "" }, + { "nv!persist.tegra.idle.minimum_fps", "" }, + { "nv!persist.tegra.panel.rotation", "" }, + { "nv!persist.tegra.scan_props", "" }, + { "nv!persist.tegra.stb.mode", "" }, + { "nv!persist.tegra.zbc_override", "" }, + { "nv!pixbar_mode", "" }, + { "nv!qualityenhancements", "" }, + { "nv!r27s18q28", "" }, + { "nv!r2d7c1d8", "" }, + { "nv!renderer", "" }, + { "nv!renderqualityflags", "" }, + { "nv!rmos_debug_mask", "" }, + { "nv!rmos_set_production_mode", "" }, + { "nv!s3tcquality", "" }, + { "nv!shaderatomics", "" }, + { "nv!shadercacheinitsize", "" }, + { "nv!shader_disk_cache_path", "" }, + { "nv!shader_disk_cache_read_only", "" }, + { "nv!shaderobjects", "" }, + { "nv!shaderportabilitywarnings", "" }, + { "nv!shaderwarningsaserrors", "" }, + { "nv!skiptexturehostcopies", "" }, + { "nv!sli_dli_control", "" }, + { "nv!sparsetexture", "" }, + { "nv!spinlooptimeout", "" }, + { "nv!sync_to_vblank", "" }, + { "nv!sysheapreuseratio", "" }, + { "nv!sysmemtexturepromotion", "" }, + { "nv!targetflushcount", "" }, + { "nv!tearingfreeswappresent", "" }, + { "nv!tegra.refresh", "" }, + { "nv!texclampbehavior", "" }, + { "nv!texlodbias", "" }, + { "nv!texmemoryspaceenables", "" }, + { "nv!textureprecache", "" }, + { "nv!threadcontrol", "" }, + { "nv!threadcontrol2", "" }, + { "nv!tvmr.avp.logs", "" }, + { "nv!tvmr.buffer.logs", "" }, + { "nv!tvmr.dec.prof", "" }, + { "nv!tvmr.deint.logs", "" }, + { "nv!tvmr.dfs.logs", "" }, + { "nv!tvmr.ffprof.logs", "" }, + { "nv!tvmr.game.stream", "" }, + { "nv!tvmr.general.logs", "" }, + { "nv!tvmr.input.dump", "" }, + { "nv!tvmr.seeking.logs", "" }, + { "nv!tvmr.ts_pulldown", "" }, + { "nv!usegvievents", "" }, + { "nv!vbomemoryspaceenables", "" }, + { "nv!vcc_debug_ip", "" }, + { "nv!vcc_verbose_level", "" }, + { "nv!vertexlimit", "" }, + { "nv!viccomposer.filter", "" }, + { "nv!videostats-enable", "" }, + { "nv!vidheapreuseratio", "" }, + { "nv!vpipe", "" }, + { "nv!vpipeformatbloatlimit", "" }, + { "nv!wglmessageboxonabort", "" }, + { "nv!writeinfolog", "" }, + { "nv!writeprogramobjectassembly", "" }, + { "nv!writeprogramobjectsource", "" }, + { "nv!xnvadapterpresent", "" }, + { "nv!yield", "" }, + { "nv!yieldfunction", "" }, + { "nv!yieldfunctionfast", "" }, + { "nv!yieldfunctionslow", "" }, + { "nv!yieldfunctionwaitfordcqueue", "" }, + { "nv!yieldfunctionwaitforframe", "" }, + { "nv!yieldfunctionwaitforgpu", "" }, + { "nv!zbctableaddhysteresis", "" }, + { "pcm!enable", true }, + { "pctl!intermittent_task_interval_seconds", 21600 }, + { "prepo!devmenu_prepo_page_view", false }, + { "prepo!background_processing", true }, + { "prepo!transmission_interval_min", 10 }, + { "prepo!transmission_retry_interval", 3600 }, + { "psm!evaluation_log_enabled", false }, + { "snap_shot_dump!auto_dump", false }, + { "snap_shot_dump!output_dir", "%USERPROFILE%/Documents/Nintendo/NXDMP" }, + { "snap_shot_dump!full_dump", false }, + { "systemconfig!field_testing", false }, + { "systemconfig!exhivision", false }, + { "systempowerstate!always_reboot", false }, + { "systempowerstate!power_state_message_emulation_trigger_time", 0 }, + { "systempowerstate!power_state_message_to_emulate", 0 }, + { "target_manager!device_name", "" }, + { "vulnerability!needs_update_vulnerability_policy", 0 }, + { "apm!performance_mode_policy", "auto" }, + { "apm!sdev_throttling_enabled", true }, + { "apm!sdev_throttling_additional_delay_us", 16000 }, + { "apm!battery_draining_enabled", false }, + { "apm!sdev_cpu_overclock_enabled", false }, + { "bcat!production_mode", true }, + { "bpc!enable_quasi_off", true }, + { "bsp0!usb", "UDS" }, + { "bsp0!tm_transport", "USB" }, + { "bluetooth_debug!skip_boot", false }, + { "contents_delivery!enable_debug_api", false }, + { "eupld!upload_enabled", true }, + { "fatal!transition_to_fatal", true }, + { "fatal!show_extra_info", false }, + { "gpu_core_dump!auto_dump", false }, + { "hid_debug!enables_debugpad", false }, + { "hid_debug!manages_devices", true }, + { "hid_debug!emulate_future_device", false }, + { "hid_debug!emulate_firmware_update_failure", false }, + { "hid_debug!emulate_mcu_hardware_error", false }, + { "hid_debug!firmware_update_failure_emulation_mode", 0 }, + { "jit_debug!enable_jit_debug", false }, + { "npns!background_processing", true }, + { "npns!logmanager_redirection", true }, + { "npns!sleep_processing_timeout", 30 }, + { "npns!sleep_periodic_interval", 10800 }, + { "npns!sleep_max_try_count", 5 }, + { "npns!test_mode", false }, + { "ns.applet!overlay_applet_id", "0x010000000000100c" }, + { "ns.applet!system_applet_id", "0x0100000000001000" }, + { "ns.applet!shop_applet_id", "0x010000000000100b" }, + { "ns.autoboot!enabled", true }, + { "ns.pseudodeviceid!reset_pseudo_device_id", false }, + { "nsd!environment_identifier", "lp1" }, + { "nsd!test_mode", false }, + { "ntc!is_autonomic_correction_enabled", true }, + { "ntc!autonomic_correction_interval_seconds", 432000 }, + { "ntc!autonomic_correction_failed_retry_interval_seconds", 1800 }, + { "ntc!autonomic_correction_immediate_try_count_max", 4 }, + { "ntc!autonomic_correction_immediate_try_interval_milliseconds", 5000 }, + { "nv!nv_graphics_firmware_memory_margin", false }, + { "omm!operation_mode_policy", "auto" }, + { "omm!sleep_fade_in_ms", 50 }, + { "omm!sleep_fade_out_ms", 100 }, + { "omm!charging_sign_ms", 3000 }, + { "omm!low_battery_sign_ms", 3000 }, + { "omm!sign_fade_in_ms", 0 }, + { "omm!sign_fade_out_ms", 400 }, + { "omm!sign_wait_layer_visible_ms", 100 }, + { "omm!startup_fade_in_ms", 200 }, + { "omm!startup_fade_out_ms", 400 }, + { "omm!backlight_off_ms_on_handheld_switch", 150 }, + { "omm!sleep_on_ac_ok_boot", true }, + { "pdm!save_playlog", true }, + { "productinfo!product_name", "Nintendo Switch" }, + { "productinfo!cec_osd_name", "NintendoSwitch" }, + { "ro!ease_nro_restriction", false }, + { "settings_debug!is_debug_mode_enabled", false }, + { "systemreport!enabled", true }, + { "systemsleep!enter_sleep", true }, + { "systemsleep!enter_sc7", true }, + { "systemsleep!keep_vdd_core", true }, + { "systemsleep!disable_tma_sleep", false }, + { "systemsleep!disable_auto_sleep", false }, + { "systemsleep!override_auto_sleep_time", 0 }, + { "systemsleep!sleep_pending_time_ms", 15000 }, + { "systemsleep!hush_time_after_brief_power_button_press_ms", 1000 }, + { "systemsleep!transition_timeout_sec", 60 }, + { "systemsleep!dummy_event_auto_wake", false }, + { "systemupdate!debug_id", "0x0000000000000000" }, + { "systemupdate!debug_version", 0 }, + { "systemupdate!bgnup_retry_seconds", 60 }, + { "systemupdate!enable_background_download_stress_testing", false }, + { "systemupdate!debug_id_for_content_delivery", "0x0000000000000000" }, + { "systemupdate!debug_version_for_content_delivery", 0 }, + { "systemupdate!assumed_system_applet_version", 0 }, + { "tc!iir_filter_gain_soc", 100 }, + { "tc!iir_filter_gain_pcb", 100 }, + { "tc!tskin_soc_coefficients_handheld", "[5464, 174190]" }, + { "tc!tskin_soc_coefficients_console", "[6182, 112480]" }, + { "tc!tskin_pcb_coefficients_handheld", "[5464, 174190]" }, + { "tc!tskin_pcb_coefficients_console", "[6182, 112480]" }, + { "tc!tskin_select", "both" }, + { "tc!tskin_rate_table_handheld", "[[-1000000, 40000, 0, 0], [36000, 43000, 51, 51], [43000, 48000, 51, 102], [48000, 53000, 102, 153], [53000, 1000000, 153, 153], [48000, 1000000, 153, 153]]" }, + { "tc!tskin_rate_table_console", "[[-1000000, 43000, 51, 51], [43000, 53000, 51, 153], [53000, 58000, 153, 255], [58000, 1000000, 255, 255]]" }, + { "tc!rate_select", "both" }, + { "tc!log_enabled", false }, + { "tc!sleep_enabled", true }, + { "time!standard_steady_clock_test_offset_minutes", 0 }, + { "time!standard_steady_clock_rtc_update_interval_minutes", 5 }, + { "time!standard_network_clock_sufficient_accuracy_minutes", 43200 }, + { "usb!usb30_force_enabled", false }, + { "wlan_debug!skip_wlan_boot", false }, + }; + } +} diff --git a/Ryujinx.HLE/HOS/Services/Sfdnsres/IResolver.cs b/Ryujinx.HLE/HOS/Services/Sfdnsres/IResolver.cs new file mode 100644 index 00000000..26dbedf4 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Sfdnsres/IResolver.cs @@ -0,0 +1,20 @@ +using Ryujinx.HLE.HOS.Ipc; +using System.Collections.Generic; + +namespace Ryujinx.HLE.HOS.Services.Sfdnsres +{ + class IResolver : IpcService + { + private Dictionary m_Commands; + + public override IReadOnlyDictionary Commands => m_Commands; + + public IResolver() + { + m_Commands = new Dictionary() + { + //... + }; + } + } +} diff --git a/Ryujinx.HLE/HOS/Services/Sm/IUserInterface.cs b/Ryujinx.HLE/HOS/Services/Sm/IUserInterface.cs new file mode 100644 index 00000000..efa64ee7 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Sm/IUserInterface.cs @@ -0,0 +1,69 @@ +using Ryujinx.HLE.HOS.Ipc; +using Ryujinx.HLE.HOS.Kernel; +using System.Collections.Generic; + +namespace Ryujinx.HLE.HOS.Services.Sm +{ + class IUserInterface : IpcService + { + private Dictionary m_Commands; + + public override IReadOnlyDictionary Commands => m_Commands; + + private bool IsInitialized; + + public IUserInterface() + { + m_Commands = new Dictionary() + { + { 0, Initialize }, + { 1, GetService } + }; + } + + private const int SmNotInitialized = 0x415; + + public long Initialize(ServiceCtx Context) + { + IsInitialized = true; + + return 0; + } + + public long GetService(ServiceCtx Context) + { + //Only for kernel version > 3.0.0. + if (!IsInitialized) + { + //return SmNotInitialized; + } + + string Name = string.Empty; + + for (int Index = 0; Index < 8 && + Context.RequestData.BaseStream.Position < + Context.RequestData.BaseStream.Length; Index++) + { + byte Chr = Context.RequestData.ReadByte(); + + if (Chr >= 0x20 && Chr < 0x7f) + { + Name += (char)Chr; + } + } + + if (Name == string.Empty) + { + return 0; + } + + KSession Session = new KSession(ServiceFactory.MakeService(Name), Name); + + int Handle = Context.Process.HandleTable.OpenHandle(Session); + + Context.Response.HandleDesc = IpcHandleDesc.MakeMove(Handle); + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Spl/IRandomInterface.cs b/Ryujinx.HLE/HOS/Services/Spl/IRandomInterface.cs new file mode 100644 index 00000000..6391d981 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Spl/IRandomInterface.cs @@ -0,0 +1,50 @@ +using Ryujinx.HLE.HOS.Ipc; +using System; +using System.Collections.Generic; +using System.Security.Cryptography; + +namespace Ryujinx.HLE.HOS.Services.Spl +{ + class IRandomInterface : IpcService, IDisposable + { + private Dictionary m_Commands; + + public override IReadOnlyDictionary Commands => m_Commands; + + private RNGCryptoServiceProvider Rng; + + public IRandomInterface() + { + m_Commands = new Dictionary() + { + { 0, GetRandomBytes } + }; + + Rng = new RNGCryptoServiceProvider(); + } + + public long GetRandomBytes(ServiceCtx Context) + { + byte[] RandomBytes = new byte[Context.Request.ReceiveBuff[0].Size]; + + Rng.GetBytes(RandomBytes); + + Context.Memory.WriteBytes(Context.Request.ReceiveBuff[0].Position, RandomBytes); + + return 0; + } + + public void Dispose() + { + Dispose(true); + } + + protected virtual void Dispose(bool Disposing) + { + if (Disposing) + { + Rng.Dispose(); + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Ssl/ISslService.cs b/Ryujinx.HLE/HOS/Services/Ssl/ISslService.cs new file mode 100644 index 00000000..b59527f7 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Ssl/ISslService.cs @@ -0,0 +1,30 @@ +using Ryujinx.HLE.HOS.Ipc; +using Ryujinx.HLE.Logging; +using System.Collections.Generic; + +namespace Ryujinx.HLE.HOS.Services.Ssl +{ + class ISslService : IpcService + { + private Dictionary m_Commands; + + public override IReadOnlyDictionary Commands => m_Commands; + + public ISslService() + { + m_Commands = new Dictionary() + { + { 5, SetInterfaceVersion } + }; + } + + public long SetInterfaceVersion(ServiceCtx Context) + { + int Version = Context.RequestData.ReadInt32(); + + Context.Device.Log.PrintStub(LogClass.ServiceSsl, "Stubbed."); + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Time/IStaticService.cs b/Ryujinx.HLE/HOS/Services/Time/IStaticService.cs new file mode 100644 index 00000000..66f16501 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Time/IStaticService.cs @@ -0,0 +1,74 @@ +using Ryujinx.HLE.HOS.Ipc; +using System; +using System.Collections.Generic; + +namespace Ryujinx.HLE.HOS.Services.Time +{ + class IStaticService : IpcService + { + private Dictionary m_Commands; + + public override IReadOnlyDictionary Commands => m_Commands; + + private static readonly DateTime StartupDate = DateTime.UtcNow; + + public IStaticService() + { + m_Commands = new Dictionary() + { + { 0, GetStandardUserSystemClock }, + { 1, GetStandardNetworkSystemClock }, + { 2, GetStandardSteadyClock }, + { 3, GetTimeZoneService }, + { 4, GetStandardLocalSystemClock }, + { 300, CalculateMonotonicSystemClockBaseTimePoint } + }; + } + + public long GetStandardUserSystemClock(ServiceCtx Context) + { + MakeObject(Context, new ISystemClock(SystemClockType.User)); + + return 0; + } + + public long GetStandardNetworkSystemClock(ServiceCtx Context) + { + MakeObject(Context, new ISystemClock(SystemClockType.Network)); + + return 0; + } + + public long GetStandardSteadyClock(ServiceCtx Context) + { + MakeObject(Context, new ISteadyClock()); + + return 0; + } + + public long GetTimeZoneService(ServiceCtx Context) + { + MakeObject(Context, new ITimeZoneService()); + + return 0; + } + + public long GetStandardLocalSystemClock(ServiceCtx Context) + { + MakeObject(Context, new ISystemClock(SystemClockType.Local)); + + return 0; + } + + public long CalculateMonotonicSystemClockBaseTimePoint(ServiceCtx Context) + { + long TimeOffset = (long)(DateTime.UtcNow - StartupDate).TotalSeconds; + long SystemClockContextEpoch = Context.RequestData.ReadInt64(); + + Context.ResponseData.Write(TimeOffset + SystemClockContextEpoch); + + return 0; + } + + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Time/ISteadyClock.cs b/Ryujinx.HLE/HOS/Services/Time/ISteadyClock.cs new file mode 100644 index 00000000..e4020bb1 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Time/ISteadyClock.cs @@ -0,0 +1,53 @@ +using Ryujinx.HLE.HOS.Ipc; +using System; +using System.Collections.Generic; + +namespace Ryujinx.HLE.HOS.Services.Time +{ + class ISteadyClock : IpcService + { + private Dictionary m_Commands; + + public override IReadOnlyDictionary Commands => m_Commands; + + private ulong TestOffset; + + public ISteadyClock() + { + m_Commands = new Dictionary() + { + { 0, GetCurrentTimePoint }, + { 1, GetTestOffset }, + { 2, SetTestOffset } + }; + + TestOffset = 0; + } + + public long GetCurrentTimePoint(ServiceCtx Context) + { + Context.ResponseData.Write((long)(System.Diagnostics.Process.GetCurrentProcess().StartTime - DateTime.Now).TotalSeconds); + + for (int i = 0; i < 0x10; i++) + { + Context.ResponseData.Write((byte)0); + } + + return 0; + } + + public long GetTestOffset(ServiceCtx Context) + { + Context.ResponseData.Write(TestOffset); + + return 0; + } + + public long SetTestOffset(ServiceCtx Context) + { + TestOffset = Context.RequestData.ReadUInt64(); + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Time/ISystemClock.cs b/Ryujinx.HLE/HOS/Services/Time/ISystemClock.cs new file mode 100644 index 00000000..f574826a --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Time/ISystemClock.cs @@ -0,0 +1,107 @@ +using Ryujinx.HLE.HOS.Ipc; +using System; +using System.Collections.Generic; + +namespace Ryujinx.HLE.HOS.Services.Time +{ + class ISystemClock : IpcService + { + private Dictionary m_Commands; + + public override IReadOnlyDictionary Commands => m_Commands; + + private static readonly DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); + + private SystemClockType ClockType; + + private DateTime SystemClockContextEpoch; + + private long SystemClockTimePoint; + + private byte[] SystemClockContextEnding; + + private long TimeOffset; + + public ISystemClock(SystemClockType ClockType) + { + m_Commands = new Dictionary() + { + { 0, GetCurrentTime }, + { 1, SetCurrentTime }, + { 2, GetSystemClockContext }, + { 3, SetSystemClockContext } + }; + + this.ClockType = ClockType; + SystemClockContextEpoch = System.Diagnostics.Process.GetCurrentProcess().StartTime; + SystemClockContextEnding = new byte[0x10]; + TimeOffset = 0; + + if (ClockType == SystemClockType.User || + ClockType == SystemClockType.Network) + { + SystemClockContextEpoch = SystemClockContextEpoch.ToUniversalTime(); + } + + SystemClockTimePoint = (long)(SystemClockContextEpoch - Epoch).TotalSeconds; + } + + public long GetCurrentTime(ServiceCtx Context) + { + DateTime CurrentTime = DateTime.Now; + + if (ClockType == SystemClockType.User || + ClockType == SystemClockType.Network) + { + CurrentTime = CurrentTime.ToUniversalTime(); + } + + Context.ResponseData.Write((long)((CurrentTime - Epoch).TotalSeconds) + TimeOffset); + + return 0; + } + + public long SetCurrentTime(ServiceCtx Context) + { + DateTime CurrentTime = DateTime.Now; + + if (ClockType == SystemClockType.User || + ClockType == SystemClockType.Network) + { + CurrentTime = CurrentTime.ToUniversalTime(); + } + + TimeOffset = (Context.RequestData.ReadInt64() - (long)(CurrentTime - Epoch).TotalSeconds); + + return 0; + } + + public long GetSystemClockContext(ServiceCtx Context) + { + Context.ResponseData.Write((long)(SystemClockContextEpoch - Epoch).TotalSeconds); + + // The point in time, TODO: is there a link between epoch and this? + Context.ResponseData.Write(SystemClockTimePoint); + + // This seems to be some kind of identifier? + for (int i = 0; i < 0x10; i++) + { + Context.ResponseData.Write(SystemClockContextEnding[i]); + } + + return 0; + } + + public long SetSystemClockContext(ServiceCtx Context) + { + long NewSystemClockEpoch = Context.RequestData.ReadInt64(); + long NewSystemClockTimePoint = Context.RequestData.ReadInt64(); + + SystemClockContextEpoch = Epoch.Add(TimeSpan.FromSeconds(NewSystemClockEpoch)); + SystemClockTimePoint = NewSystemClockTimePoint; + SystemClockContextEnding = Context.RequestData.ReadBytes(0x10); + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Time/ITimeZoneService.cs b/Ryujinx.HLE/HOS/Services/Time/ITimeZoneService.cs new file mode 100644 index 00000000..6df28659 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Time/ITimeZoneService.cs @@ -0,0 +1,280 @@ +using Ryujinx.HLE.HOS.Ipc; +using Ryujinx.HLE.Logging; +using System; +using System.Collections.Generic; +using System.Text; + +using static Ryujinx.HLE.HOS.ErrorCode; + +namespace Ryujinx.HLE.HOS.Services.Time +{ + class ITimeZoneService : IpcService + { + private Dictionary m_Commands; + + public override IReadOnlyDictionary Commands => m_Commands; + + private static readonly DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); + + private TimeZoneInfo TimeZone = TimeZoneInfo.Local; + + public ITimeZoneService() + { + m_Commands = new Dictionary() + { + { 0, GetDeviceLocationName }, + { 1, SetDeviceLocationName }, + { 2, GetTotalLocationNameCount }, + { 3, LoadLocationNameList }, + { 4, LoadTimeZoneRule }, + { 100, ToCalendarTime }, + { 101, ToCalendarTimeWithMyRule }, + { 201, ToPosixTime }, + { 202, ToPosixTimeWithMyRule } + }; + } + + public long GetDeviceLocationName(ServiceCtx Context) + { + char[] TzName = TimeZone.Id.ToCharArray(); + + Context.ResponseData.Write(TzName); + + int Padding = 0x24 - TzName.Length; + + for (int Index = 0; Index < Padding; Index++) + { + Context.ResponseData.Write((byte)0); + } + + return 0; + } + + public long SetDeviceLocationName(ServiceCtx Context) + { + byte[] LocationName = Context.RequestData.ReadBytes(0x24); + + string TzID = Encoding.ASCII.GetString(LocationName).TrimEnd('\0'); + + long ResultCode = 0; + + try + { + TimeZone = TimeZoneInfo.FindSystemTimeZoneById(TzID); + } + catch (TimeZoneNotFoundException) + { + ResultCode = MakeError(ErrorModule.Time, 0x3dd); + } + + return ResultCode; + } + + public long GetTotalLocationNameCount(ServiceCtx Context) + { + Context.ResponseData.Write(TimeZoneInfo.GetSystemTimeZones().Count); + + return 0; + } + + public long LoadLocationNameList(ServiceCtx Context) + { + long BufferPosition = Context.Response.SendBuff[0].Position; + long BufferSize = Context.Response.SendBuff[0].Size; + + int Offset = 0; + + foreach (TimeZoneInfo info in TimeZoneInfo.GetSystemTimeZones()) + { + byte[] TzData = Encoding.ASCII.GetBytes(info.Id); + + Context.Memory.WriteBytes(BufferPosition + Offset, TzData); + + int Padding = 0x24 - TzData.Length; + + for (int Index = 0; Index < Padding; Index++) + { + Context.ResponseData.Write((byte)0); + } + + Offset += 0x24; + } + + return 0; + } + + public long LoadTimeZoneRule(ServiceCtx Context) + { + long BufferPosition = Context.Request.ReceiveBuff[0].Position; + long BufferSize = Context.Request.ReceiveBuff[0].Size; + + if (BufferSize != 0x4000) + { + Context.Device.Log.PrintWarning(LogClass.ServiceTime, $"TimeZoneRule buffer size is 0x{BufferSize:x} (expected 0x4000)"); + } + + long ResultCode = 0; + + byte[] LocationName = Context.RequestData.ReadBytes(0x24); + + string TzID = Encoding.ASCII.GetString(LocationName).TrimEnd('\0'); + + // Check if the Time Zone exists, otherwise error out. + try + { + TimeZoneInfo Info = TimeZoneInfo.FindSystemTimeZoneById(TzID); + + byte[] TzData = Encoding.ASCII.GetBytes(Info.Id); + + // FIXME: This is not in ANY cases accurate, but the games don't care about the content of the buffer, they only pass it. + // TODO: Reverse the TZif2 conversion in PCV to make this match with real hardware. + Context.Memory.WriteBytes(BufferPosition, TzData); + } + catch (TimeZoneNotFoundException) + { + Context.Device.Log.PrintWarning(LogClass.ServiceTime, $"Timezone not found for string: {TzID} (len: {TzID.Length})"); + + ResultCode = MakeError(ErrorModule.Time, 0x3dd); + } + + return ResultCode; + } + + private long ToCalendarTimeWithTz(ServiceCtx Context, long PosixTime, TimeZoneInfo Info) + { + DateTime CurrentTime = Epoch.AddSeconds(PosixTime); + + CurrentTime = TimeZoneInfo.ConvertTimeFromUtc(CurrentTime, Info); + + Context.ResponseData.Write((ushort)CurrentTime.Year); + Context.ResponseData.Write((byte)CurrentTime.Month); + Context.ResponseData.Write((byte)CurrentTime.Day); + Context.ResponseData.Write((byte)CurrentTime.Hour); + Context.ResponseData.Write((byte)CurrentTime.Minute); + Context.ResponseData.Write((byte)CurrentTime.Second); + Context.ResponseData.Write((byte)0); //MilliSecond ? + Context.ResponseData.Write((int)CurrentTime.DayOfWeek); + Context.ResponseData.Write(CurrentTime.DayOfYear - 1); + Context.ResponseData.Write(new byte[8]); //TODO: Find out the names used. + Context.ResponseData.Write((byte)(CurrentTime.IsDaylightSavingTime() ? 1 : 0)); + Context.ResponseData.Write((int)Info.GetUtcOffset(CurrentTime).TotalSeconds); + + return 0; + } + + public long ToCalendarTime(ServiceCtx Context) + { + long PosixTime = Context.RequestData.ReadInt64(); + long BufferPosition = Context.Request.SendBuff[0].Position; + long BufferSize = Context.Request.SendBuff[0].Size; + + if (BufferSize != 0x4000) + { + Context.Device.Log.PrintWarning(LogClass.ServiceTime, $"TimeZoneRule buffer size is 0x{BufferSize:x} (expected 0x4000)"); + } + + // TODO: Reverse the TZif2 conversion in PCV to make this match with real hardware. + byte[] TzData = Context.Memory.ReadBytes(BufferPosition, 0x24); + + string TzID = Encoding.ASCII.GetString(TzData).TrimEnd('\0'); + + long ResultCode = 0; + + // Check if the Time Zone exists, otherwise error out. + try + { + TimeZoneInfo Info = TimeZoneInfo.FindSystemTimeZoneById(TzID); + + ResultCode = ToCalendarTimeWithTz(Context, PosixTime, Info); + } + catch (TimeZoneNotFoundException) + { + Context.Device.Log.PrintWarning(LogClass.ServiceTime, $"Timezone not found for string: {TzID} (len: {TzID.Length})"); + + ResultCode = MakeError(ErrorModule.Time, 0x3dd); + } + + return ResultCode; + } + + public long ToCalendarTimeWithMyRule(ServiceCtx Context) + { + long PosixTime = Context.RequestData.ReadInt64(); + + return ToCalendarTimeWithTz(Context, PosixTime, TimeZone); + } + + public long ToPosixTime(ServiceCtx Context) + { + long BufferPosition = Context.Request.SendBuff[0].Position; + long BufferSize = Context.Request.SendBuff[0].Size; + + ushort Year = Context.RequestData.ReadUInt16(); + byte Month = Context.RequestData.ReadByte(); + byte Day = Context.RequestData.ReadByte(); + byte Hour = Context.RequestData.ReadByte(); + byte Minute = Context.RequestData.ReadByte(); + byte Second = Context.RequestData.ReadByte(); + + DateTime CalendarTime = new DateTime(Year, Month, Day, Hour, Minute, Second); + + if (BufferSize != 0x4000) + { + Context.Device.Log.PrintWarning(LogClass.ServiceTime, $"TimeZoneRule buffer size is 0x{BufferSize:x} (expected 0x4000)"); + } + + // TODO: Reverse the TZif2 conversion in PCV to make this match with real hardware. + byte[] TzData = Context.Memory.ReadBytes(BufferPosition, 0x24); + + string TzID = Encoding.ASCII.GetString(TzData).TrimEnd('\0'); + + long ResultCode = 0; + + // Check if the Time Zone exists, otherwise error out. + try + { + TimeZoneInfo Info = TimeZoneInfo.FindSystemTimeZoneById(TzID); + + return ToPosixTimeWithTz(Context, CalendarTime, Info); + } + catch (TimeZoneNotFoundException) + { + Context.Device.Log.PrintWarning(LogClass.ServiceTime, $"Timezone not found for string: {TzID} (len: {TzID.Length})"); + + ResultCode = MakeError(ErrorModule.Time, 0x3dd); + } + + return ResultCode; + } + + public long ToPosixTimeWithMyRule(ServiceCtx Context) + { + ushort Year = Context.RequestData.ReadUInt16(); + byte Month = Context.RequestData.ReadByte(); + byte Day = Context.RequestData.ReadByte(); + byte Hour = Context.RequestData.ReadByte(); + byte Minute = Context.RequestData.ReadByte(); + byte Second = Context.RequestData.ReadByte(); + + DateTime CalendarTime = new DateTime(Year, Month, Day, Hour, Minute, Second, DateTimeKind.Local); + + return ToPosixTimeWithTz(Context, CalendarTime, TimeZone); + } + + private long ToPosixTimeWithTz(ServiceCtx Context, DateTime CalendarTime, TimeZoneInfo Info) + { + DateTime CalenderTimeUTC = TimeZoneInfo.ConvertTimeToUtc(CalendarTime, Info); + + long PosixTime = ((DateTimeOffset)CalenderTimeUTC).ToUnixTimeSeconds(); + + long Position = Context.Request.RecvListBuff[0].Position; + long Size = Context.Request.RecvListBuff[0].Size; + + Context.Memory.WriteInt64(Position, PosixTime); + + Context.ResponseData.Write(1); + + return 0; + } + } +} diff --git a/Ryujinx.HLE/HOS/Services/Time/SystemClockType.cs b/Ryujinx.HLE/HOS/Services/Time/SystemClockType.cs new file mode 100644 index 00000000..54b7df3f --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Time/SystemClockType.cs @@ -0,0 +1,10 @@ +namespace Ryujinx.HLE.HOS.Services.Time +{ + enum SystemClockType + { + User, + Network, + Local, + EphemeralNetwork + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Vi/Display.cs b/Ryujinx.HLE/HOS/Services/Vi/Display.cs new file mode 100644 index 00000000..50fe5e1d --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Vi/Display.cs @@ -0,0 +1,12 @@ +namespace Ryujinx.HLE.HOS.Services.Vi +{ + class Display + { + public string Name { get; private set; } + + public Display(string Name) + { + this.Name = Name; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Vi/GbpBuffer.cs b/Ryujinx.HLE/HOS/Services/Vi/GbpBuffer.cs new file mode 100644 index 00000000..4f00c3de --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Vi/GbpBuffer.cs @@ -0,0 +1,60 @@ +using System.IO; + +namespace Ryujinx.HLE.HOS.Services.Android +{ + struct GbpBuffer + { + public int Magic { get; private set; } + public int Width { get; private set; } + public int Height { get; private set; } + public int Stride { get; private set; } + public int Format { get; private set; } + public int Usage { get; private set; } + + public int Pid { get; private set; } + public int RefCount { get; private set; } + + public int FdsCount { get; private set; } + public int IntsCount { get; private set; } + + public byte[] RawData { get; private set; } + + public int Size => RawData.Length + 10 * 4; + + public GbpBuffer(BinaryReader Reader) + { + Magic = Reader.ReadInt32(); + Width = Reader.ReadInt32(); + Height = Reader.ReadInt32(); + Stride = Reader.ReadInt32(); + Format = Reader.ReadInt32(); + Usage = Reader.ReadInt32(); + + Pid = Reader.ReadInt32(); + RefCount = Reader.ReadInt32(); + + FdsCount = Reader.ReadInt32(); + IntsCount = Reader.ReadInt32(); + + RawData = Reader.ReadBytes((FdsCount + IntsCount) * 4); + } + + public void Write(BinaryWriter Writer) + { + Writer.Write(Magic); + Writer.Write(Width); + Writer.Write(Height); + Writer.Write(Stride); + Writer.Write(Format); + Writer.Write(Usage); + + Writer.Write(Pid); + Writer.Write(RefCount); + + Writer.Write(FdsCount); + Writer.Write(IntsCount); + + Writer.Write(RawData); + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Vi/IApplicationDisplayService.cs b/Ryujinx.HLE/HOS/Services/Vi/IApplicationDisplayService.cs new file mode 100644 index 00000000..3006b73a --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Vi/IApplicationDisplayService.cs @@ -0,0 +1,233 @@ +using ChocolArm64.Memory; +using Ryujinx.HLE.HOS.Ipc; +using System.Collections.Generic; +using System.IO; +using System.Text; + +using static Ryujinx.HLE.HOS.Services.Android.Parcel; + +namespace Ryujinx.HLE.HOS.Services.Vi +{ + class IApplicationDisplayService : IpcService + { + private Dictionary m_Commands; + + public override IReadOnlyDictionary Commands => m_Commands; + + private IdDictionary Displays; + + public IApplicationDisplayService() + { + m_Commands = new Dictionary() + { + { 100, GetRelayService }, + { 101, GetSystemDisplayService }, + { 102, GetManagerDisplayService }, + { 103, GetIndirectDisplayTransactionService }, + { 1000, ListDisplays }, + { 1010, OpenDisplay }, + { 1020, CloseDisplay }, + { 1102, GetDisplayResolution }, + { 2020, OpenLayer }, + { 2021, CloseLayer }, + { 2030, CreateStrayLayer }, + { 2031, DestroyStrayLayer }, + { 2101, SetLayerScalingMode }, + { 5202, GetDisplayVSyncEvent } + }; + + Displays = new IdDictionary(); + } + + public long GetRelayService(ServiceCtx Context) + { + MakeObject(Context, new IHOSBinderDriver(Context.Device.Gpu.Renderer)); + + return 0; + } + + public long GetSystemDisplayService(ServiceCtx Context) + { + MakeObject(Context, new ISystemDisplayService()); + + return 0; + } + + public long GetManagerDisplayService(ServiceCtx Context) + { + MakeObject(Context, new IManagerDisplayService()); + + return 0; + } + + public long GetIndirectDisplayTransactionService(ServiceCtx Context) + { + MakeObject(Context, new IHOSBinderDriver(Context.Device.Gpu.Renderer)); + + return 0; + } + + public long ListDisplays(ServiceCtx Context) + { + long RecBuffPtr = Context.Request.ReceiveBuff[0].Position; + + AMemoryHelper.FillWithZeros(Context.Memory, RecBuffPtr, 0x60); + + //Add only the default display to buffer + Context.Memory.WriteBytes(RecBuffPtr, Encoding.ASCII.GetBytes("Default")); + Context.Memory.WriteInt64(RecBuffPtr + 0x40, 0x1L); + Context.Memory.WriteInt64(RecBuffPtr + 0x48, 0x1L); + Context.Memory.WriteInt64(RecBuffPtr + 0x50, 1920L); + Context.Memory.WriteInt64(RecBuffPtr + 0x58, 1080L); + + Context.ResponseData.Write(1L); + + return 0; + } + + public long OpenDisplay(ServiceCtx Context) + { + string Name = GetDisplayName(Context); + + long DisplayId = Displays.Add(new Display(Name)); + + Context.ResponseData.Write(DisplayId); + + return 0; + } + + public long CloseDisplay(ServiceCtx Context) + { + int DisplayId = Context.RequestData.ReadInt32(); + + Displays.Delete(DisplayId); + + return 0; + } + + public long GetDisplayResolution(ServiceCtx Context) + { + long DisplayId = Context.RequestData.ReadInt32(); + + Context.ResponseData.Write(1280); + Context.ResponseData.Write(720); + + return 0; + } + + public long OpenLayer(ServiceCtx Context) + { + long LayerId = Context.RequestData.ReadInt64(); + long UserId = Context.RequestData.ReadInt64(); + + long ParcelPtr = Context.Request.ReceiveBuff[0].Position; + + byte[] Parcel = MakeIGraphicsBufferProducer(ParcelPtr); + + Context.Memory.WriteBytes(ParcelPtr, Parcel); + + Context.ResponseData.Write((long)Parcel.Length); + + return 0; + } + + public long CloseLayer(ServiceCtx Context) + { + long LayerId = Context.RequestData.ReadInt64(); + + return 0; + } + + public long CreateStrayLayer(ServiceCtx Context) + { + long LayerFlags = Context.RequestData.ReadInt64(); + long DisplayId = Context.RequestData.ReadInt64(); + + long ParcelPtr = Context.Request.ReceiveBuff[0].Position; + + Display Disp = Displays.GetData((int)DisplayId); + + byte[] Parcel = MakeIGraphicsBufferProducer(ParcelPtr); + + Context.Memory.WriteBytes(ParcelPtr, Parcel); + + Context.ResponseData.Write(0L); + Context.ResponseData.Write((long)Parcel.Length); + + return 0; + } + + public long DestroyStrayLayer(ServiceCtx Context) + { + return 0; + } + + public long SetLayerScalingMode(ServiceCtx Context) + { + int ScalingMode = Context.RequestData.ReadInt32(); + long Unknown = Context.RequestData.ReadInt64(); + + return 0; + } + + public long GetDisplayVSyncEvent(ServiceCtx Context) + { + string Name = GetDisplayName(Context); + + int Handle = Context.Process.HandleTable.OpenHandle(Context.Device.System.VsyncEvent); + + Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle); + + return 0; + } + + private byte[] MakeIGraphicsBufferProducer(long BasePtr) + { + long Id = 0x20; + long CookiePtr = 0L; + + using (MemoryStream MS = new MemoryStream()) + { + BinaryWriter Writer = new BinaryWriter(MS); + + //flat_binder_object (size is 0x28) + Writer.Write(2); //Type (BINDER_TYPE_WEAK_BINDER) + Writer.Write(0); //Flags + Writer.Write((int)(Id >> 0)); + Writer.Write((int)(Id >> 32)); + Writer.Write((int)(CookiePtr >> 0)); + Writer.Write((int)(CookiePtr >> 32)); + Writer.Write((byte)'d'); + Writer.Write((byte)'i'); + Writer.Write((byte)'s'); + Writer.Write((byte)'p'); + Writer.Write((byte)'d'); + Writer.Write((byte)'r'); + Writer.Write((byte)'v'); + Writer.Write((byte)'\0'); + Writer.Write(0L); //Pad + + return MakeParcel(MS.ToArray(), new byte[] { 0, 0, 0, 0 }); + } + } + + private string GetDisplayName(ServiceCtx Context) + { + string Name = string.Empty; + + for (int Index = 0; Index < 8 && + Context.RequestData.BaseStream.Position < + Context.RequestData.BaseStream.Length; Index++) + { + byte Chr = Context.RequestData.ReadByte(); + + if (Chr >= 0x20 && Chr < 0x7f) + { + Name += (char)Chr; + } + } + + return Name; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Vi/IApplicationRootService.cs b/Ryujinx.HLE/HOS/Services/Vi/IApplicationRootService.cs new file mode 100644 index 00000000..e86734e6 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Vi/IApplicationRootService.cs @@ -0,0 +1,29 @@ +using Ryujinx.HLE.HOS.Ipc; +using System.Collections.Generic; + +namespace Ryujinx.HLE.HOS.Services.Vi +{ + class IApplicationRootService : IpcService + { + private Dictionary m_Commands; + + public override IReadOnlyDictionary Commands => m_Commands; + + public IApplicationRootService() + { + m_Commands = new Dictionary() + { + { 0, GetDisplayService } + }; + } + + public long GetDisplayService(ServiceCtx Context) + { + int ServiceType = Context.RequestData.ReadInt32(); + + MakeObject(Context, new IApplicationDisplayService()); + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Vi/IHOSBinderDriver.cs b/Ryujinx.HLE/HOS/Services/Vi/IHOSBinderDriver.cs new file mode 100644 index 00000000..bf5f20a2 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Vi/IHOSBinderDriver.cs @@ -0,0 +1,100 @@ +using Ryujinx.Graphics.Gal; +using Ryujinx.HLE.HOS.Ipc; +using Ryujinx.HLE.HOS.Kernel; +using Ryujinx.HLE.HOS.Services.Android; +using System; +using System.Collections.Generic; + +namespace Ryujinx.HLE.HOS.Services.Vi +{ + class IHOSBinderDriver : IpcService, IDisposable + { + private Dictionary m_Commands; + + public override IReadOnlyDictionary Commands => m_Commands; + + private KEvent ReleaseEvent; + + private NvFlinger Flinger; + + public IHOSBinderDriver(IGalRenderer Renderer) + { + m_Commands = new Dictionary() + { + { 0, TransactParcel }, + { 1, AdjustRefcount }, + { 2, GetNativeHandle }, + { 3, TransactParcelAuto } + }; + + ReleaseEvent = new KEvent(); + + Flinger = new NvFlinger(Renderer, ReleaseEvent); + } + + public long TransactParcel(ServiceCtx Context) + { + int Id = Context.RequestData.ReadInt32(); + int Code = Context.RequestData.ReadInt32(); + + long DataPos = Context.Request.SendBuff[0].Position; + long DataSize = Context.Request.SendBuff[0].Size; + + byte[] Data = Context.Memory.ReadBytes(DataPos, DataSize); + + Data = Parcel.GetParcelData(Data); + + return Flinger.ProcessParcelRequest(Context, Data, Code); + } + + public long TransactParcelAuto(ServiceCtx Context) + { + int Id = Context.RequestData.ReadInt32(); + int Code = Context.RequestData.ReadInt32(); + + (long DataPos, long DataSize) = Context.Request.GetBufferType0x21(); + + byte[] Data = Context.Memory.ReadBytes(DataPos, DataSize); + + Data = Parcel.GetParcelData(Data); + + return Flinger.ProcessParcelRequest(Context, Data, Code); + } + + public long AdjustRefcount(ServiceCtx Context) + { + int Id = Context.RequestData.ReadInt32(); + int AddVal = Context.RequestData.ReadInt32(); + int Type = Context.RequestData.ReadInt32(); + + return 0; + } + + public long GetNativeHandle(ServiceCtx Context) + { + int Id = Context.RequestData.ReadInt32(); + uint Unk = Context.RequestData.ReadUInt32(); + + int Handle = Context.Process.HandleTable.OpenHandle(ReleaseEvent); + + Context.Response.HandleDesc = IpcHandleDesc.MakeMove(Handle); + + return 0; + } + + public void Dispose() + { + Dispose(true); + } + + protected virtual void Dispose(bool Disposing) + { + if (Disposing) + { + ReleaseEvent.Dispose(); + + Flinger.Dispose(); + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Vi/IManagerDisplayService.cs b/Ryujinx.HLE/HOS/Services/Vi/IManagerDisplayService.cs new file mode 100644 index 00000000..61f0ffaa --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Vi/IManagerDisplayService.cs @@ -0,0 +1,54 @@ +using Ryujinx.HLE.HOS.Ipc; +using Ryujinx.HLE.Logging; +using System.Collections.Generic; + +namespace Ryujinx.HLE.HOS.Services.Vi +{ + class IManagerDisplayService : IpcService + { + private Dictionary m_Commands; + + public override IReadOnlyDictionary Commands => m_Commands; + + public IManagerDisplayService() + { + m_Commands = new Dictionary() + { + { 2010, CreateManagedLayer }, + { 2011, DestroyManagedLayer }, + { 6000, AddToLayerStack }, + { 6002, SetLayerVisibility } + }; + } + + public static long CreateManagedLayer(ServiceCtx Context) + { + Context.Device.Log.PrintStub(LogClass.ServiceVi, "Stubbed."); + + Context.ResponseData.Write(0L); //LayerId + + return 0; + } + + public long DestroyManagedLayer(ServiceCtx Context) + { + Context.Device.Log.PrintStub(LogClass.ServiceVi, "Stubbed."); + + return 0; + } + + public static long AddToLayerStack(ServiceCtx Context) + { + Context.Device.Log.PrintStub(LogClass.ServiceVi, "Stubbed."); + + return 0; + } + + public static long SetLayerVisibility(ServiceCtx Context) + { + Context.Device.Log.PrintStub(LogClass.ServiceVi, "Stubbed."); + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Vi/IManagerRootService.cs b/Ryujinx.HLE/HOS/Services/Vi/IManagerRootService.cs new file mode 100644 index 00000000..14b8fc3c --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Vi/IManagerRootService.cs @@ -0,0 +1,29 @@ +using Ryujinx.HLE.HOS.Ipc; +using System.Collections.Generic; + +namespace Ryujinx.HLE.HOS.Services.Vi +{ + class IManagerRootService : IpcService + { + private Dictionary m_Commands; + + public override IReadOnlyDictionary Commands => m_Commands; + + public IManagerRootService() + { + m_Commands = new Dictionary() + { + { 2, GetDisplayService } + }; + } + + public long GetDisplayService(ServiceCtx Context) + { + int ServiceType = Context.RequestData.ReadInt32(); + + MakeObject(Context, new IApplicationDisplayService()); + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Vi/ISystemDisplayService.cs b/Ryujinx.HLE/HOS/Services/Vi/ISystemDisplayService.cs new file mode 100644 index 00000000..5657ba69 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Vi/ISystemDisplayService.cs @@ -0,0 +1,48 @@ +using Ryujinx.HLE.HOS.Ipc; +using Ryujinx.HLE.Logging; +using System.Collections.Generic; + +namespace Ryujinx.HLE.HOS.Services.Vi +{ + class ISystemDisplayService : IpcService + { + private Dictionary m_Commands; + + public override IReadOnlyDictionary Commands => m_Commands; + + public ISystemDisplayService() + { + m_Commands = new Dictionary() + { + { 2205, SetLayerZ }, + { 2207, SetLayerVisibility }, + { 3200, GetDisplayMode } + }; + } + + public static long SetLayerZ(ServiceCtx Context) + { + Context.Device.Log.PrintStub(LogClass.ServiceVi, "Stubbed."); + + return 0; + } + + public static long SetLayerVisibility(ServiceCtx Context) + { + Context.Device.Log.PrintStub(LogClass.ServiceVi, "Stubbed."); + + return 0; + } + + public static long GetDisplayMode(ServiceCtx Context) + { + //TODO: De-hardcode resolution. + Context.ResponseData.Write(1280); + Context.ResponseData.Write(720); + Context.ResponseData.Write(60.0f); + Context.ResponseData.Write(0); + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Vi/ISystemRootService.cs b/Ryujinx.HLE/HOS/Services/Vi/ISystemRootService.cs new file mode 100644 index 00000000..d9b7c220 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Vi/ISystemRootService.cs @@ -0,0 +1,29 @@ +using Ryujinx.HLE.HOS.Ipc; +using System.Collections.Generic; + +namespace Ryujinx.HLE.HOS.Services.Vi +{ + class ISystemRootService : IpcService + { + private Dictionary m_Commands; + + public override IReadOnlyDictionary Commands => m_Commands; + + public ISystemRootService() + { + m_Commands = new Dictionary() + { + { 1, GetDisplayService } + }; + } + + public long GetDisplayService(ServiceCtx Context) + { + int ServiceType = Context.RequestData.ReadInt32(); + + MakeObject(Context, new IApplicationDisplayService()); + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Vi/NvFlinger.cs b/Ryujinx.HLE/HOS/Services/Vi/NvFlinger.cs new file mode 100644 index 00000000..12c17311 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Vi/NvFlinger.cs @@ -0,0 +1,416 @@ +using Ryujinx.Graphics.Gal; +using Ryujinx.HLE.Gpu.Texture; +using Ryujinx.HLE.HOS.Kernel; +using Ryujinx.HLE.HOS.Services.Nv.NvMap; +using Ryujinx.HLE.Logging; +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using System.Threading; + +using static Ryujinx.HLE.HOS.Services.Android.Parcel; + +namespace Ryujinx.HLE.HOS.Services.Android +{ + class NvFlinger : IDisposable + { + private delegate long ServiceProcessParcel(ServiceCtx Context, BinaryReader ParcelReader); + + private Dictionary<(string, int), ServiceProcessParcel> Commands; + + private KEvent ReleaseEvent; + + private IGalRenderer Renderer; + + private const int BufferQueueCount = 0x40; + private const int BufferQueueMask = BufferQueueCount - 1; + + [Flags] + private enum HalTransform + { + FlipX = 1 << 0, + FlipY = 1 << 1, + Rotate90 = 1 << 2 + } + + private enum BufferState + { + Free, + Dequeued, + Queued, + Acquired + } + + private struct Rect + { + public int Top; + public int Left; + public int Right; + public int Bottom; + } + + private struct BufferEntry + { + public BufferState State; + + public HalTransform Transform; + + public Rect Crop; + + public GbpBuffer Data; + } + + private BufferEntry[] BufferQueue; + + private ManualResetEvent WaitBufferFree; + + private bool Disposed; + + public NvFlinger(IGalRenderer Renderer, KEvent ReleaseEvent) + { + Commands = new Dictionary<(string, int), ServiceProcessParcel>() + { + { ("android.gui.IGraphicBufferProducer", 0x1), GbpRequestBuffer }, + { ("android.gui.IGraphicBufferProducer", 0x3), GbpDequeueBuffer }, + { ("android.gui.IGraphicBufferProducer", 0x4), GbpDetachBuffer }, + { ("android.gui.IGraphicBufferProducer", 0x7), GbpQueueBuffer }, + { ("android.gui.IGraphicBufferProducer", 0x8), GbpCancelBuffer }, + { ("android.gui.IGraphicBufferProducer", 0x9), GbpQuery }, + { ("android.gui.IGraphicBufferProducer", 0xa), GbpConnect }, + { ("android.gui.IGraphicBufferProducer", 0xb), GbpDisconnect }, + { ("android.gui.IGraphicBufferProducer", 0xe), GbpPreallocBuffer } + }; + + this.Renderer = Renderer; + this.ReleaseEvent = ReleaseEvent; + + BufferQueue = new BufferEntry[0x40]; + + WaitBufferFree = new ManualResetEvent(false); + } + + public long ProcessParcelRequest(ServiceCtx Context, byte[] ParcelData, int Code) + { + using (MemoryStream MS = new MemoryStream(ParcelData)) + { + BinaryReader Reader = new BinaryReader(MS); + + MS.Seek(4, SeekOrigin.Current); + + int StrSize = Reader.ReadInt32(); + + string InterfaceName = Encoding.Unicode.GetString(Reader.ReadBytes(StrSize * 2)); + + long Remainder = MS.Position & 0xf; + + if (Remainder != 0) + { + MS.Seek(0x10 - Remainder, SeekOrigin.Current); + } + + MS.Seek(0x50, SeekOrigin.Begin); + + if (Commands.TryGetValue((InterfaceName, Code), out ServiceProcessParcel ProcReq)) + { + Context.Device.Log.PrintDebug(LogClass.ServiceVi, $"{InterfaceName} {ProcReq.Method.Name}"); + + return ProcReq(Context, Reader); + } + else + { + throw new NotImplementedException($"{InterfaceName} {Code}"); + } + } + } + + private long GbpRequestBuffer(ServiceCtx Context, BinaryReader ParcelReader) + { + int Slot = ParcelReader.ReadInt32(); + + using (MemoryStream MS = new MemoryStream()) + { + BinaryWriter Writer = new BinaryWriter(MS); + + BufferEntry Entry = BufferQueue[Slot]; + + int BufferCount = 1; //? + long BufferSize = Entry.Data.Size; + + Writer.Write(BufferCount); + Writer.Write(BufferSize); + + Entry.Data.Write(Writer); + + Writer.Write(0); + + return MakeReplyParcel(Context, MS.ToArray()); + } + } + + private long GbpDequeueBuffer(ServiceCtx Context, BinaryReader ParcelReader) + { + //TODO: Errors. + int Format = ParcelReader.ReadInt32(); + int Width = ParcelReader.ReadInt32(); + int Height = ParcelReader.ReadInt32(); + int GetTimestamps = ParcelReader.ReadInt32(); + int Usage = ParcelReader.ReadInt32(); + + int Slot = GetFreeSlotBlocking(Width, Height); + + return MakeReplyParcel(Context, Slot, 1, 0x24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + } + + private long GbpQueueBuffer(ServiceCtx Context, BinaryReader ParcelReader) + { + Context.Device.Statistics.RecordGameFrameTime(); + + //TODO: Errors. + int Slot = ParcelReader.ReadInt32(); + int Unknown4 = ParcelReader.ReadInt32(); + int Unknown8 = ParcelReader.ReadInt32(); + int Unknownc = ParcelReader.ReadInt32(); + int Timestamp = ParcelReader.ReadInt32(); + int IsAutoTimestamp = ParcelReader.ReadInt32(); + int CropTop = ParcelReader.ReadInt32(); + int CropLeft = ParcelReader.ReadInt32(); + int CropRight = ParcelReader.ReadInt32(); + int CropBottom = ParcelReader.ReadInt32(); + int ScalingMode = ParcelReader.ReadInt32(); + int Transform = ParcelReader.ReadInt32(); + int StickyTransform = ParcelReader.ReadInt32(); + int Unknown34 = ParcelReader.ReadInt32(); + int Unknown38 = ParcelReader.ReadInt32(); + int IsFenceValid = ParcelReader.ReadInt32(); + int Fence0Id = ParcelReader.ReadInt32(); + int Fence0Value = ParcelReader.ReadInt32(); + int Fence1Id = ParcelReader.ReadInt32(); + int Fence1Value = ParcelReader.ReadInt32(); + + BufferQueue[Slot].Transform = (HalTransform)Transform; + + BufferQueue[Slot].Crop.Top = CropTop; + BufferQueue[Slot].Crop.Left = CropLeft; + BufferQueue[Slot].Crop.Right = CropRight; + BufferQueue[Slot].Crop.Bottom = CropBottom; + + BufferQueue[Slot].State = BufferState.Queued; + + SendFrameBuffer(Context, Slot); + + return MakeReplyParcel(Context, 1280, 720, 0, 0, 0); + } + + private long GbpDetachBuffer(ServiceCtx Context, BinaryReader ParcelReader) + { + return MakeReplyParcel(Context, 0); + } + + private long GbpCancelBuffer(ServiceCtx Context, BinaryReader ParcelReader) + { + //TODO: Errors. + int Slot = ParcelReader.ReadInt32(); + + BufferQueue[Slot].State = BufferState.Free; + + return MakeReplyParcel(Context, 0); + } + + private long GbpQuery(ServiceCtx Context, BinaryReader ParcelReader) + { + return MakeReplyParcel(Context, 0, 0); + } + + private long GbpConnect(ServiceCtx Context, BinaryReader ParcelReader) + { + return MakeReplyParcel(Context, 1280, 720, 0, 0, 0); + } + + private long GbpDisconnect(ServiceCtx Context, BinaryReader ParcelReader) + { + return MakeReplyParcel(Context, 0); + } + + private long GbpPreallocBuffer(ServiceCtx Context, BinaryReader ParcelReader) + { + int Slot = ParcelReader.ReadInt32(); + + int BufferCount = ParcelReader.ReadInt32(); + + if (BufferCount > 0) + { + long BufferSize = ParcelReader.ReadInt64(); + + BufferQueue[Slot].State = BufferState.Free; + + BufferQueue[Slot].Data = new GbpBuffer(ParcelReader); + } + + return MakeReplyParcel(Context, 0); + } + + private long MakeReplyParcel(ServiceCtx Context, params int[] Ints) + { + using (MemoryStream MS = new MemoryStream()) + { + BinaryWriter Writer = new BinaryWriter(MS); + + foreach (int Int in Ints) + { + Writer.Write(Int); + } + + return MakeReplyParcel(Context, MS.ToArray()); + } + } + + private long MakeReplyParcel(ServiceCtx Context, byte[] Data) + { + long ReplyPos = Context.Request.ReceiveBuff[0].Position; + long ReplySize = Context.Request.ReceiveBuff[0].Size; + + byte[] Reply = MakeParcel(Data, new byte[0]); + + Context.Memory.WriteBytes(ReplyPos, Reply); + + return 0; + } + + private void SendFrameBuffer(ServiceCtx Context, int Slot) + { + int FbWidth = BufferQueue[Slot].Data.Width; + int FbHeight = BufferQueue[Slot].Data.Height; + + int NvMapHandle = BitConverter.ToInt32(BufferQueue[Slot].Data.RawData, 0x4c); + int BufferOffset = BitConverter.ToInt32(BufferQueue[Slot].Data.RawData, 0x50); + + NvMapHandle Map = NvMapIoctl.GetNvMap(Context, NvMapHandle);; + + long FbAddr = Map.Address + BufferOffset; + + BufferQueue[Slot].State = BufferState.Acquired; + + Rect Crop = BufferQueue[Slot].Crop; + + bool FlipX = BufferQueue[Slot].Transform.HasFlag(HalTransform.FlipX); + bool FlipY = BufferQueue[Slot].Transform.HasFlag(HalTransform.FlipY); + + //Rotation is being ignored + + int Top = Crop.Top; + int Left = Crop.Left; + int Right = Crop.Right; + int Bottom = Crop.Bottom; + + Renderer.QueueAction(() => Renderer.FrameBuffer.SetTransform(FlipX, FlipY, Top, Left, Right, Bottom)); + + //TODO: Support double buffering here aswell, it is broken for GPU + //frame buffers because it seems to be completely out of sync. + if (Context.Device.Gpu.Engine3d.IsFrameBufferPosition(FbAddr)) + { + //Frame buffer is rendered to by the GPU, we can just + //bind the frame buffer texture, it's not necessary to read anything. + Renderer.QueueAction(() => Renderer.FrameBuffer.Set(FbAddr)); + } + else + { + //Frame buffer is not set on the GPU registers, in this case + //assume that the app is manually writing to it. + TextureInfo Texture = new TextureInfo(FbAddr, FbWidth, FbHeight); + + byte[] Data = TextureReader.Read(Context.Memory, Texture); + + Renderer.QueueAction(() => Renderer.FrameBuffer.Set(Data, FbWidth, FbHeight)); + } + + Context.Device.Gpu.Renderer.QueueAction(() => ReleaseBuffer(Slot)); + } + + private void ReleaseBuffer(int Slot) + { + BufferQueue[Slot].State = BufferState.Free; + + ReleaseEvent.WaitEvent.Set(); + + lock (WaitBufferFree) + { + WaitBufferFree.Set(); + } + } + + private int GetFreeSlotBlocking(int Width, int Height) + { + int Slot; + + do + { + lock (WaitBufferFree) + { + if ((Slot = GetFreeSlot(Width, Height)) != -1) + { + break; + } + + if (Disposed) + { + break; + } + + WaitBufferFree.Reset(); + } + + WaitBufferFree.WaitOne(); + } + while (!Disposed); + + return Slot; + } + + private int GetFreeSlot(int Width, int Height) + { + lock (BufferQueue) + { + for (int Slot = 0; Slot < BufferQueue.Length; Slot++) + { + if (BufferQueue[Slot].State != BufferState.Free) + { + continue; + } + + GbpBuffer Data = BufferQueue[Slot].Data; + + if (Data.Width == Width && + Data.Height == Height) + { + BufferQueue[Slot].State = BufferState.Dequeued; + + return Slot; + } + } + } + + return -1; + } + + public void Dispose() + { + Dispose(true); + } + + protected virtual void Dispose(bool Disposing) + { + if (Disposing && !Disposed) + { + Disposed = true; + + lock (WaitBufferFree) + { + WaitBufferFree.Set(); + } + + WaitBufferFree.Dispose(); + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Vi/Parcel.cs b/Ryujinx.HLE/HOS/Services/Vi/Parcel.cs new file mode 100644 index 00000000..bb842795 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Vi/Parcel.cs @@ -0,0 +1,58 @@ +using System; +using System.IO; + +namespace Ryujinx.HLE.HOS.Services.Android +{ + static class Parcel + { + public static byte[] GetParcelData(byte[] Parcel) + { + if (Parcel == null) + { + throw new ArgumentNullException(nameof(Parcel)); + } + + using (MemoryStream MS = new MemoryStream(Parcel)) + { + BinaryReader Reader = new BinaryReader(MS); + + int DataSize = Reader.ReadInt32(); + int DataOffset = Reader.ReadInt32(); + int ObjsSize = Reader.ReadInt32(); + int ObjsOffset = Reader.ReadInt32(); + + MS.Seek(DataOffset - 0x10, SeekOrigin.Current); + + return Reader.ReadBytes(DataSize); + } + } + + public static byte[] MakeParcel(byte[] Data, byte[] Objs) + { + if (Data == null) + { + throw new ArgumentNullException(nameof(Data)); + } + + if (Objs == null) + { + throw new ArgumentNullException(nameof(Objs)); + } + + using (MemoryStream MS = new MemoryStream()) + { + BinaryWriter Writer = new BinaryWriter(MS); + + Writer.Write(Data.Length); + Writer.Write(0x10); + Writer.Write(Objs.Length); + Writer.Write(Data.Length + 0x10); + + Writer.Write(Data); + Writer.Write(Objs); + + return MS.ToArray(); + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/SystemState/AppletStateMgr.cs b/Ryujinx.HLE/HOS/SystemState/AppletStateMgr.cs new file mode 100644 index 00000000..ee0e6fea --- /dev/null +++ b/Ryujinx.HLE/HOS/SystemState/AppletStateMgr.cs @@ -0,0 +1,62 @@ +using Ryujinx.HLE.HOS.Kernel; +using Ryujinx.HLE.HOS.Services.Am; +using System; +using System.Collections.Concurrent; + +namespace Ryujinx.HLE.HOS.SystemState +{ + class AppletStateMgr : IDisposable + { + private ConcurrentQueue Messages; + + public FocusState FocusState { get; private set; } + + public KEvent MessageEvent { get; private set; } + + public AppletStateMgr() + { + Messages = new ConcurrentQueue(); + + MessageEvent = new KEvent(); + } + + public void SetFocus(bool IsFocused) + { + FocusState = IsFocused + ? FocusState.InFocus + : FocusState.OutOfFocus; + + EnqueueMessage(MessageInfo.FocusStateChanged); + } + + public void EnqueueMessage(MessageInfo Message) + { + Messages.Enqueue(Message); + + MessageEvent.WaitEvent.Set(); + } + + public bool TryDequeueMessage(out MessageInfo Message) + { + if (Messages.Count < 2) + { + MessageEvent.WaitEvent.Reset(); + } + + return Messages.TryDequeue(out Message); + } + + public void Dispose() + { + Dispose(true); + } + + protected virtual void Dispose(bool Disposing) + { + if (Disposing) + { + MessageEvent.Dispose(); + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/SystemState/ColorSet.cs b/Ryujinx.HLE/HOS/SystemState/ColorSet.cs new file mode 100644 index 00000000..4d7a7e2f --- /dev/null +++ b/Ryujinx.HLE/HOS/SystemState/ColorSet.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.SystemState +{ + public enum ColorSet + { + BasicWhite = 0, + BasicBlack = 1 + } +} diff --git a/Ryujinx.HLE/HOS/SystemState/OpenCloseState.cs b/Ryujinx.HLE/HOS/SystemState/OpenCloseState.cs new file mode 100644 index 00000000..a2678b5c --- /dev/null +++ b/Ryujinx.HLE/HOS/SystemState/OpenCloseState.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.SystemState +{ + public enum OpenCloseState + { + Closed, + Open + } +} diff --git a/Ryujinx.HLE/HOS/SystemState/SystemLanguage.cs b/Ryujinx.HLE/HOS/SystemState/SystemLanguage.cs new file mode 100644 index 00000000..2046ed62 --- /dev/null +++ b/Ryujinx.HLE/HOS/SystemState/SystemLanguage.cs @@ -0,0 +1,23 @@ +namespace Ryujinx.HLE.HOS.SystemState +{ + public enum SystemLanguage + { + Japanese, + AmericanEnglish, + French, + German, + Italian, + Spanish, + Chinese, + Korean, + Dutch, + Portuguese, + Russian, + Taiwanese, + BritishEnglish, + CanadianFrench, + LatinAmericanSpanish, + SimplifiedChinese, + TraditionalChinese + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/SystemState/SystemStateMgr.cs b/Ryujinx.HLE/HOS/SystemState/SystemStateMgr.cs new file mode 100644 index 00000000..bd1dbd78 --- /dev/null +++ b/Ryujinx.HLE/HOS/SystemState/SystemStateMgr.cs @@ -0,0 +1,145 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; + +namespace Ryujinx.HLE.HOS.SystemState +{ + public class SystemStateMgr + { + internal static string[] LanguageCodes = new string[] + { + "ja", + "en-US", + "fr", + "de", + "it", + "es", + "zh-CN", + "ko", + "nl", + "pt", + "ru", + "zh-TW", + "en-GB", + "fr-CA", + "es-419", + "zh-Hans", + "zh-Hant" + }; + + internal static string[] AudioOutputs = new string[] + { + "AudioTvOutput", + "AudioStereoJackOutput", + "AudioBuiltInSpeakerOutput" + }; + + internal long DesiredLanguageCode { get; private set; } + + internal string ActiveAudioOutput { get; private set; } + + public bool DockedMode { get; set; } + + public ColorSet ThemeColor { get; set; } + + private ConcurrentDictionary Profiles; + + internal UserProfile LastOpenUser { get; private set; } + + public SystemStateMgr() + { + SetLanguage(SystemLanguage.AmericanEnglish); + + SetAudioOutputAsBuiltInSpeaker(); + + Profiles = new ConcurrentDictionary(); + + UserId DefaultUuid = new UserId("00000000000000000000000000000001"); + + AddUser(DefaultUuid, "Player"); + OpenUser(DefaultUuid); + } + + public void SetLanguage(SystemLanguage Language) + { + DesiredLanguageCode = GetLanguageCode((int)Language); + } + + public void SetAudioOutputAsTv() + { + ActiveAudioOutput = AudioOutputs[0]; + } + + public void SetAudioOutputAsStereoJack() + { + ActiveAudioOutput = AudioOutputs[1]; + } + + public void SetAudioOutputAsBuiltInSpeaker() + { + ActiveAudioOutput = AudioOutputs[2]; + } + + public void AddUser(UserId Uuid, string Name) + { + UserProfile Profile = new UserProfile(Uuid, Name); + + Profiles.AddOrUpdate(Uuid.UserIdHex, Profile, (Key, Old) => Profile); + } + + public void OpenUser(UserId Uuid) + { + if (Profiles.TryGetValue(Uuid.UserIdHex, out UserProfile Profile)) + { + (LastOpenUser = Profile).AccountState = OpenCloseState.Open; + } + } + + public void CloseUser(UserId Uuid) + { + if (Profiles.TryGetValue(Uuid.UserIdHex, out UserProfile Profile)) + { + Profile.AccountState = OpenCloseState.Closed; + } + } + + public int GetUserCount() + { + return Profiles.Count; + } + + internal bool TryGetUser(UserId Uuid, out UserProfile Profile) + { + return Profiles.TryGetValue(Uuid.UserIdHex, out Profile); + } + + internal IEnumerable GetAllUsers() + { + return Profiles.Values; + } + + internal IEnumerable GetOpenUsers() + { + return Profiles.Values.Where(x => x.AccountState == OpenCloseState.Open); + } + + internal static long GetLanguageCode(int Index) + { + if ((uint)Index >= LanguageCodes.Length) + { + throw new ArgumentOutOfRangeException(nameof(Index)); + } + + long Code = 0; + int Shift = 0; + + foreach (char Chr in LanguageCodes[Index]) + { + Code |= (long)(byte)Chr << Shift++ * 8; + } + + return Code; + } + } +} diff --git a/Ryujinx.HLE/HOS/SystemState/UserId.cs b/Ryujinx.HLE/HOS/SystemState/UserId.cs new file mode 100644 index 00000000..1e7c53dd --- /dev/null +++ b/Ryujinx.HLE/HOS/SystemState/UserId.cs @@ -0,0 +1,76 @@ +using Ryujinx.HLE.Utilities; +using System; +using System.IO; +using System.Linq; + +namespace Ryujinx.HLE.HOS.SystemState +{ + public struct UserId + { + public string UserIdHex { get; private set; } + + public byte[] Bytes { get; private set; } + + public UserId(long Low, long High) + { + if ((Low | High) == 0) + { + throw new ArgumentException("Zero is not a valid user id!"); + } + + byte[] Bytes = new byte[16]; + + int Index = Bytes.Length; + + void WriteBytes(long Value) + { + for (int Byte = 0; Byte < 8; Byte++) + { + Bytes[--Index] = (byte)(Value >> Byte * 8); + } + } + + WriteBytes(Low); + WriteBytes(High); + + UserIdHex = string.Empty; + + foreach (byte Byte in Bytes) + { + UserIdHex += Byte.ToString("X2"); + } + + this.Bytes = Bytes; + } + + public UserId(string UserIdHex) + { + if (UserIdHex == null || UserIdHex.Length != 32 || !UserIdHex.All("0123456789abcdefABCDEF".Contains)) + { + throw new ArgumentException("Invalid user id!", nameof(UserIdHex)); + } + + if (UserIdHex == "00000000000000000000000000000000") + { + throw new ArgumentException("Zero is not a valid user id!", nameof(UserIdHex)); + } + + this.UserIdHex = UserIdHex.ToUpper(); + + Bytes = StringUtils.HexToBytes(UserIdHex); + } + + internal void Write(BinaryWriter Writer) + { + for (int Index = Bytes.Length - 1; Index >= 0; Index--) + { + Writer.Write(Bytes[Index]); + } + } + + public override string ToString() + { + return UserIdHex; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/SystemState/UserProfile.cs b/Ryujinx.HLE/HOS/SystemState/UserProfile.cs new file mode 100644 index 00000000..63852cdf --- /dev/null +++ b/Ryujinx.HLE/HOS/SystemState/UserProfile.cs @@ -0,0 +1,36 @@ +using System; + +namespace Ryujinx.HLE.HOS.SystemState +{ + class UserProfile + { + private static readonly DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); + + public UserId Uuid { get; private set; } + + public string Name { get; private set; } + + public long LastModifiedTimestamp { get; private set; } + + public OpenCloseState AccountState { get; set; } + public OpenCloseState OnlinePlayState { get; set; } + + public UserProfile(UserId Uuid, string Name) + { + this.Uuid = Uuid; + this.Name = Name; + + LastModifiedTimestamp = 0; + + AccountState = OpenCloseState.Closed; + OnlinePlayState = OpenCloseState.Closed; + + UpdateTimestamp(); + } + + private void UpdateTimestamp() + { + LastModifiedTimestamp = (long)(DateTime.Now - Epoch).TotalSeconds; + } + } +} diff --git a/Ryujinx.HLE/Hid/Hid.cs b/Ryujinx.HLE/Hid/Hid.cs index 492eb30a..0353b3ba 100644 --- a/Ryujinx.HLE/Hid/Hid.cs +++ b/Ryujinx.HLE/Hid/Hid.cs @@ -1,4 +1,4 @@ -using Ryujinx.HLE.OsHle; +using Ryujinx.HLE.HOS; using System; namespace Ryujinx.HLE.Input diff --git a/Ryujinx.HLE/Loaders/Executable.cs b/Ryujinx.HLE/Loaders/Executable.cs index ba5f8d7e..6a3f0b97 100644 --- a/Ryujinx.HLE/Loaders/Executable.cs +++ b/Ryujinx.HLE/Loaders/Executable.cs @@ -1,8 +1,8 @@ using ChocolArm64.Memory; +using Ryujinx.HLE.HOS; +using Ryujinx.HLE.HOS.Kernel; using Ryujinx.HLE.Loaders.Executables; -using Ryujinx.HLE.OsHle; -using Ryujinx.HLE.OsHle.Handles; -using Ryujinx.HLE.OsHle.Utilities; +using Ryujinx.HLE.Utilities; using System.Collections.Generic; using System.IO; diff --git a/Ryujinx.HLE/Loaders/Npdm/ACI0.cs b/Ryujinx.HLE/Loaders/Npdm/ACI0.cs index 47b30a3c..fd6fd6c3 100644 --- a/Ryujinx.HLE/Loaders/Npdm/ACI0.cs +++ b/Ryujinx.HLE/Loaders/Npdm/ACI0.cs @@ -1,55 +1,53 @@ -using System; +using Ryujinx.HLE.Exceptions; using System.IO; namespace Ryujinx.HLE.Loaders.Npdm { class ACI0 { - public string TitleId; + private const int ACI0Magic = 'A' << 0 | 'C' << 8 | 'I' << 16 | '0' << 24; - private int FSAccessHeaderOffset; - private int FSAccessHeaderSize; - private int ServiceAccessControlOffset; - private int ServiceAccessControlSize; - private int KernelAccessControlOffset; - private int KernelAccessControlSize; + public long TitleId { get; private set; } - public FSAccessHeader FSAccessHeader; - public ServiceAccessControl ServiceAccessControl; - public KernelAccessControl KernelAccessControl; + public int FsVersion { get; private set; } + public ulong FsPermissionsBitmask { get; private set; } - public const long ACI0Magic = 'A' << 0 | 'C' << 8 | 'I' << 16 | '0' << 24; + public ServiceAccessControl ServiceAccessControl { get; private set; } + public KernelAccessControl KernelAccessControl { get; private set; } - public ACI0(Stream ACI0Stream, int Offset) + public ACI0(Stream Stream, int Offset) { - ACI0Stream.Seek(Offset, SeekOrigin.Begin); + Stream.Seek(Offset, SeekOrigin.Begin); - BinaryReader Reader = new BinaryReader(ACI0Stream); + BinaryReader Reader = new BinaryReader(Stream); if (Reader.ReadInt32() != ACI0Magic) { throw new InvalidNpdmException("ACI0 Stream doesn't contain ACI0 section!"); } - ACI0Stream.Seek(0x0C, SeekOrigin.Current); + Stream.Seek(0xc, SeekOrigin.Current); - byte[] TempTitleId = Reader.ReadBytes(8); - Array.Reverse(TempTitleId); - TitleId = BitConverter.ToString(TempTitleId).Replace("-", ""); + TitleId = Reader.ReadInt64(); - // Reserved (Not currently used, potentially to be used for lowest title ID in future.) - ACI0Stream.Seek(0x08, SeekOrigin.Current); + //Reserved. + Stream.Seek(8, SeekOrigin.Current); - FSAccessHeaderOffset = Reader.ReadInt32(); - FSAccessHeaderSize = Reader.ReadInt32(); - ServiceAccessControlOffset = Reader.ReadInt32(); - ServiceAccessControlSize = Reader.ReadInt32(); - KernelAccessControlOffset = Reader.ReadInt32(); - KernelAccessControlSize = Reader.ReadInt32(); + int FsAccessHeaderOffset = Reader.ReadInt32(); + int FsAccessHeaderSize = Reader.ReadInt32(); + int ServiceAccessControlOffset = Reader.ReadInt32(); + int ServiceAccessControlSize = Reader.ReadInt32(); + int KernelAccessControlOffset = Reader.ReadInt32(); + int KernelAccessControlSize = Reader.ReadInt32(); - FSAccessHeader = new FSAccessHeader(ACI0Stream, Offset + FSAccessHeaderOffset, FSAccessHeaderSize); - ServiceAccessControl = new ServiceAccessControl(ACI0Stream, Offset + ServiceAccessControlOffset, ServiceAccessControlSize); - KernelAccessControl = new KernelAccessControl(ACI0Stream, Offset + KernelAccessControlOffset, KernelAccessControlSize); + FsAccessHeader FsAccessHeader = new FsAccessHeader(Stream, Offset + FsAccessHeaderOffset, FsAccessHeaderSize); + + FsVersion = FsAccessHeader.Version; + FsPermissionsBitmask = FsAccessHeader.PermissionsBitmask; + + ServiceAccessControl = new ServiceAccessControl(Stream, Offset + ServiceAccessControlOffset, ServiceAccessControlSize); + + KernelAccessControl = new KernelAccessControl(Stream, Offset + KernelAccessControlOffset, KernelAccessControlSize); } } } diff --git a/Ryujinx.HLE/Loaders/Npdm/ACID.cs b/Ryujinx.HLE/Loaders/Npdm/ACID.cs index 09768a92..7ead3294 100644 --- a/Ryujinx.HLE/Loaders/Npdm/ACID.cs +++ b/Ryujinx.HLE/Loaders/Npdm/ACID.cs @@ -1,36 +1,29 @@ -using System; +using Ryujinx.HLE.Exceptions; using System.IO; namespace Ryujinx.HLE.Loaders.Npdm { class ACID { - public byte[] RSA2048Signature; - public byte[] RSA2048Modulus; - public int Unknown1; - public int Flags; + private const int ACIDMagic = 'A' << 0 | 'C' << 8 | 'I' << 16 | 'D' << 24; - public string TitleIdRangeMin; - public string TitleIdRangeMax; + public byte[] RSA2048Signature { get; private set; } + public byte[] RSA2048Modulus { get; private set; } + public int Unknown1 { get; private set; } + public int Flags { get; private set; } - private int FSAccessControlOffset; - private int FSAccessControlSize; - private int ServiceAccessControlOffset; - private int ServiceAccessControlSize; - private int KernelAccessControlOffset; - private int KernelAccessControlSize; + public long TitleIdRangeMin { get; private set; } + public long TitleIdRangeMax { get; private set; } - public FSAccessControl FSAccessControl; - public ServiceAccessControl ServiceAccessControl; - public KernelAccessControl KernelAccessControl; + public FsAccessControl FsAccessControl { get; private set; } + public ServiceAccessControl ServiceAccessControl { get; private set; } + public KernelAccessControl KernelAccessControl { get; private set; } - public const long ACIDMagic = 'A' << 0 | 'C' << 8 | 'I' << 16 | 'D' << 24; - - public ACID(Stream ACIDStream, int Offset) + public ACID(Stream Stream, int Offset) { - ACIDStream.Seek(Offset, SeekOrigin.Begin); + Stream.Seek(Offset, SeekOrigin.Begin); - BinaryReader Reader = new BinaryReader(ACIDStream); + BinaryReader Reader = new BinaryReader(Stream); RSA2048Signature = Reader.ReadBytes(0x100); RSA2048Modulus = Reader.ReadBytes(0x100); @@ -40,28 +33,29 @@ namespace Ryujinx.HLE.Loaders.Npdm throw new InvalidNpdmException("ACID Stream doesn't contain ACID section!"); } - Unknown1 = Reader.ReadInt32(); // Size field used with the above signature(?). - Reader.ReadInt32(); // Padding / Unused - Flags = Reader.ReadInt32(); // Bit0 must be 1 on retail, on devunit 0 is also allowed. Bit1 is unknown. + //Size field used with the above signature (?). + Unknown1 = Reader.ReadInt32(); + + Reader.ReadInt32(); + + //Bit0 must be 1 on retail, on devunit 0 is also allowed. Bit1 is unknown. + Flags = Reader.ReadInt32(); + + TitleIdRangeMin = Reader.ReadInt64(); + TitleIdRangeMax = Reader.ReadInt64(); - byte[] TempTitleIdRangeMin = Reader.ReadBytes(8); - Array.Reverse(TempTitleIdRangeMin); - TitleIdRangeMin = BitConverter.ToString(TempTitleIdRangeMin).Replace("-", ""); + int FsAccessControlOffset = Reader.ReadInt32(); + int FsAccessControlSize = Reader.ReadInt32(); + int ServiceAccessControlOffset = Reader.ReadInt32(); + int ServiceAccessControlSize = Reader.ReadInt32(); + int KernelAccessControlOffset = Reader.ReadInt32(); + int KernelAccessControlSize = Reader.ReadInt32(); - byte[] TempTitleIdRangeMax = Reader.ReadBytes(8); - Array.Reverse(TempTitleIdRangeMax); - TitleIdRangeMax = BitConverter.ToString(TempTitleIdRangeMax).Replace("-", ""); + FsAccessControl = new FsAccessControl(Stream, Offset + FsAccessControlOffset, FsAccessControlSize); - FSAccessControlOffset = Reader.ReadInt32(); - FSAccessControlSize = Reader.ReadInt32(); - ServiceAccessControlOffset = Reader.ReadInt32(); - ServiceAccessControlSize = Reader.ReadInt32(); - KernelAccessControlOffset = Reader.ReadInt32(); - KernelAccessControlSize = Reader.ReadInt32(); + ServiceAccessControl = new ServiceAccessControl(Stream, Offset + ServiceAccessControlOffset, ServiceAccessControlSize); - FSAccessControl = new FSAccessControl(ACIDStream, Offset + FSAccessControlOffset, FSAccessControlSize); - ServiceAccessControl = new ServiceAccessControl(ACIDStream, Offset + ServiceAccessControlOffset, ServiceAccessControlSize); - KernelAccessControl = new KernelAccessControl(ACIDStream, Offset + KernelAccessControlOffset, KernelAccessControlSize); + KernelAccessControl = new KernelAccessControl(Stream, Offset + KernelAccessControlOffset, KernelAccessControlSize); } } } diff --git a/Ryujinx.HLE/Loaders/Npdm/ApplicationType.cs b/Ryujinx.HLE/Loaders/Npdm/ApplicationType.cs new file mode 100644 index 00000000..ad279032 --- /dev/null +++ b/Ryujinx.HLE/Loaders/Npdm/ApplicationType.cs @@ -0,0 +1,9 @@ +namespace Ryujinx.HLE.Loaders.Npdm +{ + enum ApplicationType + { + SystemModule, + Application, + Applet + } +} diff --git a/Ryujinx.HLE/Loaders/Npdm/FSAccessControl.cs b/Ryujinx.HLE/Loaders/Npdm/FSAccessControl.cs deleted file mode 100644 index ca8eac2e..00000000 --- a/Ryujinx.HLE/Loaders/Npdm/FSAccessControl.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System.IO; - -namespace Ryujinx.HLE.Loaders.Npdm -{ - public class FSAccessControl - { - public int Version; - public ulong PermissionsBitmask; - public int Unknown1; - public int Unknown2; - public int Unknown3; - public int Unknown4; - - public FSAccessControl(Stream FSAccessHeaderStream, int Offset, int Size) - { - FSAccessHeaderStream.Seek(Offset, SeekOrigin.Begin); - - BinaryReader Reader = new BinaryReader(FSAccessHeaderStream); - - Version = Reader.ReadInt32(); - PermissionsBitmask = Reader.ReadUInt64(); - Unknown1 = Reader.ReadInt32(); - Unknown2 = Reader.ReadInt32(); - Unknown3 = Reader.ReadInt32(); - Unknown4 = Reader.ReadInt32(); - } - } -} diff --git a/Ryujinx.HLE/Loaders/Npdm/FSAccessHeader.cs b/Ryujinx.HLE/Loaders/Npdm/FSAccessHeader.cs deleted file mode 100644 index 0ba3af73..00000000 --- a/Ryujinx.HLE/Loaders/Npdm/FSAccessHeader.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System.IO; - -namespace Ryujinx.HLE.Loaders.Npdm -{ - public class FSAccessHeader - { - public int Version; - public ulong PermissionsBitmask; - public int DataSize; - public int ContentOwnerIDSize; - public int DataAndContentOwnerIDSize; - - public FSAccessHeader(Stream FSAccessHeaderStream, int Offset, int Size) - { - FSAccessHeaderStream.Seek(Offset, SeekOrigin.Begin); - - BinaryReader Reader = new BinaryReader(FSAccessHeaderStream); - - Version = Reader.ReadInt32(); - PermissionsBitmask = Reader.ReadUInt64(); - DataSize = Reader.ReadInt32(); - - if (DataSize != 0x1C) - { - throw new InvalidNpdmException("FSAccessHeader is corrupted!"); - } - - ContentOwnerIDSize = Reader.ReadInt32(); - DataAndContentOwnerIDSize = Reader.ReadInt32(); - - if (DataAndContentOwnerIDSize != 0x1C) - { - throw new InvalidNpdmException("ContentOwnerID section is not implemented!"); - } - } - } -} diff --git a/Ryujinx.HLE/Loaders/Npdm/FsAccessControl.cs b/Ryujinx.HLE/Loaders/Npdm/FsAccessControl.cs new file mode 100644 index 00000000..00faf321 --- /dev/null +++ b/Ryujinx.HLE/Loaders/Npdm/FsAccessControl.cs @@ -0,0 +1,28 @@ +using System.IO; + +namespace Ryujinx.HLE.Loaders.Npdm +{ + class FsAccessControl + { + public int Version { get; private set; } + public ulong PermissionsBitmask { get; private set; } + public int Unknown1 { get; private set; } + public int Unknown2 { get; private set; } + public int Unknown3 { get; private set; } + public int Unknown4 { get; private set; } + + public FsAccessControl(Stream Stream, int Offset, int Size) + { + Stream.Seek(Offset, SeekOrigin.Begin); + + BinaryReader Reader = new BinaryReader(Stream); + + Version = Reader.ReadInt32(); + PermissionsBitmask = Reader.ReadUInt64(); + Unknown1 = Reader.ReadInt32(); + Unknown2 = Reader.ReadInt32(); + Unknown3 = Reader.ReadInt32(); + Unknown4 = Reader.ReadInt32(); + } + } +} diff --git a/Ryujinx.HLE/Loaders/Npdm/FsAccessHeader.cs b/Ryujinx.HLE/Loaders/Npdm/FsAccessHeader.cs new file mode 100644 index 00000000..50e82309 --- /dev/null +++ b/Ryujinx.HLE/Loaders/Npdm/FsAccessHeader.cs @@ -0,0 +1,37 @@ +using Ryujinx.HLE.Exceptions; +using System; +using System.IO; + +namespace Ryujinx.HLE.Loaders.Npdm +{ + class FsAccessHeader + { + public int Version { get; private set; } + public ulong PermissionsBitmask { get; private set; } + + public FsAccessHeader(Stream Stream, int Offset, int Size) + { + Stream.Seek(Offset, SeekOrigin.Begin); + + BinaryReader Reader = new BinaryReader(Stream); + + Version = Reader.ReadInt32(); + PermissionsBitmask = Reader.ReadUInt64(); + + int DataSize = Reader.ReadInt32(); + + if (DataSize != 0x1c) + { + throw new InvalidNpdmException("FsAccessHeader is corrupted!"); + } + + int ContentOwnerIdSize = Reader.ReadInt32(); + int DataAndContentOwnerIdSize = Reader.ReadInt32(); + + if (DataAndContentOwnerIdSize != 0x1c) + { + throw new NotImplementedException("ContentOwnerId section is not implemented!"); + } + } + } +} diff --git a/Ryujinx.HLE/Loaders/Npdm/FsPermissionBool.cs b/Ryujinx.HLE/Loaders/Npdm/FsPermissionBool.cs new file mode 100644 index 00000000..571b7b5a --- /dev/null +++ b/Ryujinx.HLE/Loaders/Npdm/FsPermissionBool.cs @@ -0,0 +1,33 @@ +namespace Ryujinx.HLE.Loaders.Npdm +{ + enum FsPermissionBool : ulong + { + BisCache = 0x8000000000000080, + EraseMmc = 0x8000000000000080, + GameCardCertificate = 0x8000000000000010, + GameCardIdSet = 0x8000000000000010, + GameCardDriver = 0x8000000000000200, + GameCardAsic = 0x8000000000000200, + SaveDataCreate = 0x8000000000002020, + SaveDataDelete0 = 0x8000000000000060, + SystemSaveDataCreate0 = 0x8000000000000028, + SystemSaveDataCreate1 = 0x8000000000000020, + SaveDataDelete1 = 0x8000000000004028, + SaveDataIterators0 = 0x8000000000000060, + SaveDataIterators1 = 0x8000000000004020, + SaveThumbnails = 0x8000000000020000, + PosixTime = 0x8000000000000400, + SaveDataExtraData = 0x8000000000004060, + GlobalMode = 0x8000000000080000, + SpeedEmulation = 0x8000000000080000, + NULL = 0, + PaddingFiles = 0xC000000000800000, + SaveData_Debug = 0xC000000001000000, + SaveData_SystemManagement = 0xC000000002000000, + Unknown0x16 = 0x8000000004000000, + Unknown0x17 = 0x8000000008000000, + Unknown0x18 = 0x8000000010000000, + Unknown0x19 = 0x8000000000000800, + Unknown0x1A = 0x8000000000004020 + } +} diff --git a/Ryujinx.HLE/Loaders/Npdm/FsPermissionRw.cs b/Ryujinx.HLE/Loaders/Npdm/FsPermissionRw.cs new file mode 100644 index 00000000..ca21279b --- /dev/null +++ b/Ryujinx.HLE/Loaders/Npdm/FsPermissionRw.cs @@ -0,0 +1,45 @@ +namespace Ryujinx.HLE.Loaders.Npdm +{ + enum FsPermissionRw : ulong + { + MountContentType2 = 0x8000000000000801, + MountContentType5 = 0x8000000000000801, + MountContentType3 = 0x8000000000000801, + MountContentType4 = 0x8000000000000801, + MountContentType6 = 0x8000000000000801, + MountContentType7 = 0x8000000000000801, + Unknown0x6 = 0x8000000000000000, + ContentStorageAccess = 0x8000000000000800, + ImageDirectoryAccess = 0x8000000000001000, + MountBisType28 = 0x8000000000000084, + MountBisType29 = 0x8000000000000080, + MountBisType30 = 0x8000000000008080, + MountBisType31 = 0x8000000000008080, + Unknown0xD = 0x8000000000000080, + SdCardAccess = 0xC000000000200000, + GameCardUser = 0x8000000000000010, + SaveDataAccess0 = 0x8000000000040020, + SystemSaveDataAccess0 = 0x8000000000000028, + SaveDataAccess1 = 0x8000000000000020, + SystemSaveDataAccess1 = 0x8000000000000020, + BisPartition0 = 0x8000000000010082, + BisPartition10 = 0x8000000000010080, + BisPartition20 = 0x8000000000010080, + BisPartition21 = 0x8000000000010080, + BisPartition22 = 0x8000000000010080, + BisPartition23 = 0x8000000000010080, + BisPartition24 = 0x8000000000010080, + BisPartition25 = 0x8000000000010080, + BisPartition26 = 0x8000000000000080, + BisPartition27 = 0x8000000000000084, + BisPartition28 = 0x8000000000000084, + BisPartition29 = 0x8000000000000080, + BisPartition30 = 0x8000000000000080, + BisPartition31 = 0x8000000000000080, + BisPartition32 = 0x8000000000000080, + Unknown0x23 = 0xC000000000200000, + GameCard_System = 0x8000000000000100, + MountContent_System = 0x8000000000100008, + HostAccess = 0xC000000000400000 + } +} diff --git a/Ryujinx.HLE/Loaders/Npdm/KernelAccessControl.cs b/Ryujinx.HLE/Loaders/Npdm/KernelAccessControl.cs index 46fad63e..0b45ebfb 100644 --- a/Ryujinx.HLE/Loaders/Npdm/KernelAccessControl.cs +++ b/Ryujinx.HLE/Loaders/Npdm/KernelAccessControl.cs @@ -1,79 +1,40 @@ -using System.Collections.Generic; +using Ryujinx.HLE.Exceptions; +using System; +using System.Collections.ObjectModel; using System.IO; namespace Ryujinx.HLE.Loaders.Npdm { - public class KernelAccessControlIRQ + class KernelAccessControl { - public uint IRQ0; - public uint IRQ1; - } - - public class KernelAccessControlMMIO - { - public ulong Address; - public ulong Size; - public bool IsRO; - public bool IsNormal; - } - - public class KernelAccessControlItems - { - public bool HasKernelFlags; - public uint LowestThreadPriority; - public uint HighestThreadPriority; - public uint LowestCpuId; - public uint HighestCpuId; - - public bool HasSVCFlags; - public int[] SVCsAllowed; - - public List NormalMMIO; - public List PageMMIO; - public List IRQ; - - public bool HasApplicationType; - public int ApplicationType; - - public bool HasKernelVersion; - public int KernelVersionRelease; - - public bool HasHandleTableSize; - public int HandleTableSize; - - public bool HasDebugFlags; - public bool AllowDebug; - public bool ForceDebug; - } - - public class KernelAccessControl - { - public KernelAccessControlItems[] Items; + public ReadOnlyCollection Items; - public KernelAccessControl(Stream FSAccessControlsStream, int Offset, int Size) + public KernelAccessControl(Stream Stream, int Offset, int Size) { - FSAccessControlsStream.Seek(Offset, SeekOrigin.Begin); + Stream.Seek(Offset, SeekOrigin.Begin); - BinaryReader Reader = new BinaryReader(FSAccessControlsStream); + BinaryReader Reader = new BinaryReader(Stream); - Items = new KernelAccessControlItems[Size / 4]; + KernelAccessControlItem[] Items = new KernelAccessControlItem[Size / 4]; - for (int i = 0; i < Size / 4; i++) + for (int Index = 0; Index < Size / 4; Index++) { uint Descriptor = Reader.ReadUInt32(); - if (Descriptor == 0xFFFFFFFF) //Ignore the descriptor + //Ignore the descriptor. + if (Descriptor == 0xffffffff) { continue; } - Items[i] = new KernelAccessControlItems(); + Items[Index] = new KernelAccessControlItem(); int LowBits = 0; while ((Descriptor & 1) != 0) { Descriptor >>= 1; + LowBits++; } @@ -81,128 +42,132 @@ namespace Ryujinx.HLE.Loaders.Npdm switch (LowBits) { - case 3: // Kernel flags + //Kernel flags. + case 3: { - Items[i].HasKernelFlags = true; + Items[Index].HasKernelFlags = true; - Items[i].HighestThreadPriority = Descriptor & 0x3F; - Items[i].LowestThreadPriority = (Descriptor >> 6) & 0x3F; - Items[i].LowestCpuId = (Descriptor >> 12) & 0xFF; - Items[i].HighestCpuId = (Descriptor >> 20) & 0xFF; + Items[Index].HighestThreadPriority = (Descriptor >> 0) & 0x3f; + Items[Index].LowestThreadPriority = (Descriptor >> 6) & 0x3f; + Items[Index].LowestCpuId = (Descriptor >> 12) & 0xff; + Items[Index].HighestCpuId = (Descriptor >> 20) & 0xff; break; } - case 4: // Syscall mask + //Syscall mask. + case 4: { - Items[i].HasSVCFlags = true; + Items[Index].HasSvcFlags = true; - Items[i].SVCsAllowed = new int[0x80]; + Items[Index].AllowedSvcs = new bool[0x80]; int SysCallBase = (int)(Descriptor >> 24) * 0x18; for (int SysCall = 0; SysCall < 0x18 && SysCallBase + SysCall < 0x80; SysCall++) { - Items[i].SVCsAllowed[SysCallBase + SysCall] = (int)Descriptor & 1; + Items[Index].AllowedSvcs[SysCallBase + SysCall] = (Descriptor & 1) != 0; + Descriptor >>= 1; } break; } - case 6: // Map IO/Normal - Never tested. + //Map IO/Normal. + case 6: { - KernelAccessControlMMIO TempNormalMMIO = new KernelAccessControlMMIO - { - Address = (Descriptor & 0xFFFFFF) << 12, - IsRO = (Descriptor >> 24) != 0 - }; + ulong Address = (Descriptor & 0xffffff) << 12; + bool IsRo = (Descriptor >> 24) != 0; - if (i == Size / 4 - 1) + if (Index == Size / 4 - 1) { throw new InvalidNpdmException("Invalid Kernel Access Control Descriptors!"); } Descriptor = Reader.ReadUInt32(); - if ((Descriptor & 0x7F) != 0x3F) + if ((Descriptor & 0x7f) != 0x3f) { throw new InvalidNpdmException("Invalid Kernel Access Control Descriptors!"); } Descriptor >>= 7; - TempNormalMMIO.Size = (Descriptor & 0xFFFFFF) << 12; - TempNormalMMIO.IsNormal = (Descriptor >> 24) != 0; - Items[i].NormalMMIO.Add(TempNormalMMIO); - i++; + ulong MmioSize = (Descriptor & 0xffffff) << 12; + bool IsNormal = (Descriptor >> 24) != 0; + + Items[Index].NormalMmio.Add(new KernelAccessControlMmio(Address, MmioSize, IsRo, IsNormal)); + + Index++; break; } - case 7: // Map Normal Page - Never tested. + //Map Normal Page. + case 7: { - KernelAccessControlMMIO TempPageMMIO = new KernelAccessControlMMIO - { - Address = Descriptor << 12, - Size = 0x1000, - IsRO = false, - IsNormal = false - }; + ulong Address = Descriptor << 12; - Items[i].PageMMIO.Add(TempPageMMIO); + Items[Index].PageMmio.Add(new KernelAccessControlMmio(Address, 0x1000, false, false)); break; } - case 11: // IRQ Pair - Never tested. + //IRQ Pair. + case 11: { - KernelAccessControlIRQ TempIRQ = new KernelAccessControlIRQ - { - IRQ0 = Descriptor & 0x3FF, - IRQ1 = (Descriptor >> 10) & 0x3FF - }; + Items[Index].Irq.Add(new KernelAccessControlIrq( + (Descriptor >> 0) & 0x3ff, + (Descriptor >> 10) & 0x3ff)); break; } - case 13: // App Type + //Application Type. + case 13: { - Items[i].HasApplicationType = true; - Items[i].ApplicationType = (int)Descriptor & 7; + Items[Index].HasApplicationType = true; + + Items[Index].ApplicationType = (int)Descriptor & 7; break; } - case 14: // Kernel Release Version + //Kernel Release Version. + case 14: { - Items[i].HasKernelVersion = true; + Items[Index].HasKernelVersion = true; - Items[i].KernelVersionRelease = (int)Descriptor; + Items[Index].KernelVersionRelease = (int)Descriptor; break; } - case 15: // Handle Table Size + //Handle Table Size. + case 15: { - Items[i].HasHandleTableSize = true; + Items[Index].HasHandleTableSize = true; - Items[i].HandleTableSize = (int)Descriptor; + Items[Index].HandleTableSize = (int)Descriptor; break; } - case 16: // Debug Flags + //Debug Flags. + case 16: { - Items[i].HasDebugFlags = true; + Items[Index].HasDebugFlags = true; - Items[i].AllowDebug = (Descriptor & 1) != 0; - Items[i].ForceDebug = ((Descriptor >> 1) & 1) != 0; + Items[Index].AllowDebug = ((Descriptor >> 0) & 1) != 0; + Items[Index].ForceDebug = ((Descriptor >> 1) & 1) != 0; break; } } } + + this.Items = Array.AsReadOnly(Items); } } } diff --git a/Ryujinx.HLE/Loaders/Npdm/KernelAccessControlIrq.cs b/Ryujinx.HLE/Loaders/Npdm/KernelAccessControlIrq.cs new file mode 100644 index 00000000..63671331 --- /dev/null +++ b/Ryujinx.HLE/Loaders/Npdm/KernelAccessControlIrq.cs @@ -0,0 +1,14 @@ +namespace Ryujinx.HLE.Loaders.Npdm +{ + struct KernelAccessControlIrq + { + public uint Irq0 { get; private set; } + public uint Irq1 { get; private set; } + + public KernelAccessControlIrq(uint Irq0, uint Irq1) + { + this.Irq0 = Irq0; + this.Irq1 = Irq1; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/Loaders/Npdm/KernelAccessControlMmio.cs b/Ryujinx.HLE/Loaders/Npdm/KernelAccessControlMmio.cs new file mode 100644 index 00000000..1ec79c88 --- /dev/null +++ b/Ryujinx.HLE/Loaders/Npdm/KernelAccessControlMmio.cs @@ -0,0 +1,22 @@ +namespace Ryujinx.HLE.Loaders.Npdm +{ + struct KernelAccessControlMmio + { + public ulong Address { get; private set; } + public ulong Size { get; private set; } + public bool IsRo { get; private set; } + public bool IsNormal { get; private set; } + + public KernelAccessControlMmio( + ulong Address, + ulong Size, + bool IsRo, + bool IsNormal) + { + this.Address = Address; + this.Size = Size; + this.IsRo = IsRo; + this.IsNormal = IsNormal; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/Loaders/Npdm/KernelAccessItem.cs b/Ryujinx.HLE/Loaders/Npdm/KernelAccessItem.cs new file mode 100644 index 00000000..42015c3e --- /dev/null +++ b/Ryujinx.HLE/Loaders/Npdm/KernelAccessItem.cs @@ -0,0 +1,33 @@ +using System.Collections.Generic; + +namespace Ryujinx.HLE.Loaders.Npdm +{ + struct KernelAccessControlItem + { + public bool HasKernelFlags { get; set; } + public uint LowestThreadPriority { get; set; } + public uint HighestThreadPriority { get; set; } + public uint LowestCpuId { get; set; } + public uint HighestCpuId { get; set; } + + public bool HasSvcFlags { get; set; } + public bool[] AllowedSvcs { get; set; } + + public List NormalMmio { get; set; } + public List PageMmio { get; set; } + public List Irq { get; set; } + + public bool HasApplicationType { get; set; } + public int ApplicationType { get; set; } + + public bool HasKernelVersion { get; set; } + public int KernelVersionRelease { get; set; } + + public bool HasHandleTableSize { get; set; } + public int HandleTableSize { get; set; } + + public bool HasDebugFlags { get; set; } + public bool AllowDebug { get; set; } + public bool ForceDebug { get; set; } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/Loaders/Npdm/Npdm.cs b/Ryujinx.HLE/Loaders/Npdm/Npdm.cs index eaa662f0..8aacfd99 100644 --- a/Ryujinx.HLE/Loaders/Npdm/Npdm.cs +++ b/Ryujinx.HLE/Loaders/Npdm/Npdm.cs @@ -1,4 +1,5 @@ -using Ryujinx.HLE.OsHle.Utilities; +using Ryujinx.HLE.Exceptions; +using Ryujinx.HLE.Utilities; using System.IO; using System.Text; @@ -9,77 +10,69 @@ namespace Ryujinx.HLE.Loaders.Npdm //http://switchbrew.org/index.php?title=NPDM class Npdm { - public bool Is64Bits; - public int AddressSpaceWidth; - public byte MainThreadPriority; - public byte DefaultCpuId; - public int SystemResourceSize; - public int ProcessCategory; - public int MainEntrypointStackSize; - public string TitleName; - public byte[] ProductCode; - public ulong FSPerms; - - private int ACI0Offset; - private int ACI0Size; - private int ACIDOffset; - private int ACIDSize; - - public ACI0 ACI0; - public ACID ACID; - - public const long NpdmMagic = 'M' << 0 | 'E' << 8 | 'T' << 16 | 'A' << 24; - - public Npdm(Stream NPDMStream) + private const int MetaMagic = 'M' << 0 | 'E' << 8 | 'T' << 16 | 'A' << 24; + + public bool Is64Bits { get; private set; } + public int AddressSpaceWidth { get; private set; } + public byte MainThreadPriority { get; private set; } + public byte DefaultCpuId { get; private set; } + public int SystemResourceSize { get; private set; } + public int ProcessCategory { get; private set; } + public int MainEntrypointStackSize { get; private set; } + public string TitleName { get; private set; } + public byte[] ProductCode { get; private set; } + + public ACI0 ACI0 { get; private set; } + public ACID ACID { get; private set; } + + public Npdm(Stream Stream) { - BinaryReader Reader = new BinaryReader(NPDMStream); + BinaryReader Reader = new BinaryReader(Stream); - if (Reader.ReadInt32() != NpdmMagic) + if (Reader.ReadInt32() != MetaMagic) { throw new InvalidNpdmException("NPDM Stream doesn't contain NPDM file!"); } - Reader.ReadInt64(); // Padding / Unused + Reader.ReadInt64(); + + //MmuFlags, bit0: 64-bit instructions, bits1-3: address space width (1=64-bit, 2=32-bit). Needs to be <= 0xF. + byte MmuFlags = Reader.ReadByte(); - // MmuFlags, bit0: 64-bit instructions, bits1-3: address space width (1=64-bit, 2=32-bit). Needs to be <= 0xF - byte MmuFlags = Reader.ReadByte(); Is64Bits = (MmuFlags & 1) != 0; AddressSpaceWidth = (MmuFlags >> 1) & 7; - Reader.ReadByte(); // Padding / Unused + Reader.ReadByte(); - MainThreadPriority = Reader.ReadByte(); // (0-63) + MainThreadPriority = Reader.ReadByte(); //(0-63). DefaultCpuId = Reader.ReadByte(); - Reader.ReadInt32(); // Padding / Unused + Reader.ReadInt32(); - // System resource size (max size as of 5.x: 534773760). Unknown usage. + //System resource size (max size as of 5.x: 534773760). SystemResourceSize = EndianSwap.Swap32(Reader.ReadInt32()); - // ProcessCategory (0: regular title, 1: kernel built-in). Should be 0 here. + //ProcessCategory (0: regular title, 1: kernel built-in). Should be 0 here. ProcessCategory = EndianSwap.Swap32(Reader.ReadInt32()); - // Main entrypoint stack size - // (Should(?) be page-aligned. In non-nspwn scenarios, values of 0 can also rarely break in Horizon. - // This might be something auto-adapting or a security feature of some sort ?) + //Main entrypoint stack size. MainEntrypointStackSize = Reader.ReadInt32(); byte[] TempTitleName = Reader.ReadBytes(0x10); - TitleName = Encoding.UTF8.GetString(TempTitleName, 0, TempTitleName.Length).Trim('\0'); - ProductCode = Reader.ReadBytes(0x10); // Unknown value + TitleName = Encoding.UTF8.GetString(TempTitleName, 0, TempTitleName.Length).Trim('\0'); - NPDMStream.Seek(0x30, SeekOrigin.Current); // Skip reserved bytes + ProductCode = Reader.ReadBytes(0x10); - ACI0Offset = Reader.ReadInt32(); - ACI0Size = Reader.ReadInt32(); - ACIDOffset = Reader.ReadInt32(); - ACIDSize = Reader.ReadInt32(); + Stream.Seek(0x30, SeekOrigin.Current); - ACI0 = new ACI0(NPDMStream, ACI0Offset); - ACID = new ACID(NPDMStream, ACIDOffset); + int ACI0Offset = Reader.ReadInt32(); + int ACI0Size = Reader.ReadInt32(); + int ACIDOffset = Reader.ReadInt32(); + int ACIDSize = Reader.ReadInt32(); - FSPerms = ACI0.FSAccessHeader.PermissionsBitmask & ACID.FSAccessControl.PermissionsBitmask; + ACI0 = new ACI0(Stream, ACI0Offset); + ACID = new ACID(Stream, ACIDOffset); } } } diff --git a/Ryujinx.HLE/Loaders/Npdm/NpdmException.cs b/Ryujinx.HLE/Loaders/Npdm/NpdmException.cs deleted file mode 100644 index d87a6461..00000000 --- a/Ryujinx.HLE/Loaders/Npdm/NpdmException.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System; - -namespace Ryujinx.HLE.Loaders.Npdm -{ - public class InvalidNpdmException : Exception - { - public InvalidNpdmException(string ExMsg) : base(ExMsg) { } - } -} diff --git a/Ryujinx.HLE/Loaders/Npdm/NpdmInfo.cs b/Ryujinx.HLE/Loaders/Npdm/NpdmInfo.cs deleted file mode 100644 index 72e6b3e2..00000000 --- a/Ryujinx.HLE/Loaders/Npdm/NpdmInfo.cs +++ /dev/null @@ -1,215 +0,0 @@ -namespace Ryujinx.HLE.Loaders.Npdm -{ - enum FSPermissionRW : ulong - { - MountContentType2 = 0x8000000000000801, - MountContentType5 = 0x8000000000000801, - MountContentType3 = 0x8000000000000801, - MountContentType4 = 0x8000000000000801, - MountContentType6 = 0x8000000000000801, - MountContentType7 = 0x8000000000000801, - Unknown0x6 = 0x8000000000000000, - ContentStorageAccess = 0x8000000000000800, - ImageDirectoryAccess = 0x8000000000001000, - MountBisType28 = 0x8000000000000084, - MountBisType29 = 0x8000000000000080, - MountBisType30 = 0x8000000000008080, - MountBisType31 = 0x8000000000008080, - Unknown0xD = 0x8000000000000080, - SdCardAccess = 0xC000000000200000, - GameCardUser = 0x8000000000000010, - SaveDataAccess0 = 0x8000000000040020, - SystemSaveDataAccess0 = 0x8000000000000028, - SaveDataAccess1 = 0x8000000000000020, - SystemSaveDataAccess1 = 0x8000000000000020, - BisPartition0 = 0x8000000000010082, - BisPartition10 = 0x8000000000010080, - BisPartition20 = 0x8000000000010080, - BisPartition21 = 0x8000000000010080, - BisPartition22 = 0x8000000000010080, - BisPartition23 = 0x8000000000010080, - BisPartition24 = 0x8000000000010080, - BisPartition25 = 0x8000000000010080, - BisPartition26 = 0x8000000000000080, - BisPartition27 = 0x8000000000000084, - BisPartition28 = 0x8000000000000084, - BisPartition29 = 0x8000000000000080, - BisPartition30 = 0x8000000000000080, - BisPartition31 = 0x8000000000000080, - BisPartition32 = 0x8000000000000080, - Unknown0x23 = 0xC000000000200000, - GameCard_System = 0x8000000000000100, - MountContent_System = 0x8000000000100008, - HostAccess = 0xC000000000400000 - }; - - enum FSPermissionBool : ulong - { - BisCache = 0x8000000000000080, - EraseMmc = 0x8000000000000080, - GameCardCertificate = 0x8000000000000010, - GameCardIdSet = 0x8000000000000010, - GameCardDriver = 0x8000000000000200, - GameCardAsic = 0x8000000000000200, - SaveDataCreate = 0x8000000000002020, - SaveDataDelete0 = 0x8000000000000060, - SystemSaveDataCreate0 = 0x8000000000000028, - SystemSaveDataCreate1 = 0x8000000000000020, - SaveDataDelete1 = 0x8000000000004028, - SaveDataIterators0 = 0x8000000000000060, - SaveDataIterators1 = 0x8000000000004020, - SaveThumbnails = 0x8000000000020000, - PosixTime = 0x8000000000000400, - SaveDataExtraData = 0x8000000000004060, - GlobalMode = 0x8000000000080000, - SpeedEmulation = 0x8000000000080000, - NULL = 0, - PaddingFiles = 0xC000000000800000, - SaveData_Debug = 0xC000000001000000, - SaveData_SystemManagement = 0xC000000002000000, - Unknown0x16 = 0x8000000004000000, - Unknown0x17 = 0x8000000008000000, - Unknown0x18 = 0x8000000010000000, - Unknown0x19 = 0x8000000000000800, - Unknown0x1A = 0x8000000000004020 - } - - enum NpdmApplicationType - { - SystemModule, - Application, - Applet - } - - enum SvcName - { - svcUnknown0, - svcSetHeapSize, - svcSetMemoryPermission, - svcSetMemoryAttribute, - svcMapMemory, - svcUnmapMemory, - svcQueryMemory, - svcExitProcess, - svcCreateThread, - svcStartThread, - svcExitThread, - svcSleepThread, - svcGetThreadPriority, - svcSetThreadPriority, - svcGetThreadCoreMask, - svcSetThreadCoreMask, - svcGetCurrentProcessorNumber, - svcSignalEvent, - svcClearEvent, - svcMapSharedMemory, - svcUnmapSharedMemory, - svcCreateTransferMemory, - svcCloseHandle, - svcResetSignal, - svcWaitSynchronization, - svcCancelSynchronization, - svcArbitrateLock, - svcArbitrateUnlock, - svcWaitProcessWideKeyAtomic, - svcSignalProcessWideKey, - svcGetSystemTick, - svcConnectToNamedPort, - svcSendSyncRequestLight, - svcSendSyncRequest, - svcSendSyncRequestWithUserBuffer, - svcSendAsyncRequestWithUserBuffer, - svcGetProcessId, - svcGetThreadId, - svcBreak, - svcOutputDebugString, - svcReturnFromException, - svcGetInfo, - svcFlushEntireDataCache, - svcFlushDataCache, - svcMapPhysicalMemory, - svcUnmapPhysicalMemory, - svcGetFutureThreadInfo, - svcGetLastThreadInfo, - svcGetResourceLimitLimitValue, - svcGetResourceLimitCurrentValue, - svcSetThreadActivity, - svcGetThreadContext3, - svcWaitForAddress, - svcSignalToAddress, - svcUnknown1, - svcUnknown2, - svcUnknown3, - svcUnknown4, - svcUnknown5, - svcUnknown6, - svcDumpInfo, - svcDumpInfoNew, - svcUnknown7, - svcUnknown8, - svcCreateSession, - svcAcceptSession, - svcReplyAndReceiveLight, - svcReplyAndReceive, - svcReplyAndReceiveWithUserBuffer, - svcCreateEvent, - svcUnknown9, - svcUnknown10, - svcMapPhysicalMemoryUnsafe, - svcUnmapPhysicalMemoryUnsafe, - svcSetUnsafeLimit, - svcCreateCodeMemory, - svcControlCodeMemory, - svcSleepSystem, - svcReadWriteRegister, - svcSetProcessActivity, - svcCreateSharedMemory, - svcMapTransferMemory, - svcUnmapTransferMemory, - svcCreateInterruptEvent, - svcQueryPhysicalAddress, - svcQueryIoMapping, - svcCreateDeviceAddressSpace, - svcAttachDeviceAddressSpace, - svcDetachDeviceAddressSpace, - svcMapDeviceAddressSpaceByForce, - svcMapDeviceAddressSpaceAligned, - svcMapDeviceAddressSpace, - svcUnmapDeviceAddressSpace, - svcInvalidateProcessDataCache, - svcStoreProcessDataCache, - svcFlushProcessDataCache, - svcDebugActiveProcess, - svcBreakDebugProcess, - svcTerminateDebugProcess, - svcGetDebugEvent, - svcContinueDebugEvent, - svcGetProcessList, - svcGetThreadList, - svcGetDebugThreadContext, - svcSetDebugThreadContext, - svcQueryDebugProcessMemory, - svcReadDebugProcessMemory, - svcWriteDebugProcessMemory, - svcSetHardwareBreakPoint, - svcGetDebugThreadParam, - svcUnknown11, - svcGetSystemInfo, - svcCreatePort, - svcManageNamedPort, - svcConnectToPort, - svcSetProcessMemoryPermission, - svcMapProcessMemory, - svcUnmapProcessMemory, - svcQueryProcessMemory, - svcMapProcessCodeMemory, - svcUnmapProcessCodeMemory, - svcCreateProcess, - svcStartProcess, - svcTerminateProcess, - svcGetProcessInfo, - svcCreateResourceLimit, - svcSetResourceLimitLimitValue, - svcCallSecureMonitor - }; -} diff --git a/Ryujinx.HLE/Loaders/Npdm/ServiceAccessControl.cs b/Ryujinx.HLE/Loaders/Npdm/ServiceAccessControl.cs index ddd7d7ed..910eacb3 100644 --- a/Ryujinx.HLE/Loaders/Npdm/ServiceAccessControl.cs +++ b/Ryujinx.HLE/Loaders/Npdm/ServiceAccessControl.cs @@ -1,34 +1,42 @@ using System.Collections.Generic; +using System.Collections.ObjectModel; using System.IO; using System.Text; namespace Ryujinx.HLE.Loaders.Npdm { - public class ServiceAccessControl + class ServiceAccessControl { - public List<(string, bool)> Services = new List<(string, bool)>(); + public IReadOnlyDictionary Services { get; private set; } - public ServiceAccessControl(Stream ServiceAccessControlStream, int Offset, int Size) + public ServiceAccessControl(Stream Stream, int Offset, int Size) { - ServiceAccessControlStream.Seek(Offset, SeekOrigin.Begin); + Stream.Seek(Offset, SeekOrigin.Begin); - BinaryReader Reader = new BinaryReader(ServiceAccessControlStream); + BinaryReader Reader = new BinaryReader(Stream); int ByteReaded = 0; + Dictionary Services = new Dictionary(); + while (ByteReaded != Size) { byte ControlByte = Reader.ReadByte(); - if (ControlByte == 0x00) break; + if (ControlByte == 0) + { + break; + } - int Length = ((ControlByte & 0x07)) + 1; - bool RegisterAllowed = ((ControlByte & 0x80) != 0); + int Length = ((ControlByte & 0x07)) + 1; + bool RegisterAllowed = ((ControlByte & 0x80) != 0); - Services.Add((Encoding.ASCII.GetString(Reader.ReadBytes(Length), 0, Length), RegisterAllowed)); + Services.Add(Encoding.ASCII.GetString(Reader.ReadBytes(Length), 0, Length), RegisterAllowed); ByteReaded += Length + 1; } + + this.Services = new ReadOnlyDictionary(Services); } } } diff --git a/Ryujinx.HLE/Loaders/Npdm/SvcName.cs b/Ryujinx.HLE/Loaders/Npdm/SvcName.cs new file mode 100644 index 00000000..e519e05e --- /dev/null +++ b/Ryujinx.HLE/Loaders/Npdm/SvcName.cs @@ -0,0 +1,134 @@ +namespace Ryujinx.HLE.Loaders.Npdm +{ + enum SvcName + { + Reserved0, + SetHeapSize, + SetMemoryPermission, + SetMemoryAttribute, + MapMemory, + UnmapMemory, + QueryMemory, + ExitProcess, + CreateThread, + StartThread, + ExitThread, + SleepThread, + GetThreadPriority, + SetThreadPriority, + GetThreadCoreMask, + SetThreadCoreMask, + GetCurrentProcessorNumber, + SignalEvent, + ClearEvent, + MapSharedMemory, + UnmapSharedMemory, + CreateTransferMemory, + CloseHandle, + ResetSignal, + WaitSynchronization, + CancelSynchronization, + ArbitrateLock, + ArbitrateUnlock, + WaitProcessWideKeyAtomic, + SignalProcessWideKey, + GetSystemTick, + ConnectToNamedPort, + SendSyncRequestLight, + SendSyncRequest, + SendSyncRequestWithUserBuffer, + SendAsyncRequestWithUserBuffer, + GetProcessId, + GetThreadId, + Break, + OutputDebugString, + ReturnFromException, + GetInfo, + FlushEntireDataCache, + FlushDataCache, + MapPhysicalMemory, + UnmapPhysicalMemory, + GetFutureThreadInfo, + GetLastThreadInfo, + GetResourceLimitLimitValue, + GetResourceLimitCurrentValue, + SetThreadActivity, + GetThreadContext3, + WaitForAddress, + SignalToAddress, + Reserved1, + Reserved2, + Reserved3, + Reserved4, + Reserved5, + Reserved6, + DumpInfo, + DumpInfoNew, + Reserved7, + Reserved8, + CreateSession, + AcceptSession, + ReplyAndReceiveLight, + ReplyAndReceive, + ReplyAndReceiveWithUserBuffer, + CreateEvent, + Reserved9, + Reserved10, + MapPhysicalMemoryUnsafe, + UnmapPhysicalMemoryUnsafe, + SetUnsafeLimit, + CreateCodeMemory, + ControlCodeMemory, + SleepSystem, + ReadWriteRegister, + SetProcessActivity, + CreateSharedMemory, + MapTransferMemory, + UnmapTransferMemory, + CreateInterruptEvent, + QueryPhysicalAddress, + QueryIoMapping, + CreateDeviceAddressSpace, + AttachDeviceAddressSpace, + DetachDeviceAddressSpace, + MapDeviceAddressSpaceByForce, + MapDeviceAddressSpaceAligned, + MapDeviceAddressSpace, + UnmapDeviceAddressSpace, + InvalidateProcessDataCache, + StoreProcessDataCache, + FlushProcessDataCache, + DebugActiveProcess, + BreakDebugProcess, + TerminateDebugProcess, + GetDebugEvent, + ContinueDebugEvent, + GetProcessList, + GetThreadList, + GetDebugThreadContext, + SetDebugThreadContext, + QueryDebugProcessMemory, + ReadDebugProcessMemory, + WriteDebugProcessMemory, + SetHardwareBreakPoint, + GetDebugThreadParam, + Reserved11, + GetSystemInfo, + CreatePort, + ManageNamedPort, + ConnectToPort, + SetProcessMemoryPermission, + MapProcessMemory, + UnmapProcessMemory, + QueryProcessMemory, + MapProcessCodeMemory, + UnmapProcessCodeMemory, + CreateProcess, + StartProcess, + TerminateProcess, + GetProcessInfo, + CreateResourceLimit, + SetResourceLimitLimitValue, + CallSecureMonitor + } +} diff --git a/Ryujinx.HLE/OsHle/Diagnostics/Demangler.cs b/Ryujinx.HLE/OsHle/Diagnostics/Demangler.cs deleted file mode 100644 index 6646dede..00000000 --- a/Ryujinx.HLE/OsHle/Diagnostics/Demangler.cs +++ /dev/null @@ -1,416 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; - -namespace Ryujinx.HLE.OsHle.Diagnostics -{ - static class Demangler - { - private static readonly Dictionary BuiltinTypes = new Dictionary - { - { "v", "void" }, - { "w", "wchar_t" }, - { "b", "bool" }, - { "c", "char" }, - { "a", "signed char" }, - { "h", "unsigned char" }, - { "s", "short" }, - { "t", "unsigned short" }, - { "i", "int" }, - { "j", "unsigned int" }, - { "l", "long" }, - { "m", "unsigned long" }, - { "x", "long long" }, - { "y", "unsigned long long" }, - { "n", "__int128" }, - { "o", "unsigned __int128" }, - { "f", "float" }, - { "d", "double" }, - { "e", "long double" }, - { "g", "__float128" }, - { "z", "..." }, - { "Dd", "__iec559_double" }, - { "De", "__iec559_float128" }, - { "Df", "__iec559_float" }, - { "Dh", "__iec559_float16" }, - { "Di", "char32_t" }, - { "Ds", "char16_t" }, - { "Da", "decltype(auto)" }, - { "Dn", "std::nullptr_t" }, - }; - - private static readonly Dictionary SubstitutionExtra = new Dictionary - { - {"Sa", "std::allocator"}, - {"Sb", "std::basic_string"}, - {"Ss", "std::basic_string, ::std::allocator>"}, - {"Si", "std::basic_istream>"}, - {"So", "std::basic_ostream>"}, - {"Sd", "std::basic_iostream>"} - }; - - private static int FromBase36(string encoded) - { - string base36 = "0123456789abcdefghijklmnopqrstuvwxyz"; - char[] reversedEncoded = encoded.ToLower().ToCharArray().Reverse().ToArray(); - int result = 0; - for (int i = 0; i < reversedEncoded.Length; i++) - { - char c = reversedEncoded[i]; - int value = base36.IndexOf(c); - if (value == -1) - return -1; - result += value * (int)Math.Pow(36, i); - } - return result; - } - - private static string GetCompressedValue(string compression, List compressionData, out int pos) - { - string res = null; - bool canHaveUnqualifiedName = false; - pos = -1; - if (compressionData.Count == 0 || !compression.StartsWith("S")) - return null; - - if (compression.Length >= 2 && SubstitutionExtra.TryGetValue(compression.Substring(0, 2), out string substitutionValue)) - { - pos = 1; - res = substitutionValue; - compression = compression.Substring(2); - } - else if (compression.StartsWith("St")) - { - pos = 1; - canHaveUnqualifiedName = true; - res = "std"; - compression = compression.Substring(2); - } - else if (compression.StartsWith("S_")) - { - pos = 1; - res = compressionData[0]; - canHaveUnqualifiedName = true; - compression = compression.Substring(2); - } - else - { - int id = -1; - int underscorePos = compression.IndexOf('_'); - if (underscorePos == -1) - return null; - string partialId = compression.Substring(1, underscorePos - 1); - - id = FromBase36(partialId); - if (id == -1 || compressionData.Count <= (id + 1)) - { - return null; - } - res = compressionData[id + 1]; - pos = partialId.Length + 1; - canHaveUnqualifiedName= true; - compression = compression.Substring(pos); - } - if (res != null) - { - if (canHaveUnqualifiedName) - { - List type = ReadName(compression, compressionData, out int endOfNameType); - if (endOfNameType != -1 && type != null) - { - pos += endOfNameType; - res = res + "::" + type[type.Count - 1]; - } - } - } - return res; - } - - private static List ReadName(string mangled, List compressionData, out int pos, bool isNested = true) - { - List res = new List(); - string charCountString = null; - int charCount = 0; - int i; - - pos = -1; - for (i = 0; i < mangled.Length; i++) - { - char chr = mangled[i]; - if (charCountString == null) - { - if (ReadCVQualifiers(chr) != null) - { - continue; - } - if (chr == 'S') - { - string data = GetCompressedValue(mangled.Substring(i), compressionData, out pos); - if (pos == -1) - { - return null; - } - if (res.Count == 0) - res.Add(data); - else - res.Add(res[res.Count - 1] + "::" + data); - i += pos; - if (i < mangled.Length && mangled[i] == 'E') - { - break; - } - continue; - } - else if (chr == 'E') - { - break; - } - } - if (Char.IsDigit(chr)) - { - charCountString += chr; - } - else - { - if (!int.TryParse(charCountString, out charCount)) - { - return null; - } - string demangledPart = mangled.Substring(i, charCount); - if (res.Count == 0) - res.Add(demangledPart); - else - res.Add(res[res.Count - 1] + "::" + demangledPart); - i = i + charCount - 1; - charCount = 0; - charCountString = null; - if (!isNested) - break; - } - } - if (res.Count == 0) - { - return null; - } - pos = i; - return res; - } - - private static string ReadBuiltinType(string mangledType, out int pos) - { - string res = null; - string possibleBuiltinType; - pos = -1; - possibleBuiltinType = mangledType[0].ToString(); - if (!BuiltinTypes.TryGetValue(possibleBuiltinType, out res)) - { - if (mangledType.Length >= 2) - { - // Try to match the first 2 chars if the first call failed - possibleBuiltinType = mangledType.Substring(0, 2); - BuiltinTypes.TryGetValue(possibleBuiltinType, out res); - } - } - if (res != null) - pos = possibleBuiltinType.Length; - return res; - } - - private static string ReadCVQualifiers(char qualifier) - { - if (qualifier == 'r') - return "restricted"; - else if (qualifier == 'V') - return "volatile"; - else if (qualifier == 'K') - return "const"; - return null; - } - - private static string ReadRefQualifiers(char qualifier) - { - if (qualifier == 'R') - return "&"; - else if (qualifier == 'O') - return "&&"; - return null; - } - - private static string ReadSpecialQualifiers(char qualifier) - { - if (qualifier == 'P') - return "*"; - else if (qualifier == 'C') - return "complex"; - else if (qualifier == 'G') - return "imaginary"; - return null; - } - - private static List ReadParameters(string mangledParams, List compressionData, out int pos) - { - List res = new List(); - List refQualifiers = new List(); - string parsedTypePart = null; - string currentRefQualifiers = null; - string currentBuiltinType = null; - string currentSpecialQualifiers = null; - string currentCompressedValue = null; - int i = 0; - pos = -1; - - for (i = 0; i < mangledParams.Length; i++) - { - if (currentBuiltinType != null) - { - string currentCVQualifier = String.Join(" ", refQualifiers); - // Try to mimic the compression indexing - if (currentRefQualifiers != null) - { - compressionData.Add(currentBuiltinType + currentRefQualifiers); - } - if (refQualifiers.Count != 0) - { - compressionData.Add(currentBuiltinType + " " + currentCVQualifier + currentRefQualifiers); - } - if (currentSpecialQualifiers != null) - { - compressionData.Add(currentBuiltinType + " " + currentCVQualifier + currentRefQualifiers + currentSpecialQualifiers); - } - if (currentRefQualifiers == null && currentCVQualifier == null && currentSpecialQualifiers == null) - { - compressionData.Add(currentBuiltinType); - } - currentBuiltinType = null; - currentCompressedValue = null; - currentCVQualifier = null; - currentRefQualifiers = null; - refQualifiers.Clear(); - currentSpecialQualifiers = null; - } - char chr = mangledParams[i]; - string part = mangledParams.Substring(i); - - // Try to read qualifiers - parsedTypePart = ReadCVQualifiers(chr); - if (parsedTypePart != null) - { - refQualifiers.Add(parsedTypePart); - - // need more data - continue; - } - - parsedTypePart = ReadRefQualifiers(chr); - if (parsedTypePart != null) - { - currentRefQualifiers = parsedTypePart; - - // need more data - continue; - } - - parsedTypePart = ReadSpecialQualifiers(chr); - if (parsedTypePart != null) - { - currentSpecialQualifiers = parsedTypePart; - - // need more data - continue; - } - - // TODO: extended-qualifier? - - if (part.StartsWith("S")) - { - parsedTypePart = GetCompressedValue(part, compressionData, out pos); - if (pos != -1 && parsedTypePart != null) - { - currentCompressedValue = parsedTypePart; - i += pos; - res.Add(currentCompressedValue + " " + String.Join(" ", refQualifiers) + currentRefQualifiers + currentSpecialQualifiers); - currentBuiltinType = null; - currentCompressedValue = null; - currentRefQualifiers = null; - refQualifiers.Clear(); - currentSpecialQualifiers = null; - continue; - } - pos = -1; - return null; - } - else if (part.StartsWith("N")) - { - part = part.Substring(1); - List name = ReadName(part, compressionData, out pos); - if (pos != -1 && name != null) - { - i += pos + 1; - res.Add(name[name.Count - 1] + " " + String.Join(" ", refQualifiers) + currentRefQualifiers + currentSpecialQualifiers); - currentBuiltinType = null; - currentCompressedValue = null; - currentRefQualifiers = null; - refQualifiers.Clear(); - currentSpecialQualifiers = null; - continue; - } - } - - // Try builting - parsedTypePart = ReadBuiltinType(part, out pos); - if (pos == -1) - { - return null; - } - currentBuiltinType = parsedTypePart; - res.Add(currentBuiltinType + " " + String.Join(" ", refQualifiers) + currentRefQualifiers + currentSpecialQualifiers); - i = i + pos -1; - } - pos = i; - return res; - } - - private static string ParseFunctionName(string mangled) - { - List compressionData = new List(); - int pos = 0; - string res; - bool isNested = mangled.StartsWith("N"); - - // If it's start with "N" it must be a nested function name - if (isNested) - mangled = mangled.Substring(1); - compressionData = ReadName(mangled, compressionData, out pos, isNested); - if (pos == -1) - return null; - res = compressionData[compressionData.Count - 1]; - compressionData.Remove(res); - mangled = mangled.Substring(pos + 1); - - // more data? maybe not a data name so... - if (mangled != String.Empty) - { - List parameters = ReadParameters(mangled, compressionData, out pos); - // parameters parsing error, we return the original data to avoid information loss. - if (pos == -1) - return null; - parameters = parameters.Select(outer => outer.Trim()).ToList(); - res += "(" + String.Join(", ", parameters) + ")"; - } - return res; - } - - public static string Parse(string originalMangled) - { - if (originalMangled.StartsWith("_Z")) - { - // We assume that we have a name (TOOD: support special names) - string res = ParseFunctionName(originalMangled.Substring(2)); - if (res == null) - return originalMangled; - return res; - } - return originalMangled; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/ErrorCode.cs b/Ryujinx.HLE/OsHle/ErrorCode.cs deleted file mode 100644 index 1e07f9b2..00000000 --- a/Ryujinx.HLE/OsHle/ErrorCode.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Ryujinx.HLE.OsHle -{ - static class ErrorCode - { - public static uint MakeError(ErrorModule Module, int Code) - { - return (uint)Module | ((uint)Code << 9); - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/ErrorModule.cs b/Ryujinx.HLE/OsHle/ErrorModule.cs deleted file mode 100644 index 924ee951..00000000 --- a/Ryujinx.HLE/OsHle/ErrorModule.cs +++ /dev/null @@ -1,101 +0,0 @@ -namespace Ryujinx.HLE.OsHle -{ - enum ErrorModule - { - Kernel = 1, - Fs = 2, - Os = 3, // (Memory, Thread, Mutex, NVIDIA) - Htcs = 4, - Ncm = 5, - Dd = 6, - Debug_Monitor = 7, - Lr = 8, - Loader = 9, - IPC_Command_Interface = 10, - IPC = 11, - Pm = 15, - Ns = 16, - Socket = 17, - Htc = 18, - Ncm_Content = 20, - Sm = 21, - RO_Userland = 22, - SdMmc = 24, - Ovln = 25, - Spl = 26, - Ethc = 100, - I2C = 101, - Gpio = 102, - Uart = 103, - Settings = 105, - Wlan = 107, - Xcd = 108, - Nifm = 110, - Hwopus = 111, - Bluetooth = 113, - Vi = 114, - Nfp = 115, - Time = 116, - Fgm = 117, - Oe = 118, - Pcie = 120, - Friends = 121, - Bcat = 122, - SSL = 123, - Account = 124, - News = 125, - Mii = 126, - Nfc = 127, - Am = 128, - Play_Report = 129, - Ahid = 130, - Qlaunch = 132, - Pcv = 133, - Omm = 134, - Bpc = 135, - Psm = 136, - Nim = 137, - Psc = 138, - Tc = 139, - Usb = 140, - Nsd = 141, - Pctl = 142, - Btm = 143, - Ec = 144, - ETicket = 145, - Ngc = 146, - Error_Report = 147, - Apm = 148, - Profiler = 150, - Error_Upload = 151, - Audio = 153, - Npns = 154, - Npns_Http_Stream = 155, - Arp = 157, - Swkbd = 158, - Boot = 159, - Nfc_Mifare = 161, - Userland_Assert = 162, - Fatal = 163, - Nim_Shop = 164, - Spsm = 165, - Bgtc = 167, - Userland_Crash = 168, - SRepo = 180, - Dauth = 181, - Hid = 202, - Ldn = 203, - Irsensor = 205, - Capture = 206, - Manu = 208, - Atk = 209, - Web = 210, - Grc = 212, - Migration = 216, - Migration_Ldc_Server = 217, - General_Web_Applet = 800, - Wifi_Web_Auth_Applet = 809, - Whitelisted_Applet = 810, - ShopN = 811 - } -} diff --git a/Ryujinx.HLE/OsHle/Exceptions/GuestBrokeExecutionException.cs b/Ryujinx.HLE/OsHle/Exceptions/GuestBrokeExecutionException.cs deleted file mode 100644 index 2ed7f19e..00000000 --- a/Ryujinx.HLE/OsHle/Exceptions/GuestBrokeExecutionException.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System; - -namespace Ryujinx.HLE.OsHle.Exceptions -{ - public class GuestBrokeExecutionException : Exception - { - private const string ExMsg = "The guest program broke execution!"; - - public GuestBrokeExecutionException() : base(ExMsg) { } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Exceptions/UndefinedInstructionException.cs b/Ryujinx.HLE/OsHle/Exceptions/UndefinedInstructionException.cs deleted file mode 100644 index d9f0b8cf..00000000 --- a/Ryujinx.HLE/OsHle/Exceptions/UndefinedInstructionException.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; - -namespace Ryujinx.HLE.OsHle.Exceptions -{ - public class UndefinedInstructionException : Exception - { - private const string ExMsg = "The instruction at 0x{0:x16} (opcode 0x{1:x8}) is undefined!"; - - public UndefinedInstructionException() : base() { } - - public UndefinedInstructionException(long Position, int OpCode) : base(string.Format(ExMsg, Position, OpCode)) { } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Font/SharedFontManager.cs b/Ryujinx.HLE/OsHle/Font/SharedFontManager.cs deleted file mode 100644 index 12b6973e..00000000 --- a/Ryujinx.HLE/OsHle/Font/SharedFontManager.cs +++ /dev/null @@ -1,122 +0,0 @@ -using Ryujinx.HLE.Memory; -using Ryujinx.HLE.OsHle.Utilities; -using Ryujinx.HLE.Resource; -using System.Collections.Generic; -using System.IO; - -namespace Ryujinx.HLE.OsHle.Font -{ - class SharedFontManager - { - private DeviceMemory Memory; - - private long PhysicalAddress; - - private string FontsPath; - - private struct FontInfo - { - public int Offset; - public int Size; - - public FontInfo(int Offset, int Size) - { - this.Offset = Offset; - this.Size = Size; - } - } - - private Dictionary FontData; - - public SharedFontManager(Switch Device, long PhysicalAddress) - { - this.PhysicalAddress = PhysicalAddress; - - Memory = Device.Memory; - - FontsPath = Path.Combine(Device.VFs.GetSystemPath(), "fonts"); - } - - public void EnsureInitialized() - { - if (FontData == null) - { - Memory.FillWithZeros(PhysicalAddress, Horizon.FontSize); - - uint FontOffset = 0; - - FontInfo CreateFont(string Name) - { - string FontFilePath = Path.Combine(FontsPath, Name + ".ttf"); - - if (File.Exists(FontFilePath)) - { - byte[] Data = File.ReadAllBytes(FontFilePath); - - FontInfo Info = new FontInfo((int)FontOffset, Data.Length); - - WriteMagicAndSize(PhysicalAddress + FontOffset, Data.Length); - - FontOffset += 8; - - uint Start = FontOffset; - - for (; FontOffset - Start < Data.Length; FontOffset++) - { - Memory.WriteByte(PhysicalAddress + FontOffset, Data[FontOffset - Start]); - } - - return Info; - } - else - { - throw new InvalidSystemResourceException($"Font \"{Name}.ttf\" not found. Please provide it in \"{FontsPath}\"."); - } - } - - FontData = new Dictionary() - { - { SharedFontType.JapanUsEurope, CreateFont("FontStandard") }, - { SharedFontType.SimplifiedChinese, CreateFont("FontChineseSimplified") }, - { SharedFontType.SimplifiedChineseEx, CreateFont("FontExtendedChineseSimplified") }, - { SharedFontType.TraditionalChinese, CreateFont("FontChineseTraditional") }, - { SharedFontType.Korean, CreateFont("FontKorean") }, - { SharedFontType.NintendoEx, CreateFont("FontNintendoExtended") } - }; - - if (FontOffset > Horizon.FontSize) - { - throw new InvalidSystemResourceException( - $"The sum of all fonts size exceed the shared memory size. " + - $"Please make sure that the fonts don't exceed {Horizon.FontSize} bytes in total. " + - $"(actual size: {FontOffset} bytes)."); - } - } - } - - private void WriteMagicAndSize(long Position, int Size) - { - const int DecMagic = 0x18029a7f; - const int Key = 0x49621806; - - int EncryptedSize = EndianSwap.Swap32(Size ^ Key); - - Memory.WriteInt32(Position + 0, DecMagic); - Memory.WriteInt32(Position + 4, EncryptedSize); - } - - public int GetFontSize(SharedFontType FontType) - { - EnsureInitialized(); - - return FontData[FontType].Size; - } - - public int GetSharedMemoryAddressOffset(SharedFontType FontType) - { - EnsureInitialized(); - - return FontData[FontType].Offset + 8; - } - } -} diff --git a/Ryujinx.HLE/OsHle/Font/SharedFontType.cs b/Ryujinx.HLE/OsHle/Font/SharedFontType.cs deleted file mode 100644 index 80f42a7d..00000000 --- a/Ryujinx.HLE/OsHle/Font/SharedFontType.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace Ryujinx.HLE.OsHle.Font -{ - public enum SharedFontType - { - JapanUsEurope = 0, - SimplifiedChinese = 1, - SimplifiedChineseEx = 2, - TraditionalChinese = 3, - Korean = 4, - NintendoEx = 5, - Count - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/GlobalStateTable.cs b/Ryujinx.HLE/OsHle/GlobalStateTable.cs deleted file mode 100644 index fb71e46b..00000000 --- a/Ryujinx.HLE/OsHle/GlobalStateTable.cs +++ /dev/null @@ -1,69 +0,0 @@ -using System.Collections.Concurrent; -using System.Collections.Generic; - -namespace Ryujinx.HLE.OsHle -{ - class GlobalStateTable - { - private ConcurrentDictionary DictByProcess; - - public GlobalStateTable() - { - DictByProcess = new ConcurrentDictionary(); - } - - public bool Add(Process Process, int Id, object Data) - { - IdDictionary Dict = DictByProcess.GetOrAdd(Process, (Key) => new IdDictionary()); - - return Dict.Add(Id, Data); - } - - public int Add(Process Process, object Data) - { - IdDictionary Dict = DictByProcess.GetOrAdd(Process, (Key) => new IdDictionary()); - - return Dict.Add(Data); - } - - public object GetData(Process Process, int Id) - { - if (DictByProcess.TryGetValue(Process, out IdDictionary Dict)) - { - return Dict.GetData(Id); - } - - return null; - } - - public T GetData(Process Process, int Id) - { - if (DictByProcess.TryGetValue(Process, out IdDictionary Dict)) - { - return Dict.GetData(Id); - } - - return default(T); - } - - public object Delete(Process Process, int Id) - { - if (DictByProcess.TryGetValue(Process, out IdDictionary Dict)) - { - return Dict.Delete(Id); - } - - return null; - } - - public ICollection DeleteProcess(Process Process) - { - if (DictByProcess.TryRemove(Process, out IdDictionary Dict)) - { - return Dict.Clear(); - } - - return null; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Handles/AddressSpaceType.cs b/Ryujinx.HLE/OsHle/Handles/AddressSpaceType.cs deleted file mode 100644 index 946c51e1..00000000 --- a/Ryujinx.HLE/OsHle/Handles/AddressSpaceType.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Ryujinx.HLE.OsHle.Handles -{ - enum AddressSpaceType - { - Addr32Bits = 0, - Addr36Bits = 1, - Addr36BitsNoMap = 2, - Addr39Bits = 3 - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Handles/KEvent.cs b/Ryujinx.HLE/OsHle/Handles/KEvent.cs deleted file mode 100644 index df5108f9..00000000 --- a/Ryujinx.HLE/OsHle/Handles/KEvent.cs +++ /dev/null @@ -1,4 +0,0 @@ -namespace Ryujinx.HLE.OsHle.Handles -{ - class KEvent : KSynchronizationObject { } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Handles/KMemoryBlock.cs b/Ryujinx.HLE/OsHle/Handles/KMemoryBlock.cs deleted file mode 100644 index e33b6cb9..00000000 --- a/Ryujinx.HLE/OsHle/Handles/KMemoryBlock.cs +++ /dev/null @@ -1,43 +0,0 @@ -namespace Ryujinx.HLE.OsHle.Handles -{ - class KMemoryBlock - { - public long BasePosition { get; set; } - public long PagesCount { get; set; } - - public MemoryState State { get; set; } - public MemoryPermission Permission { get; set; } - public MemoryAttribute Attribute { get; set; } - - public int IpcRefCount { get; set; } - public int DeviceRefCount { get; set; } - - public KMemoryBlock( - long BasePosition, - long PagesCount, - MemoryState State, - MemoryPermission Permission, - MemoryAttribute Attribute) - { - this.BasePosition = BasePosition; - this.PagesCount = PagesCount; - this.State = State; - this.Attribute = Attribute; - this.Permission = Permission; - } - - public KMemoryInfo GetInfo() - { - long Size = PagesCount * KMemoryManager.PageSize; - - return new KMemoryInfo( - BasePosition, - Size, - State, - Permission, - Attribute, - IpcRefCount, - DeviceRefCount); - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Handles/KMemoryInfo.cs b/Ryujinx.HLE/OsHle/Handles/KMemoryInfo.cs deleted file mode 100644 index 3f79f000..00000000 --- a/Ryujinx.HLE/OsHle/Handles/KMemoryInfo.cs +++ /dev/null @@ -1,33 +0,0 @@ -namespace Ryujinx.HLE.OsHle.Handles -{ - class KMemoryInfo - { - public long Position { get; private set; } - public long Size { get; private set; } - - public MemoryState State { get; private set; } - public MemoryPermission Permission { get; private set; } - public MemoryAttribute Attribute { get; private set; } - - public int IpcRefCount { get; private set; } - public int DeviceRefCount { get; private set; } - - public KMemoryInfo( - long Position, - long Size, - MemoryState State, - MemoryPermission Permission, - MemoryAttribute Attribute, - int IpcRefCount, - int DeviceRefCount) - { - this.Position = Position; - this.Size = Size; - this.State = State; - this.Attribute = Attribute; - this.Permission = Permission; - this.IpcRefCount = IpcRefCount; - this.DeviceRefCount = DeviceRefCount; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Handles/KMemoryManager.cs b/Ryujinx.HLE/OsHle/Handles/KMemoryManager.cs deleted file mode 100644 index 76c5a53d..00000000 --- a/Ryujinx.HLE/OsHle/Handles/KMemoryManager.cs +++ /dev/null @@ -1,1082 +0,0 @@ -using ChocolArm64.Memory; -using Ryujinx.HLE.Memory; -using Ryujinx.HLE.OsHle.Kernel; -using System; -using System.Collections.Generic; - -using static Ryujinx.HLE.OsHle.ErrorCode; - -namespace Ryujinx.HLE.OsHle.Handles -{ - class KMemoryManager - { - public const int PageSize = 0x1000; - - private LinkedList Blocks; - - private AMemory CpuMemory; - - private ArenaAllocator Allocator; - - public long AddrSpaceStart { get; private set; } - public long AddrSpaceEnd { get; private set; } - - public long CodeRegionStart { get; private set; } - public long CodeRegionEnd { get; private set; } - - public long MapRegionStart { get; private set; } - public long MapRegionEnd { get; private set; } - - public long HeapRegionStart { get; private set; } - public long HeapRegionEnd { get; private set; } - - public long NewMapRegionStart { get; private set; } - public long NewMapRegionEnd { get; private set; } - - public long TlsIoRegionStart { get; private set; } - public long TlsIoRegionEnd { get; private set; } - - public long PersonalMmHeapUsage { get; private set; } - - private long CurrentHeapAddr; - - public KMemoryManager(Process Process) - { - CpuMemory = Process.Memory; - Allocator = Process.Ns.Memory.Allocator; - - long CodeRegionSize; - long MapRegionSize; - long HeapRegionSize; - long NewMapRegionSize; - long TlsIoRegionSize; - int AddrSpaceWidth; - - AddressSpaceType AddrType = AddressSpaceType.Addr39Bits; - - if (Process.MetaData != null) - { - AddrType = (AddressSpaceType)Process.MetaData.AddressSpaceWidth; - } - - switch (AddrType) - { - case AddressSpaceType.Addr32Bits: - CodeRegionStart = 0x200000; - CodeRegionSize = 0x3fe00000; - MapRegionSize = 0x40000000; - HeapRegionSize = 0x40000000; - NewMapRegionSize = 0; - TlsIoRegionSize = 0; - AddrSpaceWidth = 32; - break; - - case AddressSpaceType.Addr36Bits: - CodeRegionStart = 0x8000000; - CodeRegionSize = 0x78000000; - MapRegionSize = 0x180000000; - HeapRegionSize = 0x180000000; - NewMapRegionSize = 0; - TlsIoRegionSize = 0; - AddrSpaceWidth = 36; - break; - - case AddressSpaceType.Addr36BitsNoMap: - CodeRegionStart = 0x200000; - CodeRegionSize = 0x3fe00000; - MapRegionSize = 0; - HeapRegionSize = 0x80000000; - NewMapRegionSize = 0; - TlsIoRegionSize = 0; - AddrSpaceWidth = 36; - break; - - case AddressSpaceType.Addr39Bits: - CodeRegionStart = 0; - CodeRegionSize = 0x80000000; - MapRegionSize = 0x1000000000; - HeapRegionSize = 0x180000000; - NewMapRegionSize = 0x80000000; - TlsIoRegionSize = 0x1000000000; - AddrSpaceWidth = 39; - break; - - default: throw new InvalidOperationException(); - } - - AddrSpaceStart = 0; - AddrSpaceEnd = 1L << AddrSpaceWidth; - - CodeRegionEnd = CodeRegionStart + CodeRegionSize; - MapRegionStart = CodeRegionEnd; - MapRegionEnd = CodeRegionEnd + MapRegionSize; - HeapRegionStart = MapRegionEnd; - HeapRegionEnd = MapRegionEnd + HeapRegionSize; - NewMapRegionStart = HeapRegionEnd; - NewMapRegionEnd = HeapRegionEnd + NewMapRegionSize; - TlsIoRegionStart = NewMapRegionEnd; - TlsIoRegionEnd = NewMapRegionEnd + TlsIoRegionSize; - - CurrentHeapAddr = HeapRegionStart; - - if (NewMapRegionSize == 0) - { - NewMapRegionStart = AddrSpaceStart; - NewMapRegionEnd = AddrSpaceEnd; - } - - Blocks = new LinkedList(); - - long AddrSpacePagesCount = (AddrSpaceEnd - AddrSpaceStart) / PageSize; - - InsertBlock(AddrSpaceStart, AddrSpacePagesCount, MemoryState.Unmapped); - } - - public void HleMapProcessCode(long Position, long Size) - { - long PagesCount = Size / PageSize; - - if (!Allocator.TryAllocate(Size, out long PA)) - { - throw new InvalidOperationException(); - } - - lock (Blocks) - { - InsertBlock(Position, PagesCount, MemoryState.CodeStatic, MemoryPermission.ReadAndExecute); - - CpuMemory.Map(Position, PA, Size); - } - } - - public void HleMapCustom(long Position, long Size, MemoryState State, MemoryPermission Permission) - { - long PagesCount = Size / PageSize; - - if (!Allocator.TryAllocate(Size, out long PA)) - { - throw new InvalidOperationException(); - } - - lock (Blocks) - { - InsertBlock(Position, PagesCount, State, Permission); - - CpuMemory.Map(Position, PA, Size); - } - } - - public long HleMapTlsPage() - { - bool HasTlsIoRegion = TlsIoRegionStart != TlsIoRegionEnd; - - long Position = HasTlsIoRegion ? TlsIoRegionStart : CodeRegionStart; - - lock (Blocks) - { - while (Position < (HasTlsIoRegion ? TlsIoRegionEnd : CodeRegionEnd)) - { - if (FindBlock(Position).State == MemoryState.Unmapped) - { - InsertBlock(Position, 1, MemoryState.ThreadLocal, MemoryPermission.ReadAndWrite); - - if (!Allocator.TryAllocate(PageSize, out long PA)) - { - throw new InvalidOperationException(); - } - - CpuMemory.Map(Position, PA, PageSize); - - return Position; - } - - Position += PageSize; - } - - throw new InvalidOperationException(); - } - } - - public long TrySetHeapSize(long Size, out long Position) - { - Position = 0; - - if ((ulong)Size > (ulong)(HeapRegionEnd - HeapRegionStart)) - { - return MakeError(ErrorModule.Kernel, KernelErr.OutOfMemory); - } - - bool Success = false; - - long CurrentHeapSize = GetHeapSize(); - - if ((ulong)CurrentHeapSize <= (ulong)Size) - { - //Expand. - long DiffSize = Size - CurrentHeapSize; - - lock (Blocks) - { - if (Success = IsUnmapped(CurrentHeapAddr, DiffSize)) - { - if (!Allocator.TryAllocate(DiffSize, out long PA)) - { - return MakeError(ErrorModule.Kernel, KernelErr.OutOfMemory); - } - - long PagesCount = DiffSize / PageSize; - - InsertBlock(CurrentHeapAddr, PagesCount, MemoryState.Heap, MemoryPermission.ReadAndWrite); - - CpuMemory.Map(CurrentHeapAddr, PA, DiffSize); - } - } - } - else - { - //Shrink. - long FreeAddr = HeapRegionStart + Size; - long DiffSize = CurrentHeapSize - Size; - - lock (Blocks) - { - Success = CheckRange( - FreeAddr, - DiffSize, - MemoryState.Mask, - MemoryState.Heap, - MemoryPermission.Mask, - MemoryPermission.ReadAndWrite, - MemoryAttribute.Mask, - MemoryAttribute.None, - MemoryAttribute.IpcAndDeviceMapped, - out _, - out _, - out _); - - if (Success) - { - long PagesCount = DiffSize / PageSize; - - InsertBlock(FreeAddr, PagesCount, MemoryState.Unmapped); - - CpuMemory.Unmap(FreeAddr, DiffSize); - - FreePages(FreeAddr, PagesCount); - } - } - } - - CurrentHeapAddr = HeapRegionStart + Size; - - if (Success) - { - Position = HeapRegionStart; - - return 0; - } - - return MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); - } - - public long GetHeapSize() - { - return CurrentHeapAddr - HeapRegionStart; - } - - public long SetMemoryAttribute( - long Position, - long Size, - MemoryAttribute AttributeMask, - MemoryAttribute AttributeValue) - { - lock (Blocks) - { - if (CheckRange( - Position, - Size, - MemoryState.AttributeChangeAllowed, - MemoryState.AttributeChangeAllowed, - MemoryPermission.None, - MemoryPermission.None, - MemoryAttribute.BorrowedAndIpcMapped, - MemoryAttribute.None, - MemoryAttribute.DeviceMappedAndUncached, - out MemoryState State, - out MemoryPermission Permission, - out MemoryAttribute Attribute)) - { - long PagesCount = Size / PageSize; - - Attribute &= ~AttributeMask; - Attribute |= AttributeMask & AttributeValue; - - InsertBlock(Position, PagesCount, State, Permission, Attribute); - - return 0; - } - } - - return MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); - } - - public KMemoryInfo QueryMemory(long Position) - { - if ((ulong)Position >= (ulong)AddrSpaceStart && - (ulong)Position < (ulong)AddrSpaceEnd) - { - lock (Blocks) - { - return FindBlock(Position).GetInfo(); - } - } - else - { - return new KMemoryInfo( - AddrSpaceEnd, - -AddrSpaceEnd, - MemoryState.Reserved, - MemoryPermission.None, - MemoryAttribute.None, - 0, - 0); - } - } - - public long Map(long Src, long Dst, long Size) - { - bool Success; - - lock (Blocks) - { - Success = CheckRange( - Src, - Size, - MemoryState.MapAllowed, - MemoryState.MapAllowed, - MemoryPermission.Mask, - MemoryPermission.ReadAndWrite, - MemoryAttribute.Mask, - MemoryAttribute.None, - MemoryAttribute.IpcAndDeviceMapped, - out MemoryState SrcState, - out _, - out _); - - Success &= IsUnmapped(Dst, Size); - - if (Success) - { - long PagesCount = Size / PageSize; - - InsertBlock(Src, PagesCount, SrcState, MemoryPermission.None, MemoryAttribute.Borrowed); - - InsertBlock(Dst, PagesCount, MemoryState.MappedMemory, MemoryPermission.ReadAndWrite); - - long PA = CpuMemory.GetPhysicalAddress(Src); - - CpuMemory.Map(Dst, PA, Size); - } - } - - return Success ? 0 : MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); - } - - public long Unmap(long Src, long Dst, long Size) - { - bool Success; - - lock (Blocks) - { - Success = CheckRange( - Src, - Size, - MemoryState.MapAllowed, - MemoryState.MapAllowed, - MemoryPermission.Mask, - MemoryPermission.None, - MemoryAttribute.Mask, - MemoryAttribute.Borrowed, - MemoryAttribute.IpcAndDeviceMapped, - out MemoryState SrcState, - out _, - out _); - - Success &= CheckRange( - Dst, - Size, - MemoryState.Mask, - MemoryState.MappedMemory, - MemoryPermission.None, - MemoryPermission.None, - MemoryAttribute.Mask, - MemoryAttribute.None, - MemoryAttribute.IpcAndDeviceMapped, - out _, - out _, - out _); - - if (Success) - { - long PagesCount = Size / PageSize; - - InsertBlock(Src, PagesCount, SrcState, MemoryPermission.ReadAndWrite); - - InsertBlock(Dst, PagesCount, MemoryState.Unmapped); - - CpuMemory.Unmap(Dst, Size); - } - } - - return Success ? 0 : MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); - } - - public long MapSharedMemory(KSharedMemory SharedMemory, MemoryPermission Permission, long Position) - { - lock (Blocks) - { - if (IsUnmapped(Position, SharedMemory.Size)) - { - long PagesCount = SharedMemory.Size / PageSize; - - InsertBlock(Position, PagesCount, MemoryState.SharedMemory, Permission); - - CpuMemory.Map(Position, SharedMemory.PA, SharedMemory.Size); - - return 0; - } - } - - return MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); - } - - public long UnmapSharedMemory(long Position, long Size) - { - lock (Blocks) - { - if (CheckRange( - Position, - Size, - MemoryState.Mask, - MemoryState.SharedMemory, - MemoryPermission.None, - MemoryPermission.None, - MemoryAttribute.Mask, - MemoryAttribute.None, - MemoryAttribute.IpcAndDeviceMapped, - out MemoryState State, - out _, - out _)) - { - long PagesCount = Size / PageSize; - - InsertBlock(Position, PagesCount, MemoryState.Unmapped); - - CpuMemory.Unmap(Position, Size); - - return 0; - } - } - - return MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); - } - - public long ReserveTransferMemory(long Position, long Size, MemoryPermission Permission) - { - lock (Blocks) - { - if (CheckRange( - Position, - Size, - MemoryState.TransferMemoryAllowed | MemoryState.IsPoolAllocated, - MemoryState.TransferMemoryAllowed | MemoryState.IsPoolAllocated, - MemoryPermission.Mask, - MemoryPermission.ReadAndWrite, - MemoryAttribute.Mask, - MemoryAttribute.None, - MemoryAttribute.IpcAndDeviceMapped, - out MemoryState State, - out _, - out MemoryAttribute Attribute)) - { - long PagesCount = Size / PageSize; - - Attribute |= MemoryAttribute.Borrowed; - - InsertBlock(Position, PagesCount, State, Permission, Attribute); - - return 0; - } - } - - return MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); - } - - public long ResetTransferMemory(long Position, long Size) - { - lock (Blocks) - { - if (CheckRange( - Position, - Size, - MemoryState.TransferMemoryAllowed | MemoryState.IsPoolAllocated, - MemoryState.TransferMemoryAllowed | MemoryState.IsPoolAllocated, - MemoryPermission.None, - MemoryPermission.None, - MemoryAttribute.Mask, - MemoryAttribute.Borrowed, - MemoryAttribute.IpcAndDeviceMapped, - out MemoryState State, - out _, - out _)) - { - long PagesCount = Size / PageSize; - - InsertBlock(Position, PagesCount, State, MemoryPermission.ReadAndWrite); - - return 0; - } - } - - return MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); - } - - public long SetProcessMemoryPermission(long Position, long Size, MemoryPermission Permission) - { - lock (Blocks) - { - if (CheckRange( - Position, - Size, - MemoryState.ProcessPermissionChangeAllowed, - MemoryState.ProcessPermissionChangeAllowed, - MemoryPermission.None, - MemoryPermission.None, - MemoryAttribute.Mask, - MemoryAttribute.None, - MemoryAttribute.IpcAndDeviceMapped, - out MemoryState State, - out _, - out _)) - { - if (State == MemoryState.CodeStatic) - { - State = MemoryState.CodeMutable; - } - else if (State == MemoryState.ModCodeStatic) - { - State = MemoryState.ModCodeMutable; - } - else - { - throw new InvalidOperationException(); - } - - long PagesCount = Size / PageSize; - - InsertBlock(Position, PagesCount, State, Permission); - - return 0; - } - } - - return MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); - } - - public long MapPhysicalMemory(long Position, long Size) - { - long End = Position + Size; - - lock (Blocks) - { - long MappedSize = 0; - - KMemoryInfo Info; - - LinkedListNode BaseNode = FindBlockNode(Position); - - LinkedListNode Node = BaseNode; - - do - { - Info = Node.Value.GetInfo(); - - if (Info.State != MemoryState.Unmapped) - { - MappedSize += GetSizeInRange(Info, Position, End); - } - - Node = Node.Next; - } - while ((ulong)(Info.Position + Info.Size) < (ulong)End && Node != null); - - if (MappedSize == Size) - { - return 0; - } - - long RemainingSize = Size - MappedSize; - - if (!Allocator.TryAllocate(RemainingSize, out long PA)) - { - return MakeError(ErrorModule.Kernel, KernelErr.OutOfMemory); - } - - Node = BaseNode; - - do - { - Info = Node.Value.GetInfo(); - - if (Info.State == MemoryState.Unmapped) - { - long CurrSize = GetSizeInRange(Info, Position, End); - - CpuMemory.Map(Info.Position, PA, CurrSize); - - PA += CurrSize; - } - - Node = Node.Next; - } - while ((ulong)(Info.Position + Info.Size) < (ulong)End && Node != null); - - PersonalMmHeapUsage += RemainingSize; - - long PagesCount = Size / PageSize; - - InsertBlock( - Position, - PagesCount, - MemoryState.Unmapped, - MemoryPermission.None, - MemoryAttribute.None, - MemoryState.Heap, - MemoryPermission.ReadAndWrite, - MemoryAttribute.None); - } - - return 0; - } - - public long UnmapPhysicalMemory(long Position, long Size) - { - long End = Position + Size; - - lock (Blocks) - { - long HeapMappedSize = 0; - - long CurrPosition = Position; - - KMemoryInfo Info; - - LinkedListNode Node = FindBlockNode(CurrPosition); - - do - { - Info = Node.Value.GetInfo(); - - if (Info.State == MemoryState.Heap) - { - if (Info.Attribute != MemoryAttribute.None) - { - return MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); - } - - HeapMappedSize += GetSizeInRange(Info, Position, End); - } - else if (Info.State != MemoryState.Unmapped) - { - return MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); - } - - Node = Node.Next; - } - while ((ulong)(Info.Position + Info.Size) < (ulong)End && Node != null); - - if (HeapMappedSize == 0) - { - return 0; - } - - PersonalMmHeapUsage -= HeapMappedSize; - - long PagesCount = Size / PageSize; - - InsertBlock(Position, PagesCount, MemoryState.Unmapped); - - CpuMemory.Unmap(Position, Size); - - FreePages(Position, PagesCount); - - return 0; - } - } - - private long GetSizeInRange(KMemoryInfo Info, long Start, long End) - { - long CurrEnd = Info.Size + Info.Position; - long CurrSize = Info.Size; - - if ((ulong)Info.Position < (ulong)Start) - { - CurrSize -= Start - Info.Position; - } - - if ((ulong)CurrEnd > (ulong)End) - { - CurrSize -= CurrEnd - End; - } - - return CurrSize; - } - - private void FreePages(long Position, long PagesCount) - { - for (long Page = 0; Page < PagesCount; Page++) - { - long VA = Position + Page * PageSize; - - long PA = CpuMemory.GetPhysicalAddress(VA); - - Allocator.Free(PA, PageSize); - } - } - - private bool IsUnmapped(long Position, long Size) - { - return CheckRange( - Position, - Size, - MemoryState.Mask, - MemoryState.Unmapped, - MemoryPermission.Mask, - MemoryPermission.None, - MemoryAttribute.Mask, - MemoryAttribute.None, - MemoryAttribute.IpcAndDeviceMapped, - out _, - out _, - out _); - } - - private bool CheckRange( - long Position, - long Size, - MemoryState StateMask, - MemoryState StateExpected, - MemoryPermission PermissionMask, - MemoryPermission PermissionExpected, - MemoryAttribute AttributeMask, - MemoryAttribute AttributeExpected, - MemoryAttribute AttributeIgnoreMask, - out MemoryState OutState, - out MemoryPermission OutPermission, - out MemoryAttribute OutAttribute) - { - KMemoryInfo BlkInfo = FindBlock(Position).GetInfo(); - - ulong Start = (ulong)Position; - ulong End = (ulong)Size + Start; - - if (End <= (ulong)(BlkInfo.Position + BlkInfo.Size)) - { - if ((BlkInfo.Attribute & AttributeMask) == AttributeExpected && - (BlkInfo.State & StateMask) == StateExpected && - (BlkInfo.Permission & PermissionMask) == PermissionExpected) - { - OutState = BlkInfo.State; - OutPermission = BlkInfo.Permission; - OutAttribute = BlkInfo.Attribute & ~AttributeIgnoreMask; - - return true; - } - } - - OutState = MemoryState.Unmapped; - OutPermission = MemoryPermission.None; - OutAttribute = MemoryAttribute.None; - - return false; - } - - private void InsertBlock( - long BasePosition, - long PagesCount, - MemoryState OldState, - MemoryPermission OldPermission, - MemoryAttribute OldAttribute, - MemoryState NewState, - MemoryPermission NewPermission, - MemoryAttribute NewAttribute) - { - //Insert new block on the list only on areas where the state - //of the block matches the state specified on the Old* state - //arguments, otherwise leave it as is. - OldAttribute |= MemoryAttribute.IpcAndDeviceMapped; - - ulong Start = (ulong)BasePosition; - ulong End = (ulong)PagesCount * PageSize + Start; - - LinkedListNode Node = Blocks.First; - - while (Node != null) - { - LinkedListNode NewNode = Node; - LinkedListNode NextNode = Node.Next; - - KMemoryBlock CurrBlock = Node.Value; - - ulong CurrStart = (ulong)CurrBlock.BasePosition; - ulong CurrEnd = (ulong)CurrBlock.PagesCount * PageSize + CurrStart; - - if (Start < CurrEnd && CurrStart < End) - { - MemoryAttribute CurrBlockAttr = CurrBlock.Attribute | MemoryAttribute.IpcAndDeviceMapped; - - if (CurrBlock.State != OldState || - CurrBlock.Permission != OldPermission || - CurrBlockAttr != OldAttribute) - { - Node = NextNode; - - continue; - } - - if (CurrStart >= Start && CurrEnd <= End) - { - CurrBlock.State = NewState; - CurrBlock.Permission = NewPermission; - CurrBlock.Attribute &= ~MemoryAttribute.IpcAndDeviceMapped; - CurrBlock.Attribute |= NewAttribute; - } - else if (CurrStart >= Start) - { - CurrBlock.BasePosition = (long)End; - - CurrBlock.PagesCount = (long)((CurrEnd - End) / PageSize); - - long NewPagesCount = (long)((End - CurrStart) / PageSize); - - NewNode = Blocks.AddBefore(Node, new KMemoryBlock( - (long)CurrStart, - NewPagesCount, - NewState, - NewPermission, - NewAttribute)); - } - else if (CurrEnd <= End) - { - CurrBlock.PagesCount = (long)((Start - CurrStart) / PageSize); - - long NewPagesCount = (long)((CurrEnd - Start) / PageSize); - - NewNode = Blocks.AddAfter(Node, new KMemoryBlock( - BasePosition, - NewPagesCount, - NewState, - NewPermission, - NewAttribute)); - } - else - { - CurrBlock.PagesCount = (long)((Start - CurrStart) / PageSize); - - long NextPagesCount = (long)((CurrEnd - End) / PageSize); - - NewNode = Blocks.AddAfter(Node, new KMemoryBlock( - BasePosition, - PagesCount, - NewState, - NewPermission, - NewAttribute)); - - Blocks.AddAfter(NewNode, new KMemoryBlock( - (long)End, - NextPagesCount, - CurrBlock.State, - CurrBlock.Permission, - CurrBlock.Attribute)); - - NextNode = null; - } - - MergeEqualStateNeighbours(NewNode); - } - - Node = NextNode; - } - } - - private void InsertBlock( - long BasePosition, - long PagesCount, - MemoryState State, - MemoryPermission Permission = MemoryPermission.None, - MemoryAttribute Attribute = MemoryAttribute.None) - { - //Inserts new block at the list, replacing and spliting - //existing blocks as needed. - KMemoryBlock Block = new KMemoryBlock(BasePosition, PagesCount, State, Permission, Attribute); - - ulong Start = (ulong)BasePosition; - ulong End = (ulong)PagesCount * PageSize + Start; - - LinkedListNode NewNode = null; - - LinkedListNode Node = Blocks.First; - - while (Node != null) - { - KMemoryBlock CurrBlock = Node.Value; - - LinkedListNode NextNode = Node.Next; - - ulong CurrStart = (ulong)CurrBlock.BasePosition; - ulong CurrEnd = (ulong)CurrBlock.PagesCount * PageSize + CurrStart; - - if (Start < CurrEnd && CurrStart < End) - { - if (Start >= CurrStart && End <= CurrEnd) - { - Block.Attribute |= CurrBlock.Attribute & MemoryAttribute.IpcAndDeviceMapped; - } - - if (Start > CurrStart && End < CurrEnd) - { - CurrBlock.PagesCount = (long)((Start - CurrStart) / PageSize); - - long NextPagesCount = (long)((CurrEnd - End) / PageSize); - - NewNode = Blocks.AddAfter(Node, Block); - - Blocks.AddAfter(NewNode, new KMemoryBlock( - (long)End, - NextPagesCount, - CurrBlock.State, - CurrBlock.Permission, - CurrBlock.Attribute)); - - break; - } - else if (Start <= CurrStart && End < CurrEnd) - { - CurrBlock.BasePosition = (long)End; - - CurrBlock.PagesCount = (long)((CurrEnd - End) / PageSize); - - if (NewNode == null) - { - NewNode = Blocks.AddBefore(Node, Block); - } - } - else if (Start > CurrStart && End >= CurrEnd) - { - CurrBlock.PagesCount = (long)((Start - CurrStart) / PageSize); - - if (NewNode == null) - { - NewNode = Blocks.AddAfter(Node, Block); - } - } - else - { - if (NewNode == null) - { - NewNode = Blocks.AddBefore(Node, Block); - } - - Blocks.Remove(Node); - } - } - - Node = NextNode; - } - - if (NewNode == null) - { - NewNode = Blocks.AddFirst(Block); - } - - MergeEqualStateNeighbours(NewNode); - } - - private void MergeEqualStateNeighbours(LinkedListNode Node) - { - KMemoryBlock Block = Node.Value; - - ulong Start = (ulong)Block.BasePosition; - ulong End = (ulong)Block.PagesCount * PageSize + Start; - - if (Node.Previous != null) - { - KMemoryBlock Previous = Node.Previous.Value; - - if (BlockStateEquals(Block, Previous)) - { - Blocks.Remove(Node.Previous); - - Block.BasePosition = Previous.BasePosition; - - Start = (ulong)Block.BasePosition; - } - } - - if (Node.Next != null) - { - KMemoryBlock Next = Node.Next.Value; - - if (BlockStateEquals(Block, Next)) - { - Blocks.Remove(Node.Next); - - End = (ulong)(Next.BasePosition + Next.PagesCount * PageSize); - } - } - - Block.PagesCount = (long)((End - Start) / PageSize); - } - - private static bool BlockStateEquals(KMemoryBlock LHS, KMemoryBlock RHS) - { - return LHS.State == RHS.State && - LHS.Permission == RHS.Permission && - LHS.Attribute == RHS.Attribute && - LHS.DeviceRefCount == RHS.DeviceRefCount && - LHS.IpcRefCount == RHS.IpcRefCount; - } - - private KMemoryBlock FindBlock(long Position) - { - return FindBlockNode(Position)?.Value; - } - - private LinkedListNode FindBlockNode(long Position) - { - ulong Addr = (ulong)Position; - - lock (Blocks) - { - LinkedListNode Node = Blocks.First; - - while (Node != null) - { - KMemoryBlock Block = Node.Value; - - ulong Start = (ulong)Block.BasePosition; - ulong End = (ulong)Block.PagesCount * PageSize + Start; - - if (Start <= Addr && End - 1 >= Addr) - { - return Node; - } - - Node = Node.Next; - } - } - - return null; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Handles/KProcessHandleTable.cs b/Ryujinx.HLE/OsHle/Handles/KProcessHandleTable.cs deleted file mode 100644 index d22b63c6..00000000 --- a/Ryujinx.HLE/OsHle/Handles/KProcessHandleTable.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System.Collections.Generic; - -namespace Ryujinx.HLE.OsHle.Handles -{ - class KProcessHandleTable - { - private IdDictionary Handles; - - public KProcessHandleTable() - { - Handles = new IdDictionary(); - } - - public int OpenHandle(object Obj) - { - return Handles.Add(Obj); - } - - public T GetData(int Handle) - { - return Handles.GetData(Handle); - } - - public object CloseHandle(int Handle) - { - return Handles.Delete(Handle); - } - - public ICollection Clear() - { - return Handles.Clear(); - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Handles/KProcessScheduler.cs b/Ryujinx.HLE/OsHle/Handles/KProcessScheduler.cs deleted file mode 100644 index 7d5e2284..00000000 --- a/Ryujinx.HLE/OsHle/Handles/KProcessScheduler.cs +++ /dev/null @@ -1,360 +0,0 @@ -using Ryujinx.HLE.Logging; -using System; -using System.Collections.Concurrent; -using System.Threading; - -namespace Ryujinx.HLE.OsHle.Handles -{ - class KProcessScheduler : IDisposable - { - private ConcurrentDictionary AllThreads; - - private ThreadQueue WaitingToRun; - - private KThread[] CoreThreads; - - private bool[] CoreReschedule; - - private object SchedLock; - - private Logger Log; - - public KProcessScheduler(Logger Log) - { - this.Log = Log; - - AllThreads = new ConcurrentDictionary(); - - WaitingToRun = new ThreadQueue(); - - CoreThreads = new KThread[4]; - - CoreReschedule = new bool[4]; - - SchedLock = new object(); - } - - public void StartThread(KThread Thread) - { - lock (SchedLock) - { - SchedulerThread SchedThread = new SchedulerThread(Thread); - - if (!AllThreads.TryAdd(Thread, SchedThread)) - { - return; - } - - if (TryAddToCore(Thread)) - { - Thread.Thread.Execute(); - - PrintDbgThreadInfo(Thread, "running."); - } - else - { - WaitingToRun.Push(SchedThread); - - PrintDbgThreadInfo(Thread, "waiting to run."); - } - } - } - - public void RemoveThread(KThread Thread) - { - PrintDbgThreadInfo(Thread, "exited."); - - lock (SchedLock) - { - if (AllThreads.TryRemove(Thread, out SchedulerThread SchedThread)) - { - WaitingToRun.Remove(SchedThread); - - SchedThread.Dispose(); - } - - int ActualCore = Thread.ActualCore; - - SchedulerThread NewThread = WaitingToRun.Pop(ActualCore); - - if (NewThread == null) - { - Log.PrintDebug(LogClass.KernelScheduler, $"Nothing to run on core {ActualCore}!"); - - CoreThreads[ActualCore] = null; - - return; - } - - NewThread.Thread.ActualCore = ActualCore; - - RunThread(NewThread); - } - } - - public void SetThreadActivity(KThread Thread, bool Active) - { - SchedulerThread SchedThread = AllThreads[Thread]; - - SchedThread.IsActive = Active; - - if (Active) - { - SchedThread.WaitActivity.Set(); - } - else - { - SchedThread.WaitActivity.Reset(); - } - } - - public void EnterWait(KThread Thread, int TimeoutMs = Timeout.Infinite) - { - SchedulerThread SchedThread = AllThreads[Thread]; - - Suspend(Thread); - - SchedThread.WaitSync.WaitOne(TimeoutMs); - - TryResumingExecution(SchedThread); - } - - public void WakeUp(KThread Thread) - { - AllThreads[Thread].WaitSync.Set(); - } - - public void ChangeCore(KThread Thread, int IdealCore, int CoreMask) - { - lock (SchedLock) - { - if (IdealCore != -3) - { - Thread.IdealCore = IdealCore; - } - - Thread.CoreMask = CoreMask; - - if (AllThreads.ContainsKey(Thread)) - { - SetReschedule(Thread.ActualCore); - - SchedulerThread SchedThread = AllThreads[Thread]; - - //Note: Aways if the thread is on the queue first, and try - //adding to a new core later, to ensure that a thread that - //is already running won't be added to another core. - if (WaitingToRun.HasThread(SchedThread) && TryAddToCore(Thread)) - { - WaitingToRun.Remove(SchedThread); - - RunThread(SchedThread); - } - } - } - } - - public void Suspend(KThread Thread) - { - lock (SchedLock) - { - PrintDbgThreadInfo(Thread, "suspended."); - - int ActualCore = Thread.ActualCore; - - CoreReschedule[ActualCore] = false; - - SchedulerThread SchedThread = WaitingToRun.Pop(ActualCore); - - if (SchedThread != null) - { - SchedThread.Thread.ActualCore = ActualCore; - - CoreThreads[ActualCore] = SchedThread.Thread; - - RunThread(SchedThread); - } - else - { - Log.PrintDebug(LogClass.KernelScheduler, $"Nothing to run on core {Thread.ActualCore}!"); - - CoreThreads[ActualCore] = null; - } - } - } - - public void SetReschedule(int Core) - { - lock (SchedLock) - { - CoreReschedule[Core] = true; - } - } - - public void Reschedule(KThread Thread) - { - bool NeedsReschedule; - - lock (SchedLock) - { - int ActualCore = Thread.ActualCore; - - NeedsReschedule = CoreReschedule[ActualCore]; - - CoreReschedule[ActualCore] = false; - } - - if (NeedsReschedule) - { - Yield(Thread, Thread.ActualPriority - 1); - } - } - - public void Yield(KThread Thread) - { - Yield(Thread, Thread.ActualPriority); - } - - private void Yield(KThread Thread, int MinPriority) - { - PrintDbgThreadInfo(Thread, "yielded execution."); - - lock (SchedLock) - { - int ActualCore = Thread.ActualCore; - - SchedulerThread NewThread = WaitingToRun.Pop(ActualCore, MinPriority); - - if (NewThread != null) - { - NewThread.Thread.ActualCore = ActualCore; - - CoreThreads[ActualCore] = NewThread.Thread; - - RunThread(NewThread); - } - else - { - CoreThreads[ActualCore] = null; - } - } - - Resume(Thread); - } - - public void Resume(KThread Thread) - { - TryResumingExecution(AllThreads[Thread]); - } - - private void TryResumingExecution(SchedulerThread SchedThread) - { - KThread Thread = SchedThread.Thread; - - PrintDbgThreadInfo(Thread, "trying to resume..."); - - SchedThread.WaitActivity.WaitOne(); - - lock (SchedLock) - { - if (TryAddToCore(Thread)) - { - PrintDbgThreadInfo(Thread, "resuming execution..."); - - return; - } - - WaitingToRun.Push(SchedThread); - - SetReschedule(Thread.ProcessorId); - - PrintDbgThreadInfo(Thread, "entering wait state..."); - } - - SchedThread.WaitSched.WaitOne(); - - PrintDbgThreadInfo(Thread, "resuming execution..."); - } - - private void RunThread(SchedulerThread SchedThread) - { - if (!SchedThread.Thread.Thread.Execute()) - { - PrintDbgThreadInfo(SchedThread.Thread, "waked."); - - SchedThread.WaitSched.Set(); - } - else - { - PrintDbgThreadInfo(SchedThread.Thread, "running."); - } - } - - public void Resort(KThread Thread) - { - if (AllThreads.TryGetValue(Thread, out SchedulerThread SchedThread)) - { - WaitingToRun.Resort(SchedThread); - } - } - - private bool TryAddToCore(KThread Thread) - { - //First, try running it on Ideal Core. - int IdealCore = Thread.IdealCore; - - if (IdealCore != -1 && CoreThreads[IdealCore] == null) - { - Thread.ActualCore = IdealCore; - - CoreThreads[IdealCore] = Thread; - - return true; - } - - //If that fails, then try running on any core allowed by Core Mask. - int CoreMask = Thread.CoreMask; - - for (int Core = 0; Core < CoreThreads.Length; Core++, CoreMask >>= 1) - { - if ((CoreMask & 1) != 0 && CoreThreads[Core] == null) - { - Thread.ActualCore = Core; - - CoreThreads[Core] = Thread; - - return true; - } - } - - return false; - } - - private void PrintDbgThreadInfo(KThread Thread, string Message) - { - Log.PrintDebug(LogClass.KernelScheduler, "(" + - "ThreadId = " + Thread.ThreadId + ", " + - "CoreMask = 0x" + Thread.CoreMask.ToString("x1") + ", " + - "ActualCore = " + Thread.ActualCore + ", " + - "IdealCore = " + Thread.IdealCore + ", " + - "ActualPriority = " + Thread.ActualPriority + ", " + - "WantedPriority = " + Thread.WantedPriority + ") " + Message); - } - - public void Dispose() - { - Dispose(true); - } - - protected virtual void Dispose(bool Disposing) - { - if (Disposing) - { - foreach (SchedulerThread SchedThread in AllThreads.Values) - { - SchedThread.Dispose(); - } - } - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Handles/KSession.cs b/Ryujinx.HLE/OsHle/Handles/KSession.cs deleted file mode 100644 index e85de36c..00000000 --- a/Ryujinx.HLE/OsHle/Handles/KSession.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Ryujinx.HLE.OsHle.Services; -using System; - -namespace Ryujinx.HLE.OsHle.Handles -{ - class KSession : IDisposable - { - public IpcService Service { get; private set; } - - public string ServiceName { get; private set; } - - public KSession(IpcService Service, string ServiceName) - { - this.Service = Service; - this.ServiceName = ServiceName; - } - - public void Dispose() - { - Dispose(true); - } - - protected virtual void Dispose(bool Disposing) - { - if (Disposing && Service is IDisposable DisposableService) - { - DisposableService.Dispose(); - } - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Handles/KSharedMemory.cs b/Ryujinx.HLE/OsHle/Handles/KSharedMemory.cs deleted file mode 100644 index 5c410474..00000000 --- a/Ryujinx.HLE/OsHle/Handles/KSharedMemory.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace Ryujinx.HLE.OsHle.Handles -{ - class KSharedMemory - { - public long PA { get; private set; } - public long Size { get; private set; } - - public KSharedMemory(long PA, long Size) - { - this.PA = PA; - this.Size = Size; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Handles/KSynchronizationObject.cs b/Ryujinx.HLE/OsHle/Handles/KSynchronizationObject.cs deleted file mode 100644 index 0e7d06f6..00000000 --- a/Ryujinx.HLE/OsHle/Handles/KSynchronizationObject.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System; -using System.Threading; - -namespace Ryujinx.HLE.OsHle.Handles -{ - class KSynchronizationObject : IDisposable - { - public ManualResetEvent WaitEvent { get; private set; } - - public KSynchronizationObject() - { - WaitEvent = new ManualResetEvent(false); - } - - public void Dispose() - { - Dispose(true); - } - - protected virtual void Dispose(bool Disposing) - { - if (Disposing) - { - WaitEvent.Dispose(); - } - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Handles/KThread.cs b/Ryujinx.HLE/OsHle/Handles/KThread.cs deleted file mode 100644 index 2b980d17..00000000 --- a/Ryujinx.HLE/OsHle/Handles/KThread.cs +++ /dev/null @@ -1,96 +0,0 @@ -using ChocolArm64; -using System.Collections.Generic; - -namespace Ryujinx.HLE.OsHle.Handles -{ - class KThread : KSynchronizationObject - { - public AThread Thread { get; private set; } - - public int CoreMask { get; set; } - - public long MutexAddress { get; set; } - public long CondVarAddress { get; set; } - public long ArbiterWaitAddress { get; set; } - - public bool CondVarSignaled { get; set; } - public bool ArbiterSignaled { get; set; } - - private Process Process; - - public List MutexWaiters { get; private set; } - - public KThread MutexOwner { get; set; } - - public int ActualPriority { get; private set; } - public int WantedPriority { get; private set; } - - public int ActualCore { get; set; } - public int ProcessorId { get; set; } - public int IdealCore { get; set; } - - public int WaitHandle { get; set; } - - public long LastPc { get; set; } - - public int ThreadId => Thread.ThreadId; - - public KThread( - AThread Thread, - Process Process, - int ProcessorId, - int Priority) - { - this.Thread = Thread; - this.Process = Process; - this.ProcessorId = ProcessorId; - this.IdealCore = ProcessorId; - - MutexWaiters = new List(); - - CoreMask = 1 << ProcessorId; - - ActualPriority = WantedPriority = Priority; - } - - public void SetPriority(int Priority) - { - WantedPriority = Priority; - - UpdatePriority(); - } - - public void UpdatePriority() - { - bool PriorityChanged; - - lock (Process.ThreadSyncLock) - { - int OldPriority = ActualPriority; - - int CurrPriority = WantedPriority; - - foreach (KThread Thread in MutexWaiters) - { - int WantedPriority = Thread.WantedPriority; - - if (CurrPriority > WantedPriority) - { - CurrPriority = WantedPriority; - } - } - - PriorityChanged = CurrPriority != OldPriority; - - ActualPriority = CurrPriority; - } - - if (PriorityChanged) - { - Process.Scheduler.Resort(this); - - MutexOwner?.UpdatePriority(); - } - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Handles/KTlsPageManager.cs b/Ryujinx.HLE/OsHle/Handles/KTlsPageManager.cs deleted file mode 100644 index f116f548..00000000 --- a/Ryujinx.HLE/OsHle/Handles/KTlsPageManager.cs +++ /dev/null @@ -1,60 +0,0 @@ -using System; - -namespace Ryujinx.HLE.OsHle.Handles -{ - class KTlsPageManager - { - private const int TlsEntrySize = 0x200; - - private long PagePosition; - - private int UsedSlots; - - private bool[] Slots; - - public bool IsEmpty => UsedSlots == 0; - public bool IsFull => UsedSlots == Slots.Length; - - public KTlsPageManager(long PagePosition) - { - this.PagePosition = PagePosition; - - Slots = new bool[KMemoryManager.PageSize / TlsEntrySize]; - } - - public bool TryGetFreeTlsAddr(out long Position) - { - Position = PagePosition; - - for (int Index = 0; Index < Slots.Length; Index++) - { - if (!Slots[Index]) - { - Slots[Index] = true; - - UsedSlots++; - - return true; - } - - Position += TlsEntrySize; - } - - Position = 0; - - return false; - } - - public void FreeTlsSlot(int Slot) - { - if ((uint)Slot > Slots.Length) - { - throw new ArgumentOutOfRangeException(nameof(Slot)); - } - - Slots[Slot] = false; - - UsedSlots--; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Handles/KTransferMemory.cs b/Ryujinx.HLE/OsHle/Handles/KTransferMemory.cs deleted file mode 100644 index 5f9c0409..00000000 --- a/Ryujinx.HLE/OsHle/Handles/KTransferMemory.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace Ryujinx.HLE.OsHle.Handles -{ - class KTransferMemory - { - public long Position { get; private set; } - public long Size { get; private set; } - - public KTransferMemory(long Position, long Size) - { - this.Position = Position; - this.Size = Size; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Handles/MemoryAttribute.cs b/Ryujinx.HLE/OsHle/Handles/MemoryAttribute.cs deleted file mode 100644 index e234d7f0..00000000 --- a/Ryujinx.HLE/OsHle/Handles/MemoryAttribute.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System; - -namespace Ryujinx.HLE.OsHle.Handles -{ - [Flags] - enum MemoryAttribute : byte - { - None = 0, - Mask = 0xff, - - Borrowed = 1 << 0, - IpcMapped = 1 << 1, - DeviceMapped = 1 << 2, - Uncached = 1 << 3, - - IpcAndDeviceMapped = IpcMapped | DeviceMapped, - - BorrowedAndIpcMapped = Borrowed | IpcMapped, - - DeviceMappedAndUncached = DeviceMapped | Uncached - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Handles/MemoryPermission.cs b/Ryujinx.HLE/OsHle/Handles/MemoryPermission.cs deleted file mode 100644 index 416f171e..00000000 --- a/Ryujinx.HLE/OsHle/Handles/MemoryPermission.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; - -namespace Ryujinx.HLE.OsHle.Handles -{ - [Flags] - enum MemoryPermission : byte - { - None = 0, - Mask = 0xff, - - Read = 1 << 0, - Write = 1 << 1, - Execute = 1 << 2, - - ReadAndWrite = Read | Write, - ReadAndExecute = Read | Execute - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Handles/MemoryState.cs b/Ryujinx.HLE/OsHle/Handles/MemoryState.cs deleted file mode 100644 index 5437d6a3..00000000 --- a/Ryujinx.HLE/OsHle/Handles/MemoryState.cs +++ /dev/null @@ -1,49 +0,0 @@ -using System; - -namespace Ryujinx.HLE.OsHle -{ - [Flags] - enum MemoryState : uint - { - Unmapped = 0x00000000, - Io = 0x00002001, - Normal = 0x00042002, - CodeStatic = 0x00DC7E03, - CodeMutable = 0x03FEBD04, - Heap = 0x037EBD05, - SharedMemory = 0x00402006, - ModCodeStatic = 0x00DD7E08, - ModCodeMutable = 0x03FFBD09, - IpcBuffer0 = 0x005C3C0A, - MappedMemory = 0x005C3C0B, - ThreadLocal = 0x0040200C, - TransferMemoryIsolated = 0x015C3C0D, - TransferMemory = 0x005C380E, - ProcessMemory = 0x0040380F, - Reserved = 0x00000010, - IpcBuffer1 = 0x005C3811, - IpcBuffer3 = 0x004C2812, - KernelStack = 0x00002013, - CodeReadOnly = 0x00402214, - CodeWritable = 0x00402015, - Mask = 0xffffffff, - - PermissionChangeAllowed = 1 << 8, - ForceReadWritableByDebugSyscalls = 1 << 9, - IpcSendAllowedType0 = 1 << 10, - IpcSendAllowedType3 = 1 << 11, - IpcSendAllowedType1 = 1 << 12, - ProcessPermissionChangeAllowed = 1 << 14, - MapAllowed = 1 << 15, - UnmapProcessCodeMemoryAllowed = 1 << 16, - TransferMemoryAllowed = 1 << 17, - QueryPhysicalAddressAllowed = 1 << 18, - MapDeviceAllowed = 1 << 19, - MapDeviceAlignedAllowed = 1 << 20, - IpcBufferAllowed = 1 << 21, - IsPoolAllocated = 1 << 22, - MapProcessAllowed = 1 << 23, - AttributeChangeAllowed = 1 << 24, - CodeMemoryAllowed = 1 << 25 - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Handles/SchedulerThread.cs b/Ryujinx.HLE/OsHle/Handles/SchedulerThread.cs deleted file mode 100644 index 5bdefe74..00000000 --- a/Ryujinx.HLE/OsHle/Handles/SchedulerThread.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System; -using System.Threading; - -namespace Ryujinx.HLE.OsHle.Handles -{ - class SchedulerThread : IDisposable - { - public KThread Thread { get; private set; } - - public SchedulerThread Next { get; set; } - - public bool IsActive { get; set; } - - public AutoResetEvent WaitSync { get; private set; } - public ManualResetEvent WaitActivity { get; private set; } - public AutoResetEvent WaitSched { get; private set; } - - public SchedulerThread(KThread Thread) - { - this.Thread = Thread; - - IsActive = true; - - WaitSync = new AutoResetEvent(false); - - WaitActivity = new ManualResetEvent(true); - - WaitSched = new AutoResetEvent(false); - } - - public void Dispose() - { - Dispose(true); - } - - protected virtual void Dispose(bool Disposing) - { - if (Disposing) - { - WaitSync.Dispose(); - - WaitActivity.Dispose(); - - WaitSched.Dispose(); - } - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Handles/ThreadQueue.cs b/Ryujinx.HLE/OsHle/Handles/ThreadQueue.cs deleted file mode 100644 index 09dcb3d0..00000000 --- a/Ryujinx.HLE/OsHle/Handles/ThreadQueue.cs +++ /dev/null @@ -1,158 +0,0 @@ -namespace Ryujinx.HLE.OsHle.Handles -{ - class ThreadQueue - { - private const int LowestPriority = 0x3f; - - private SchedulerThread Head; - - private object ListLock; - - public ThreadQueue() - { - ListLock = new object(); - } - - public void Push(SchedulerThread Wait) - { - lock (ListLock) - { - //Ensure that we're not creating circular references - //by adding a thread that is already on the list. - if (HasThread(Wait)) - { - return; - } - - if (Head == null || Head.Thread.ActualPriority >= Wait.Thread.ActualPriority) - { - Wait.Next = Head; - - Head = Wait; - - return; - } - - SchedulerThread Curr = Head; - - while (Curr.Next != null) - { - if (Curr.Next.Thread.ActualPriority >= Wait.Thread.ActualPriority) - { - break; - } - - Curr = Curr.Next; - } - - Wait.Next = Curr.Next; - Curr.Next = Wait; - } - } - - public SchedulerThread Pop(int Core, int MinPriority = LowestPriority) - { - lock (ListLock) - { - int CoreMask = 1 << Core; - - SchedulerThread Prev = null; - SchedulerThread Curr = Head; - - while (Curr != null) - { - KThread Thread = Curr.Thread; - - if (Thread.ActualPriority <= MinPriority && (Thread.CoreMask & CoreMask) != 0) - { - if (Prev != null) - { - Prev.Next = Curr.Next; - } - else - { - Head = Head.Next; - } - - break; - } - - Prev = Curr; - Curr = Curr.Next; - } - - return Curr; - } - } - - public bool Remove(SchedulerThread Thread) - { - lock (ListLock) - { - if (Head == null) - { - return false; - } - else if (Head == Thread) - { - Head = Head.Next; - - return true; - } - - SchedulerThread Prev = Head; - SchedulerThread Curr = Head.Next; - - while (Curr != null) - { - if (Curr == Thread) - { - Prev.Next = Curr.Next; - - return true; - } - - Prev = Curr; - Curr = Curr.Next; - } - - return false; - } - } - - public bool Resort(SchedulerThread Thread) - { - lock (ListLock) - { - if (Remove(Thread)) - { - Push(Thread); - - return true; - } - - return false; - } - } - - public bool HasThread(SchedulerThread Thread) - { - lock (ListLock) - { - SchedulerThread Curr = Head; - - while (Curr != null) - { - if (Curr == Thread) - { - return true; - } - - Curr = Curr.Next; - } - - return false; - } - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Homebrew.cs b/Ryujinx.HLE/OsHle/Homebrew.cs deleted file mode 100644 index 90c6c4c6..00000000 --- a/Ryujinx.HLE/OsHle/Homebrew.cs +++ /dev/null @@ -1,77 +0,0 @@ -using ChocolArm64.Memory; -using System.Text; - -namespace Ryujinx.HLE.OsHle -{ - static class Homebrew - { - public const string TemporaryNroSuffix = ".ryu_tmp.nro"; - - //http://switchbrew.org/index.php?title=Homebrew_ABI - public static void WriteHbAbiData(AMemory Memory, long Position, int MainThreadHandle, string SwitchPath) - { - //MainThreadHandle. - WriteConfigEntry(Memory, ref Position, 1, 0, MainThreadHandle); - - //NextLoadPath. - WriteConfigEntry(Memory, ref Position, 2, 0, Position + 0x200, Position + 0x400); - - //Argv. - long ArgvPosition = Position + 0xC00; - - Memory.WriteBytes(ArgvPosition, Encoding.ASCII.GetBytes(SwitchPath + "\0")); - - WriteConfigEntry(Memory, ref Position, 5, 0, 0, ArgvPosition); - - //AppletType. - WriteConfigEntry(Memory, ref Position, 7); - - //EndOfList. - WriteConfigEntry(Memory, ref Position, 0); - } - - private static void WriteConfigEntry( - AMemory Memory, - ref long Position, - int Key, - int Flags = 0, - long Value0 = 0, - long Value1 = 0) - { - Memory.WriteInt32(Position + 0x00, Key); - Memory.WriteInt32(Position + 0x04, Flags); - Memory.WriteInt64(Position + 0x08, Value0); - Memory.WriteInt64(Position + 0x10, Value1); - - Position += 0x18; - } - - public static string ReadHbAbiNextLoadPath(AMemory Memory, long Position) - { - string FileName = null; - - while (true) - { - long Key = Memory.ReadInt64(Position); - - if (Key == 2) - { - long Value0 = Memory.ReadInt64(Position + 0x08); - long Value1 = Memory.ReadInt64(Position + 0x10); - - FileName = AMemoryHelper.ReadAsciiString(Memory, Value0, Value1 - Value0); - - break; - } - else if (Key == 0) - { - break; - } - - Position += 0x18; - } - - return FileName; - } - } -} diff --git a/Ryujinx.HLE/OsHle/Horizon.cs b/Ryujinx.HLE/OsHle/Horizon.cs deleted file mode 100644 index 1fd210dd..00000000 --- a/Ryujinx.HLE/OsHle/Horizon.cs +++ /dev/null @@ -1,248 +0,0 @@ -using Ryujinx.HLE.Loaders.Executables; -using Ryujinx.HLE.Loaders.Npdm; -using Ryujinx.HLE.Logging; -using Ryujinx.HLE.OsHle.Font; -using Ryujinx.HLE.OsHle.Handles; -using Ryujinx.HLE.OsHle.SystemState; -using System; -using System.Collections.Concurrent; -using System.IO; - -namespace Ryujinx.HLE.OsHle -{ - public class Horizon : IDisposable - { - internal const int HidSize = 0x40000; - internal const int FontSize = 0x1100000; - - private Switch Ns; - - private KProcessScheduler Scheduler; - - private ConcurrentDictionary Processes; - - public SystemStateMgr SystemState { get; private set; } - - internal KSharedMemory HidSharedMem { get; private set; } - internal KSharedMemory FontSharedMem { get; private set; } - - internal SharedFontManager Font { get; private set; } - - internal KEvent VsyncEvent { get; private set; } - - public Horizon(Switch Ns) - { - this.Ns = Ns; - - Scheduler = new KProcessScheduler(Ns.Log); - - Processes = new ConcurrentDictionary(); - - SystemState = new SystemStateMgr(); - - if (!Ns.Memory.Allocator.TryAllocate(HidSize, out long HidPA) || - !Ns.Memory.Allocator.TryAllocate(FontSize, out long FontPA)) - { - throw new InvalidOperationException(); - } - - HidSharedMem = new KSharedMemory(HidPA, HidSize); - FontSharedMem = new KSharedMemory(FontPA, FontSize); - - Font = new SharedFontManager(Ns, FontSharedMem.PA); - - VsyncEvent = new KEvent(); - } - - public void LoadCart(string ExeFsDir, string RomFsFile = null) - { - if (RomFsFile != null) - { - Ns.VFs.LoadRomFs(RomFsFile); - } - - string NpdmFileName = Path.Combine(ExeFsDir, "main.npdm"); - - Npdm MetaData = null; - - if (File.Exists(NpdmFileName)) - { - Ns.Log.PrintInfo(LogClass.Loader, $"Loading main.npdm..."); - - using (FileStream Input = new FileStream(NpdmFileName, FileMode.Open)) - { - MetaData = new Npdm(Input); - } - } - else - { - Ns.Log.PrintWarning(LogClass.Loader, $"NPDM file not found, using default values!"); - } - - Process MainProcess = MakeProcess(MetaData); - - void LoadNso(string FileName) - { - foreach (string File in Directory.GetFiles(ExeFsDir, FileName)) - { - if (Path.GetExtension(File) != string.Empty) - { - continue; - } - - Ns.Log.PrintInfo(LogClass.Loader, $"Loading {Path.GetFileNameWithoutExtension(File)}..."); - - using (FileStream Input = new FileStream(File, FileMode.Open)) - { - string Name = Path.GetFileNameWithoutExtension(File); - - Nso Program = new Nso(Input, Name); - - MainProcess.LoadProgram(Program); - } - } - } - - if (!MainProcess.MetaData.Is64Bits) - { - throw new NotImplementedException("32-bit titles are unsupported!"); - } - - LoadNso("rtld"); - - MainProcess.SetEmptyArgs(); - - LoadNso("main"); - LoadNso("subsdk*"); - LoadNso("sdk"); - - MainProcess.Run(); - } - - public void LoadProgram(string FilePath) - { - bool IsNro = Path.GetExtension(FilePath).ToLower() == ".nro"; - - string Name = Path.GetFileNameWithoutExtension(FilePath); - string SwitchFilePath = Ns.VFs.SystemPathToSwitchPath(FilePath); - - if (IsNro && (SwitchFilePath == null || !SwitchFilePath.StartsWith("sdmc:/"))) - { - string SwitchPath = $"sdmc:/switch/{Name}{Homebrew.TemporaryNroSuffix}"; - string TempPath = Ns.VFs.SwitchPathToSystemPath(SwitchPath); - - string SwitchDir = Path.GetDirectoryName(TempPath); - if (!Directory.Exists(SwitchDir)) - { - Directory.CreateDirectory(SwitchDir); - } - File.Copy(FilePath, TempPath, true); - - FilePath = TempPath; - } - - Process MainProcess = MakeProcess(); - - using (FileStream Input = new FileStream(FilePath, FileMode.Open)) - { - MainProcess.LoadProgram(IsNro - ? (IExecutable)new Nro(Input, FilePath) - : (IExecutable)new Nso(Input, FilePath)); - } - - MainProcess.SetEmptyArgs(); - MainProcess.Run(IsNro); - } - - public void SignalVsync() => VsyncEvent.WaitEvent.Set(); - - private Process MakeProcess(Npdm MetaData = null) - { - Process Process; - - lock (Processes) - { - int ProcessId = 0; - - while (Processes.ContainsKey(ProcessId)) - { - ProcessId++; - } - - Process = new Process(Ns, Scheduler, ProcessId, MetaData); - - Processes.TryAdd(ProcessId, Process); - } - - InitializeProcess(Process); - - return Process; - } - - private void InitializeProcess(Process Process) - { - Process.AppletState.SetFocus(true); - } - - internal void ExitProcess(int ProcessId) - { - if (Processes.TryGetValue(ProcessId, out Process Process) && Process.NeedsHbAbi) - { - string NextNro = Homebrew.ReadHbAbiNextLoadPath(Process.Memory, Process.HbAbiDataPosition); - - Ns.Log.PrintInfo(LogClass.Loader, $"HbAbi NextLoadPath {NextNro}"); - - if (NextNro == string.Empty) - { - NextNro = "sdmc:/hbmenu.nro"; - } - - NextNro = NextNro.Replace("sdmc:", string.Empty); - - NextNro = Ns.VFs.GetFullPath(Ns.VFs.GetSdCardPath(), NextNro); - - if (File.Exists(NextNro)) - { - LoadProgram(NextNro); - } - } - - if (Processes.TryRemove(ProcessId, out Process)) - { - Process.StopAllThreadsAsync(); - Process.Dispose(); - - if (Processes.Count == 0) - { - Ns.OnFinish(EventArgs.Empty); - } - } - } - - internal bool TryGetProcess(int ProcessId, out Process Process) - { - return Processes.TryGetValue(ProcessId, out Process); - } - - public void Dispose() - { - Dispose(true); - } - - protected virtual void Dispose(bool Disposing) - { - if (Disposing) - { - foreach (Process Process in Processes.Values) - { - Process.StopAllThreadsAsync(); - Process.Dispose(); - } - - VsyncEvent.Dispose(); - - Scheduler.Dispose(); - } - } - } -} diff --git a/Ryujinx.HLE/OsHle/IdDictionary.cs b/Ryujinx.HLE/OsHle/IdDictionary.cs deleted file mode 100644 index dcb8d0f7..00000000 --- a/Ryujinx.HLE/OsHle/IdDictionary.cs +++ /dev/null @@ -1,73 +0,0 @@ -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; - -namespace Ryujinx.HLE.OsHle -{ - class IdDictionary - { - private ConcurrentDictionary Objs; - - public IdDictionary() - { - Objs = new ConcurrentDictionary(); - } - - public bool Add(int Id, object Data) - { - return Objs.TryAdd(Id, Data); - } - - public int Add(object Data) - { - for (int Id = 1; Id < int.MaxValue; Id++) - { - if (Objs.TryAdd(Id, Data)) - { - return Id; - } - } - - throw new InvalidOperationException(); - } - - public object GetData(int Id) - { - if (Objs.TryGetValue(Id, out object Data)) - { - return Data; - } - - return null; - } - - public T GetData(int Id) - { - if (Objs.TryGetValue(Id, out object Data) && Data is T) - { - return (T)Data; - } - - return default(T); - } - - public object Delete(int Id) - { - if (Objs.TryRemove(Id, out object Obj)) - { - return Obj; - } - - return null; - } - - public ICollection Clear() - { - ICollection Values = Objs.Values; - - Objs.Clear(); - - return Values; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Ipc/IpcBuffDesc.cs b/Ryujinx.HLE/OsHle/Ipc/IpcBuffDesc.cs deleted file mode 100644 index 12bff0fb..00000000 --- a/Ryujinx.HLE/OsHle/Ipc/IpcBuffDesc.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System.IO; - -namespace Ryujinx.HLE.OsHle.Ipc -{ - struct IpcBuffDesc - { - public long Position { get; private set; } - public long Size { get; private set; } - public int Flags { get; private set; } - - public IpcBuffDesc(BinaryReader Reader) - { - long Word0 = Reader.ReadUInt32(); - long Word1 = Reader.ReadUInt32(); - long Word2 = Reader.ReadUInt32(); - - Position = Word1; - Position |= (Word2 << 4) & 0x0f00000000; - Position |= (Word2 << 34) & 0x7000000000; - - Size = Word0; - Size |= (Word2 << 8) & 0xf00000000; - - Flags = (int)Word2 & 3; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Ipc/IpcHandleDesc.cs b/Ryujinx.HLE/OsHle/Ipc/IpcHandleDesc.cs deleted file mode 100644 index 609cc6e0..00000000 --- a/Ryujinx.HLE/OsHle/Ipc/IpcHandleDesc.cs +++ /dev/null @@ -1,92 +0,0 @@ -using System; -using System.IO; - -namespace Ryujinx.HLE.OsHle.Ipc -{ - class IpcHandleDesc - { - public bool HasPId { get; private set; } - - public long PId { get; private set; } - - public int[] ToCopy { get; private set; } - public int[] ToMove { get; private set; } - - public IpcHandleDesc(BinaryReader Reader) - { - int Word = Reader.ReadInt32(); - - HasPId = (Word & 1) != 0; - - ToCopy = new int[(Word >> 1) & 0xf]; - ToMove = new int[(Word >> 5) & 0xf]; - - PId = HasPId ? Reader.ReadInt64() : 0; - - for (int Index = 0; Index < ToCopy.Length; Index++) - { - ToCopy[Index] = Reader.ReadInt32(); - } - - for (int Index = 0; Index < ToMove.Length; Index++) - { - ToMove[Index] = Reader.ReadInt32(); - } - } - - public IpcHandleDesc(int[] Copy, int[] Move) - { - ToCopy = Copy ?? throw new ArgumentNullException(nameof(Copy)); - ToMove = Move ?? throw new ArgumentNullException(nameof(Move)); - } - - public IpcHandleDesc(int[] Copy, int[] Move, long PId) : this(Copy, Move) - { - this.PId = PId; - - HasPId = true; - } - - public static IpcHandleDesc MakeCopy(params int[] Handles) - { - return new IpcHandleDesc(Handles, new int[0]); - } - - public static IpcHandleDesc MakeMove(params int[] Handles) - { - return new IpcHandleDesc(new int[0], Handles); - } - - public byte[] GetBytes() - { - using (MemoryStream MS = new MemoryStream()) - { - BinaryWriter Writer = new BinaryWriter(MS); - - int Word = HasPId ? 1 : 0; - - Word |= (ToCopy.Length & 0xf) << 1; - Word |= (ToMove.Length & 0xf) << 5; - - Writer.Write(Word); - - if (HasPId) - { - Writer.Write((long)PId); - } - - foreach (int Handle in ToCopy) - { - Writer.Write(Handle); - } - - foreach (int Handle in ToMove) - { - Writer.Write(Handle); - } - - return MS.ToArray(); - } - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Ipc/IpcHandler.cs b/Ryujinx.HLE/OsHle/Ipc/IpcHandler.cs deleted file mode 100644 index cdb844cf..00000000 --- a/Ryujinx.HLE/OsHle/Ipc/IpcHandler.cs +++ /dev/null @@ -1,140 +0,0 @@ -using ChocolArm64.Memory; -using Ryujinx.HLE.OsHle.Handles; -using System; -using System.IO; - -namespace Ryujinx.HLE.OsHle.Ipc -{ - static class IpcHandler - { - public static long IpcCall( - Switch Ns, - Process Process, - AMemory Memory, - KSession Session, - IpcMessage Request, - long CmdPtr) - { - IpcMessage Response = new IpcMessage(); - - using (MemoryStream Raw = new MemoryStream(Request.RawData)) - { - BinaryReader ReqReader = new BinaryReader(Raw); - - if (Request.Type == IpcMessageType.Request || - Request.Type == IpcMessageType.RequestWithContext) - { - Response.Type = IpcMessageType.Response; - - using (MemoryStream ResMS = new MemoryStream()) - { - BinaryWriter ResWriter = new BinaryWriter(ResMS); - - ServiceCtx Context = new ServiceCtx( - Ns, - Process, - Memory, - Session, - Request, - Response, - ReqReader, - ResWriter); - - Session.Service.CallMethod(Context); - - Response.RawData = ResMS.ToArray(); - } - } - else if (Request.Type == IpcMessageType.Control || - Request.Type == IpcMessageType.ControlWithContext) - { - long Magic = ReqReader.ReadInt64(); - long CmdId = ReqReader.ReadInt64(); - - switch (CmdId) - { - case 0: - { - Request = FillResponse(Response, 0, Session.Service.ConvertToDomain()); - - break; - } - - case 3: - { - Request = FillResponse(Response, 0, 0x500); - - break; - } - - //TODO: Whats the difference between IpcDuplicateSession/Ex? - case 2: - case 4: - { - int Unknown = ReqReader.ReadInt32(); - - int Handle = Process.HandleTable.OpenHandle(Session); - - Response.HandleDesc = IpcHandleDesc.MakeMove(Handle); - - Request = FillResponse(Response, 0); - - break; - } - - default: throw new NotImplementedException(CmdId.ToString()); - } - } - else if (Request.Type == IpcMessageType.CloseSession) - { - //TODO - } - else - { - throw new NotImplementedException(Request.Type.ToString()); - } - - Memory.WriteBytes(CmdPtr, Response.GetBytes(CmdPtr)); - } - - return 0; - } - - private static IpcMessage FillResponse(IpcMessage Response, long Result, params int[] Values) - { - using (MemoryStream MS = new MemoryStream()) - { - BinaryWriter Writer = new BinaryWriter(MS); - - foreach (int Value in Values) - { - Writer.Write(Value); - } - - return FillResponse(Response, Result, MS.ToArray()); - } - } - - private static IpcMessage FillResponse(IpcMessage Response, long Result, byte[] Data = null) - { - Response.Type = IpcMessageType.Response; - - using (MemoryStream MS = new MemoryStream()) - { - BinaryWriter Writer = new BinaryWriter(MS); - - Writer.Write(IpcMagic.Sfco); - Writer.Write(Result); - - if (Data != null) - { - Writer.Write(Data); - } - - Response.RawData = MS.ToArray(); - } - - return Response; - } - } -} diff --git a/Ryujinx.HLE/OsHle/Ipc/IpcMagic.cs b/Ryujinx.HLE/OsHle/Ipc/IpcMagic.cs deleted file mode 100644 index c3f9655f..00000000 --- a/Ryujinx.HLE/OsHle/Ipc/IpcMagic.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Ryujinx.HLE.OsHle.Ipc -{ - abstract class IpcMagic - { - public const long Sfci = 'S' << 0 | 'F' << 8 | 'C' << 16 | 'I' << 24; - public const long Sfco = 'S' << 0 | 'F' << 8 | 'C' << 16 | 'O' << 24; - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Ipc/IpcMessage.cs b/Ryujinx.HLE/OsHle/Ipc/IpcMessage.cs deleted file mode 100644 index 0a64a164..00000000 --- a/Ryujinx.HLE/OsHle/Ipc/IpcMessage.cs +++ /dev/null @@ -1,215 +0,0 @@ -using System.Collections.Generic; -using System.IO; - -namespace Ryujinx.HLE.OsHle.Ipc -{ - class IpcMessage - { - public IpcMessageType Type { get; set; } - - public IpcHandleDesc HandleDesc { get; set; } - - public List PtrBuff { get; private set; } - public List SendBuff { get; private set; } - public List ReceiveBuff { get; private set; } - public List ExchangeBuff { get; private set; } - public List RecvListBuff { get; private set; } - - public List ObjectIds { get; private set; } - - public byte[] RawData { get; set; } - - public IpcMessage() - { - PtrBuff = new List(); - SendBuff = new List(); - ReceiveBuff = new List(); - ExchangeBuff = new List(); - RecvListBuff = new List(); - - ObjectIds = new List(); - } - - public IpcMessage(byte[] Data, long CmdPtr) : this() - { - using (MemoryStream MS = new MemoryStream(Data)) - { - BinaryReader Reader = new BinaryReader(MS); - - Initialize(Reader, CmdPtr); - } - } - - private void Initialize(BinaryReader Reader, long CmdPtr) - { - int Word0 = Reader.ReadInt32(); - int Word1 = Reader.ReadInt32(); - - Type = (IpcMessageType)(Word0 & 0xffff); - - int PtrBuffCount = (Word0 >> 16) & 0xf; - int SendBuffCount = (Word0 >> 20) & 0xf; - int RecvBuffCount = (Word0 >> 24) & 0xf; - int XchgBuffCount = (Word0 >> 28) & 0xf; - - int RawDataSize = (Word1 >> 0) & 0x3ff; - int RecvListFlags = (Word1 >> 10) & 0xf; - bool HndDescEnable = ((Word1 >> 31) & 0x1) != 0; - - if (HndDescEnable) - { - HandleDesc = new IpcHandleDesc(Reader); - } - - for (int Index = 0; Index < PtrBuffCount; Index++) - { - PtrBuff.Add(new IpcPtrBuffDesc(Reader)); - } - - void ReadBuff(List Buff, int Count) - { - for (int Index = 0; Index < Count; Index++) - { - Buff.Add(new IpcBuffDesc(Reader)); - } - } - - ReadBuff(SendBuff, SendBuffCount); - ReadBuff(ReceiveBuff, RecvBuffCount); - ReadBuff(ExchangeBuff, XchgBuffCount); - - RawDataSize *= 4; - - long RecvListPos = Reader.BaseStream.Position + RawDataSize; - - long Pad0 = GetPadSize16(Reader.BaseStream.Position + CmdPtr); - - Reader.BaseStream.Seek(Pad0, SeekOrigin.Current); - - int RecvListCount = RecvListFlags - 2; - - if (RecvListCount == 0) - { - RecvListCount = 1; - } - else if (RecvListCount < 0) - { - RecvListCount = 0; - } - - RawData = Reader.ReadBytes(RawDataSize); - - Reader.BaseStream.Seek(RecvListPos, SeekOrigin.Begin); - - for (int Index = 0; Index < RecvListCount; Index++) - { - RecvListBuff.Add(new IpcRecvListBuffDesc(Reader)); - } - } - - public byte[] GetBytes(long CmdPtr) - { - using (MemoryStream MS = new MemoryStream()) - { - BinaryWriter Writer = new BinaryWriter(MS); - - int Word0; - int Word1; - - Word0 = (int)Type; - Word0 |= (PtrBuff.Count & 0xf) << 16; - Word0 |= (SendBuff.Count & 0xf) << 20; - Word0 |= (ReceiveBuff.Count & 0xf) << 24; - Word0 |= (ExchangeBuff.Count & 0xf) << 28; - - byte[] HandleData = new byte[0]; - - if (HandleDesc != null) - { - HandleData = HandleDesc.GetBytes(); - } - - int DataLength = RawData?.Length ?? 0; - - int Pad0 = (int)GetPadSize16(CmdPtr + 8 + HandleData.Length); - - //Apparently, padding after Raw Data is 16 bytes, however when there is - //padding before Raw Data too, we need to subtract the size of this padding. - //This is the weirdest padding I've seen so far... - int Pad1 = 0x10 - Pad0; - - DataLength = (DataLength + Pad0 + Pad1) / 4; - - Word1 = DataLength & 0x3ff; - - if (HandleDesc != null) - { - Word1 |= 1 << 31; - } - - Writer.Write(Word0); - Writer.Write(Word1); - Writer.Write(HandleData); - - MS.Seek(Pad0, SeekOrigin.Current); - - if (RawData != null) - { - Writer.Write(RawData); - } - - Writer.Write(new byte[Pad1]); - - return MS.ToArray(); - } - } - - private long GetPadSize16(long Position) - { - if ((Position & 0xf) != 0) - { - return 0x10 - (Position & 0xf); - } - - return 0; - } - - public (long Position, long Size) GetBufferType0x21() - { - if (PtrBuff.Count != 0 && - PtrBuff[0].Position != 0 && - PtrBuff[0].Size != 0) - { - return (PtrBuff[0].Position, PtrBuff[0].Size); - } - - if (SendBuff.Count != 0 && - SendBuff[0].Position != 0 && - SendBuff[0].Size != 0) - { - return (SendBuff[0].Position, SendBuff[0].Size); - } - - return (0, 0); - } - - public (long Position, long Size) GetBufferType0x22() - { - if (RecvListBuff.Count != 0 && - RecvListBuff[0].Position != 0 && - RecvListBuff[0].Size != 0) - { - return (RecvListBuff[0].Position, RecvListBuff[0].Size); - } - - if (ReceiveBuff.Count != 0 && - ReceiveBuff[0].Position != 0 && - ReceiveBuff[0].Size != 0) - { - return (ReceiveBuff[0].Position, ReceiveBuff[0].Size); - } - - return (0, 0); - } - } -} diff --git a/Ryujinx.HLE/OsHle/Ipc/IpcMessageType.cs b/Ryujinx.HLE/OsHle/Ipc/IpcMessageType.cs deleted file mode 100644 index 3db6844e..00000000 --- a/Ryujinx.HLE/OsHle/Ipc/IpcMessageType.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace Ryujinx.HLE.OsHle.Ipc -{ - enum IpcMessageType - { - Response = 0, - CloseSession = 2, - Request = 4, - Control = 5, - RequestWithContext = 6, - ControlWithContext = 7 - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Ipc/IpcPtrBuffDesc.cs b/Ryujinx.HLE/OsHle/Ipc/IpcPtrBuffDesc.cs deleted file mode 100644 index f5a9f651..00000000 --- a/Ryujinx.HLE/OsHle/Ipc/IpcPtrBuffDesc.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System.IO; - -namespace Ryujinx.HLE.OsHle.Ipc -{ - struct IpcPtrBuffDesc - { - public long Position { get; private set; } - public int Index { get; private set; } - public long Size { get; private set; } - - public IpcPtrBuffDesc(BinaryReader Reader) - { - long Word0 = Reader.ReadUInt32(); - long Word1 = Reader.ReadUInt32(); - - Position = Word1; - Position |= (Word0 << 20) & 0x0f00000000; - Position |= (Word0 << 30) & 0x7000000000; - - Index = ((int)Word0 >> 0) & 0x03f; - Index |= ((int)Word0 >> 3) & 0x1c0; - - Size = (ushort)(Word0 >> 16); - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Ipc/IpcRecvListBuffDesc.cs b/Ryujinx.HLE/OsHle/Ipc/IpcRecvListBuffDesc.cs deleted file mode 100644 index 59191c16..00000000 --- a/Ryujinx.HLE/OsHle/Ipc/IpcRecvListBuffDesc.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System.IO; - -namespace Ryujinx.HLE.OsHle.Ipc -{ - struct IpcRecvListBuffDesc - { - public long Position { get; private set; } - public long Size { get; private set; } - - public IpcRecvListBuffDesc(BinaryReader Reader) - { - long Value = Reader.ReadInt64(); - - Position = Value & 0xffffffffffff; - - Size = (ushort)(Value >> 48); - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Ipc/ServiceProcessRequest.cs b/Ryujinx.HLE/OsHle/Ipc/ServiceProcessRequest.cs deleted file mode 100644 index 47f72cb7..00000000 --- a/Ryujinx.HLE/OsHle/Ipc/ServiceProcessRequest.cs +++ /dev/null @@ -1,4 +0,0 @@ -namespace Ryujinx.HLE.OsHle.Ipc -{ - delegate long ServiceProcessRequest(ServiceCtx Context); -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Kernel/AddressArbiter.cs b/Ryujinx.HLE/OsHle/Kernel/AddressArbiter.cs deleted file mode 100644 index ce9ef0cd..00000000 --- a/Ryujinx.HLE/OsHle/Kernel/AddressArbiter.cs +++ /dev/null @@ -1,112 +0,0 @@ -using ChocolArm64.Memory; -using ChocolArm64.State; -using Ryujinx.HLE.OsHle.Handles; - -using static Ryujinx.HLE.OsHle.ErrorCode; - -namespace Ryujinx.HLE.OsHle.Kernel -{ - static class AddressArbiter - { - static ulong WaitForAddress(Process Process, AThreadState ThreadState, long Address, ulong Timeout) - { - KThread CurrentThread = Process.GetThread(ThreadState.Tpidr); - - Process.Scheduler.SetReschedule(CurrentThread.ProcessorId); - - CurrentThread.ArbiterWaitAddress = Address; - CurrentThread.ArbiterSignaled = false; - - Process.Scheduler.EnterWait(CurrentThread, NsTimeConverter.GetTimeMs(Timeout)); - - if (!CurrentThread.ArbiterSignaled) - { - return MakeError(ErrorModule.Kernel, KernelErr.Timeout); - } - - return 0; - } - - public static ulong WaitForAddressIfLessThan(Process Process, - AThreadState ThreadState, - AMemory Memory, - long Address, - int Value, - ulong Timeout, - bool ShouldDecrement) - { - Memory.SetExclusive(ThreadState, Address); - - int CurrentValue = Memory.ReadInt32(Address); - - while (true) - { - if (Memory.TestExclusive(ThreadState, Address)) - { - if (CurrentValue < Value) - { - if (ShouldDecrement) - { - Memory.WriteInt32(Address, CurrentValue - 1); - } - - Memory.ClearExclusiveForStore(ThreadState); - } - else - { - Memory.ClearExclusiveForStore(ThreadState); - - return MakeError(ErrorModule.Kernel, KernelErr.InvalidState); - } - - break; - } - - Memory.SetExclusive(ThreadState, Address); - - CurrentValue = Memory.ReadInt32(Address); - } - - if (Timeout == 0) - { - return MakeError(ErrorModule.Kernel, KernelErr.Timeout); - } - - return WaitForAddress(Process, ThreadState, Address, Timeout); - } - - public static ulong WaitForAddressIfEqual(Process Process, - AThreadState ThreadState, - AMemory Memory, - long Address, - int Value, - ulong Timeout) - { - if (Memory.ReadInt32(Address) != Value) - { - return MakeError(ErrorModule.Kernel, KernelErr.InvalidState); - } - - if (Timeout == 0) - { - return MakeError(ErrorModule.Kernel, KernelErr.Timeout); - } - - return WaitForAddress(Process, ThreadState, Address, Timeout); - } - } - - enum ArbitrationType : int - { - WaitIfLessThan, - DecrementAndWaitIfLessThan, - WaitIfEqual - } - - enum SignalType : int - { - Signal, - IncrementAndSignalIfEqual, - ModifyByWaitingCountAndSignalIfEqual - } -} diff --git a/Ryujinx.HLE/OsHle/Kernel/KernelErr.cs b/Ryujinx.HLE/OsHle/Kernel/KernelErr.cs deleted file mode 100644 index a62fc1bf..00000000 --- a/Ryujinx.HLE/OsHle/Kernel/KernelErr.cs +++ /dev/null @@ -1,22 +0,0 @@ -namespace Ryujinx.HLE.OsHle.Kernel -{ - static class KernelErr - { - public const int InvalidSize = 101; - public const int InvalidAddress = 102; - public const int OutOfMemory = 104; - public const int NoAccessPerm = 106; - public const int InvalidPermission = 108; - public const int InvalidMemRange = 110; - public const int InvalidPriority = 112; - public const int InvalidCoreId = 113; - public const int InvalidHandle = 114; - public const int InvalidMaskValue = 116; - public const int Timeout = 117; - public const int Canceled = 118; - public const int CountOutOfRange = 119; - public const int InvalidEnumValue = 120; - public const int InvalidThread = 122; - public const int InvalidState = 125; - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Kernel/NsTimeConverter.cs b/Ryujinx.HLE/OsHle/Kernel/NsTimeConverter.cs deleted file mode 100644 index 966fdaca..00000000 --- a/Ryujinx.HLE/OsHle/Kernel/NsTimeConverter.cs +++ /dev/null @@ -1,19 +0,0 @@ -namespace Ryujinx.HLE.OsHle.Kernel -{ - static class NsTimeConverter - { - public static int GetTimeMs(ulong Ns) - { - ulong Ms = Ns / 1_000_000; - - if (Ms < int.MaxValue) - { - return (int)Ms; - } - else - { - return int.MaxValue; - } - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Kernel/SvcHandler.cs b/Ryujinx.HLE/OsHle/Kernel/SvcHandler.cs deleted file mode 100644 index a33ffe5e..00000000 --- a/Ryujinx.HLE/OsHle/Kernel/SvcHandler.cs +++ /dev/null @@ -1,124 +0,0 @@ -using ChocolArm64.Events; -using ChocolArm64.Memory; -using ChocolArm64.State; -using Ryujinx.HLE.Logging; -using Ryujinx.HLE.OsHle.Handles; -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Threading; - -namespace Ryujinx.HLE.OsHle.Kernel -{ - partial class SvcHandler - { - private delegate void SvcFunc(AThreadState ThreadState); - - private Dictionary SvcFuncs; - - private Switch Ns; - private Process Process; - private AMemory Memory; - - private ConcurrentDictionary SyncWaits; - - private const uint SelfThreadHandle = 0xffff8000; - private const uint SelfProcessHandle = 0xffff8001; - - private static Random Rng; - - public SvcHandler(Switch Ns, Process Process) - { - SvcFuncs = new Dictionary() - { - { 0x01, SvcSetHeapSize }, - { 0x03, SvcSetMemoryAttribute }, - { 0x04, SvcMapMemory }, - { 0x05, SvcUnmapMemory }, - { 0x06, SvcQueryMemory }, - { 0x07, SvcExitProcess }, - { 0x08, SvcCreateThread }, - { 0x09, SvcStartThread }, - { 0x0a, SvcExitThread }, - { 0x0b, SvcSleepThread }, - { 0x0c, SvcGetThreadPriority }, - { 0x0d, SvcSetThreadPriority }, - { 0x0e, SvcGetThreadCoreMask }, - { 0x0f, SvcSetThreadCoreMask }, - { 0x10, SvcGetCurrentProcessorNumber }, - { 0x12, SvcClearEvent }, - { 0x13, SvcMapSharedMemory }, - { 0x14, SvcUnmapSharedMemory }, - { 0x15, SvcCreateTransferMemory }, - { 0x16, SvcCloseHandle }, - { 0x17, SvcResetSignal }, - { 0x18, SvcWaitSynchronization }, - { 0x19, SvcCancelSynchronization }, - { 0x1a, SvcArbitrateLock }, - { 0x1b, SvcArbitrateUnlock }, - { 0x1c, SvcWaitProcessWideKeyAtomic }, - { 0x1d, SvcSignalProcessWideKey }, - { 0x1e, SvcGetSystemTick }, - { 0x1f, SvcConnectToNamedPort }, - { 0x21, SvcSendSyncRequest }, - { 0x22, SvcSendSyncRequestWithUserBuffer }, - { 0x25, SvcGetThreadId }, - { 0x26, SvcBreak }, - { 0x27, SvcOutputDebugString }, - { 0x29, SvcGetInfo }, - { 0x2c, SvcMapPhysicalMemory }, - { 0x2d, SvcUnmapPhysicalMemory }, - { 0x32, SvcSetThreadActivity }, - { 0x33, SvcGetThreadContext3 }, - { 0x34, SvcWaitForAddress } - }; - - this.Ns = Ns; - this.Process = Process; - this.Memory = Process.Memory; - - SyncWaits = new ConcurrentDictionary(); - } - - static SvcHandler() - { - Rng = new Random(); - } - - public void SvcCall(object sender, AInstExceptionEventArgs e) - { - AThreadState ThreadState = (AThreadState)sender; - - Process.GetThread(ThreadState.Tpidr).LastPc = e.Position; - - if (SvcFuncs.TryGetValue(e.Id, out SvcFunc Func)) - { - Ns.Log.PrintDebug(LogClass.KernelSvc, $"{Func.Method.Name} called."); - - Func(ThreadState); - - Process.Scheduler.Reschedule(Process.GetThread(ThreadState.Tpidr)); - - Ns.Log.PrintDebug(LogClass.KernelSvc, $"{Func.Method.Name} ended."); - } - else - { - Process.PrintStackTrace(ThreadState); - - throw new NotImplementedException(e.Id.ToString("x4")); - } - } - - private KThread GetThread(long Tpidr, int Handle) - { - if ((uint)Handle == SelfThreadHandle) - { - return Process.GetThread(Tpidr); - } - else - { - return Process.HandleTable.GetData(Handle); - } - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Kernel/SvcMemory.cs b/Ryujinx.HLE/OsHle/Kernel/SvcMemory.cs deleted file mode 100644 index 68d87293..00000000 --- a/Ryujinx.HLE/OsHle/Kernel/SvcMemory.cs +++ /dev/null @@ -1,578 +0,0 @@ -using ChocolArm64.State; -using Ryujinx.HLE.Logging; -using Ryujinx.HLE.OsHle.Handles; - -using static Ryujinx.HLE.OsHle.ErrorCode; - -namespace Ryujinx.HLE.OsHle.Kernel -{ - partial class SvcHandler - { - private void SvcSetHeapSize(AThreadState ThreadState) - { - long Size = (long)ThreadState.X1; - - if ((Size & 0x1fffff) != 0 || Size != (uint)Size) - { - Ns.Log.PrintWarning(LogClass.KernelSvc, $"Heap size 0x{Size:x16} is not aligned!"); - - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidSize); - - return; - } - - long Result = Process.MemoryManager.TrySetHeapSize(Size, out long Position); - - ThreadState.X0 = (ulong)Result; - - if (Result == 0) - { - ThreadState.X1 = (ulong)Position; - } - else - { - Ns.Log.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!"); - } - } - - private void SvcSetMemoryAttribute(AThreadState ThreadState) - { - long Position = (long)ThreadState.X0; - long Size = (long)ThreadState.X1; - - if (!PageAligned(Position)) - { - Ns.Log.PrintWarning(LogClass.KernelSvc, $"Address 0x{Position:x16} is not page aligned!"); - - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress); - - return; - } - - if (!PageAligned(Size) || Size == 0) - { - Ns.Log.PrintWarning(LogClass.KernelSvc, $"Size 0x{Size:x16} is not page aligned or is zero!"); - - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidSize); - - return; - } - - MemoryAttribute AttributeMask = (MemoryAttribute)ThreadState.X2; - MemoryAttribute AttributeValue = (MemoryAttribute)ThreadState.X3; - - MemoryAttribute Attributes = AttributeMask | AttributeValue; - - if (Attributes != AttributeMask || - (Attributes | MemoryAttribute.Uncached) != MemoryAttribute.Uncached) - { - Ns.Log.PrintWarning(LogClass.KernelSvc, "Invalid memory attributes!"); - - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidMaskValue); - - return; - } - - long Result = Process.MemoryManager.SetMemoryAttribute( - Position, - Size, - AttributeMask, - AttributeValue); - - if (Result != 0) - { - Ns.Log.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!"); - } - else - { - Memory.StopObservingRegion(Position, Size); - } - - ThreadState.X0 = (ulong)Result; - } - - private void SvcMapMemory(AThreadState ThreadState) - { - long Dst = (long)ThreadState.X0; - long Src = (long)ThreadState.X1; - long Size = (long)ThreadState.X2; - - if (!PageAligned(Src | Dst)) - { - Ns.Log.PrintWarning(LogClass.KernelSvc, "Addresses are not page aligned!"); - - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress); - - return; - } - - if (!PageAligned(Size) || Size == 0) - { - Ns.Log.PrintWarning(LogClass.KernelSvc, $"Size 0x{Size:x16} is not page aligned or is zero!"); - - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidSize); - - return; - } - - if ((ulong)(Src + Size) <= (ulong)Src || (ulong)(Dst + Size) <= (ulong)Dst) - { - Ns.Log.PrintWarning(LogClass.KernelSvc, "Addresses outside of range!"); - - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); - - return; - } - - if (!InsideAddrSpace(Src, Size)) - { - Ns.Log.PrintWarning(LogClass.KernelSvc, $"Src address 0x{Src:x16} out of range!"); - - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); - - return; - } - - if (!InsideNewMapRegion(Dst, Size)) - { - Ns.Log.PrintWarning(LogClass.KernelSvc, $"Dst address 0x{Dst:x16} out of range!"); - - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidMemRange); - - return; - } - - long Result = Process.MemoryManager.Map(Src, Dst, Size); - - if (Result != 0) - { - Ns.Log.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!"); - } - - ThreadState.X0 = (ulong)Result; - } - - private void SvcUnmapMemory(AThreadState ThreadState) - { - long Dst = (long)ThreadState.X0; - long Src = (long)ThreadState.X1; - long Size = (long)ThreadState.X2; - - if (!PageAligned(Src | Dst)) - { - Ns.Log.PrintWarning(LogClass.KernelSvc, "Addresses are not page aligned!"); - - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress); - - return; - } - - if (!PageAligned(Size) || Size == 0) - { - Ns.Log.PrintWarning(LogClass.KernelSvc, $"Size 0x{Size:x16} is not page aligned or is zero!"); - - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidSize); - - return; - } - - if ((ulong)(Src + Size) <= (ulong)Src || (ulong)(Dst + Size) <= (ulong)Dst) - { - Ns.Log.PrintWarning(LogClass.KernelSvc, "Addresses outside of range!"); - - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); - - return; - } - - if (!InsideAddrSpace(Src, Size)) - { - Ns.Log.PrintWarning(LogClass.KernelSvc, $"Src address 0x{Src:x16} out of range!"); - - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); - - return; - } - - if (!InsideNewMapRegion(Dst, Size)) - { - Ns.Log.PrintWarning(LogClass.KernelSvc, $"Dst address 0x{Dst:x16} out of range!"); - - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidMemRange); - - return; - } - - long Result = Process.MemoryManager.Unmap(Src, Dst, Size); - - if (Result != 0) - { - Ns.Log.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!"); - } - - ThreadState.X0 = (ulong)Result; - } - - private void SvcQueryMemory(AThreadState ThreadState) - { - long InfoPtr = (long)ThreadState.X0; - long Position = (long)ThreadState.X2; - - KMemoryInfo BlkInfo = Process.MemoryManager.QueryMemory(Position); - - Memory.WriteInt64(InfoPtr + 0x00, BlkInfo.Position); - Memory.WriteInt64(InfoPtr + 0x08, BlkInfo.Size); - Memory.WriteInt32(InfoPtr + 0x10, (int)BlkInfo.State & 0xff); - Memory.WriteInt32(InfoPtr + 0x14, (int)BlkInfo.Attribute); - Memory.WriteInt32(InfoPtr + 0x18, (int)BlkInfo.Permission); - Memory.WriteInt32(InfoPtr + 0x1c, BlkInfo.IpcRefCount); - Memory.WriteInt32(InfoPtr + 0x20, BlkInfo.DeviceRefCount); - Memory.WriteInt32(InfoPtr + 0x24, 0); - - ThreadState.X0 = 0; - ThreadState.X1 = 0; - } - - private void SvcMapSharedMemory(AThreadState ThreadState) - { - int Handle = (int)ThreadState.X0; - long Position = (long)ThreadState.X1; - long Size = (long)ThreadState.X2; - - if (!PageAligned(Position)) - { - Ns.Log.PrintWarning(LogClass.KernelSvc, $"Address 0x{Position:x16} is not page aligned!"); - - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress); - - return; - } - - if (!PageAligned(Size) || Size == 0) - { - Ns.Log.PrintWarning(LogClass.KernelSvc, $"Size 0x{Size:x16} is not page aligned or is zero!"); - - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidSize); - - return; - } - - if ((ulong)(Position + Size) <= (ulong)Position) - { - Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid region address 0x{Position:x16} / size 0x{Size:x16}!"); - - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); - - return; - } - - MemoryPermission Permission = (MemoryPermission)ThreadState.X3; - - if ((Permission | MemoryPermission.Write) != MemoryPermission.ReadAndWrite) - { - Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid permission {Permission}!"); - - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidPermission); - - return; - } - - KSharedMemory SharedMemory = Process.HandleTable.GetData(Handle); - - if (SharedMemory == null) - { - Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid shared memory handle 0x{Handle:x8}!"); - - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle); - - return; - } - - if (!InsideAddrSpace(Position, Size) || InsideMapRegion(Position, Size) || InsideHeapRegion(Position, Size)) - { - Ns.Log.PrintWarning(LogClass.KernelSvc, $"Address 0x{Position:x16} out of range!"); - - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); - - return; - } - - if (SharedMemory.Size != Size) - { - Ns.Log.PrintWarning(LogClass.KernelSvc, $"Size 0x{Size:x16} does not match shared memory size 0x{SharedMemory.Size:16}!"); - - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidSize); - - return; - } - - long Result = Process.MemoryManager.MapSharedMemory(SharedMemory, Permission, Position); - - if (Result != 0) - { - Ns.Log.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!"); - } - - ThreadState.X0 = (ulong)Result; - } - - private void SvcUnmapSharedMemory(AThreadState ThreadState) - { - int Handle = (int)ThreadState.X0; - long Position = (long)ThreadState.X1; - long Size = (long)ThreadState.X2; - - if (!PageAligned(Position)) - { - Ns.Log.PrintWarning(LogClass.KernelSvc, $"Address 0x{Position:x16} is not page aligned!"); - - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress); - - return; - } - - if (!PageAligned(Size) || Size == 0) - { - Ns.Log.PrintWarning(LogClass.KernelSvc, $"Size 0x{Size:x16} is not page aligned or is zero!"); - - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidSize); - - return; - } - - if ((ulong)(Position + Size) <= (ulong)Position) - { - Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid region address 0x{Position:x16} / size 0x{Size:x16}!"); - - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); - - return; - } - - KSharedMemory SharedMemory = Process.HandleTable.GetData(Handle); - - if (SharedMemory == null) - { - Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid shared memory handle 0x{Handle:x8}!"); - - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle); - - return; - } - - if (!InsideAddrSpace(Position, Size) || InsideMapRegion(Position, Size) || InsideHeapRegion(Position, Size)) - { - Ns.Log.PrintWarning(LogClass.KernelSvc, $"Address 0x{Position:x16} out of range!"); - - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); - - return; - } - - long Result = Process.MemoryManager.UnmapSharedMemory(Position, Size); - - if (Result != 0) - { - Ns.Log.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!"); - } - - ThreadState.X0 = (ulong)Result; - } - - private void SvcCreateTransferMemory(AThreadState ThreadState) - { - long Position = (long)ThreadState.X1; - long Size = (long)ThreadState.X2; - - if (!PageAligned(Position)) - { - Ns.Log.PrintWarning(LogClass.KernelSvc, $"Address 0x{Position:x16} is not page aligned!"); - - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress); - - return; - } - - if (!PageAligned(Size) || Size == 0) - { - Ns.Log.PrintWarning(LogClass.KernelSvc, $"Size 0x{Size:x16} is not page aligned or is zero!"); - - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress); - - return; - } - - if ((ulong)(Position + Size) <= (ulong)Position) - { - Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid region address 0x{Position:x16} / size 0x{Size:x16}!"); - - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); - - return; - } - - MemoryPermission Permission = (MemoryPermission)ThreadState.X3; - - if (Permission > MemoryPermission.ReadAndWrite || Permission == MemoryPermission.Write) - { - Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid permission {Permission}!"); - - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidPermission); - - return; - } - - Process.MemoryManager.ReserveTransferMemory(Position, Size, Permission); - - KTransferMemory TransferMemory = new KTransferMemory(Position, Size); - - int Handle = Process.HandleTable.OpenHandle(TransferMemory); - - ThreadState.X0 = 0; - ThreadState.X1 = (ulong)Handle; - } - - private void SvcMapPhysicalMemory(AThreadState ThreadState) - { - long Position = (long)ThreadState.X0; - long Size = (long)ThreadState.X1; - - if (!PageAligned(Position)) - { - Ns.Log.PrintWarning(LogClass.KernelSvc, $"Address 0x{Position:x16} is not page aligned!"); - - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress); - - return; - } - - if (!PageAligned(Size) || Size == 0) - { - Ns.Log.PrintWarning(LogClass.KernelSvc, $"Size 0x{Size:x16} is not page aligned or is zero!"); - - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidSize); - - return; - } - - if ((ulong)(Position + Size) <= (ulong)Position) - { - Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid region address 0x{Position:x16} / size 0x{Size:x16}!"); - - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); - - return; - } - - if (!InsideAddrSpace(Position, Size)) - { - Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid address {Position:x16}!"); - - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); - - return; - } - - long Result = Process.MemoryManager.MapPhysicalMemory(Position, Size); - - if (Result != 0) - { - Ns.Log.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!"); - } - - ThreadState.X0 = (ulong)Result; - } - - private void SvcUnmapPhysicalMemory(AThreadState ThreadState) - { - long Position = (long)ThreadState.X0; - long Size = (long)ThreadState.X1; - - if (!PageAligned(Position)) - { - Ns.Log.PrintWarning(LogClass.KernelSvc, $"Address 0x{Position:x16} is not page aligned!"); - - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress); - - return; - } - - if (!PageAligned(Size) || Size == 0) - { - Ns.Log.PrintWarning(LogClass.KernelSvc, $"Size 0x{Size:x16} is not page aligned or is zero!"); - - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidSize); - - return; - } - - if ((ulong)(Position + Size) <= (ulong)Position) - { - Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid region address 0x{Position:x16} / size 0x{Size:x16}!"); - - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); - - return; - } - - if (!InsideAddrSpace(Position, Size)) - { - Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid address {Position:x16}!"); - - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); - - return; - } - - long Result = Process.MemoryManager.UnmapPhysicalMemory(Position, Size); - - if (Result != 0) - { - Ns.Log.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!"); - } - - ThreadState.X0 = (ulong)Result; - } - - private static bool PageAligned(long Position) - { - return (Position & (KMemoryManager.PageSize - 1)) == 0; - } - - private bool InsideAddrSpace(long Position, long Size) - { - ulong Start = (ulong)Position; - ulong End = (ulong)Size + Start; - - return Start >= (ulong)Process.MemoryManager.AddrSpaceStart && - End < (ulong)Process.MemoryManager.AddrSpaceEnd; - } - - private bool InsideMapRegion(long Position, long Size) - { - ulong Start = (ulong)Position; - ulong End = (ulong)Size + Start; - - return Start >= (ulong)Process.MemoryManager.MapRegionStart && - End < (ulong)Process.MemoryManager.MapRegionEnd; - } - - private bool InsideHeapRegion(long Position, long Size) - { - ulong Start = (ulong)Position; - ulong End = (ulong)Size + Start; - - return Start >= (ulong)Process.MemoryManager.HeapRegionStart && - End < (ulong)Process.MemoryManager.HeapRegionEnd; - } - - private bool InsideNewMapRegion(long Position, long Size) - { - ulong Start = (ulong)Position; - ulong End = (ulong)Size + Start; - - return Start >= (ulong)Process.MemoryManager.NewMapRegionStart && - End < (ulong)Process.MemoryManager.NewMapRegionEnd; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Kernel/SvcSystem.cs b/Ryujinx.HLE/OsHle/Kernel/SvcSystem.cs deleted file mode 100644 index f833745b..00000000 --- a/Ryujinx.HLE/OsHle/Kernel/SvcSystem.cs +++ /dev/null @@ -1,374 +0,0 @@ -using ChocolArm64.Memory; -using ChocolArm64.State; -using Ryujinx.HLE.Logging; -using Ryujinx.HLE.OsHle.Exceptions; -using Ryujinx.HLE.OsHle.Handles; -using Ryujinx.HLE.OsHle.Ipc; -using Ryujinx.HLE.OsHle.Services; -using System; -using System.Threading; - -using static Ryujinx.HLE.OsHle.ErrorCode; - -namespace Ryujinx.HLE.OsHle.Kernel -{ - partial class SvcHandler - { - private const int AllowedCpuIdBitmask = 0b1111; - - private const bool EnableProcessDebugging = false; - - private void SvcExitProcess(AThreadState ThreadState) - { - Ns.Os.ExitProcess(ThreadState.ProcessId); - } - - private void SvcClearEvent(AThreadState ThreadState) - { - int Handle = (int)ThreadState.X0; - - //TODO: Implement events. - - ThreadState.X0 = 0; - } - - private void SvcCloseHandle(AThreadState ThreadState) - { - int Handle = (int)ThreadState.X0; - - object Obj = Process.HandleTable.CloseHandle(Handle); - - if (Obj == null) - { - Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid handle 0x{Handle:x8}!"); - - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle); - - return; - } - - if (Obj is KSession Session) - { - Session.Dispose(); - } - else if (Obj is KTransferMemory TransferMemory) - { - Process.MemoryManager.ResetTransferMemory( - TransferMemory.Position, - TransferMemory.Size); - } - - ThreadState.X0 = 0; - } - - private void SvcResetSignal(AThreadState ThreadState) - { - int Handle = (int)ThreadState.X0; - - KEvent Event = Process.HandleTable.GetData(Handle); - - if (Event != null) - { - Event.WaitEvent.Reset(); - - ThreadState.X0 = 0; - } - else - { - Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid event handle 0x{Handle:x8}!"); - - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle); - } - } - - private void SvcWaitSynchronization(AThreadState ThreadState) - { - long HandlesPtr = (long)ThreadState.X1; - int HandlesCount = (int)ThreadState.X2; - ulong Timeout = ThreadState.X3; - - Ns.Log.PrintDebug(LogClass.KernelSvc, - "HandlesPtr = " + HandlesPtr .ToString("x16") + ", " + - "HandlesCount = " + HandlesCount.ToString("x8") + ", " + - "Timeout = " + Timeout .ToString("x16")); - - if ((uint)HandlesCount > 0x40) - { - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.CountOutOfRange); - - return; - } - - KThread CurrThread = Process.GetThread(ThreadState.Tpidr); - - WaitHandle[] Handles = new WaitHandle[HandlesCount + 1]; - - for (int Index = 0; Index < HandlesCount; Index++) - { - int Handle = Memory.ReadInt32(HandlesPtr + Index * 4); - - KSynchronizationObject SyncObj = Process.HandleTable.GetData(Handle); - - if (SyncObj == null) - { - Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid handle 0x{Handle:x8}!"); - - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle); - - return; - } - - Handles[Index] = SyncObj.WaitEvent; - } - - using (AutoResetEvent WaitEvent = new AutoResetEvent(false)) - { - if (!SyncWaits.TryAdd(CurrThread, WaitEvent)) - { - throw new InvalidOperationException(); - } - - Handles[HandlesCount] = WaitEvent; - - Process.Scheduler.Suspend(CurrThread); - - int HandleIndex; - - ulong Result = 0; - - if (Timeout != ulong.MaxValue) - { - HandleIndex = WaitHandle.WaitAny(Handles, NsTimeConverter.GetTimeMs(Timeout)); - } - else - { - HandleIndex = WaitHandle.WaitAny(Handles); - } - - if (HandleIndex == WaitHandle.WaitTimeout) - { - Result = MakeError(ErrorModule.Kernel, KernelErr.Timeout); - } - else if (HandleIndex == HandlesCount) - { - Result = MakeError(ErrorModule.Kernel, KernelErr.Canceled); - } - - SyncWaits.TryRemove(CurrThread, out _); - - Process.Scheduler.Resume(CurrThread); - - ThreadState.X0 = Result; - - if (Result == 0) - { - ThreadState.X1 = (ulong)HandleIndex; - } - } - } - - private void SvcCancelSynchronization(AThreadState ThreadState) - { - int ThreadHandle = (int)ThreadState.X0; - - KThread Thread = GetThread(ThreadState.Tpidr, ThreadHandle); - - if (Thread == null) - { - Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{ThreadHandle:x8}!"); - - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle); - - return; - } - - if (SyncWaits.TryRemove(Thread, out AutoResetEvent WaitEvent)) - { - WaitEvent.Set(); - } - - ThreadState.X0 = 0; - } - - private void SvcGetSystemTick(AThreadState ThreadState) - { - ThreadState.X0 = ThreadState.CntpctEl0; - } - - private void SvcConnectToNamedPort(AThreadState ThreadState) - { - long StackPtr = (long)ThreadState.X0; - long NamePtr = (long)ThreadState.X1; - - string Name = AMemoryHelper.ReadAsciiString(Memory, NamePtr, 8); - - //TODO: Validate that app has perms to access the service, and that the service - //actually exists, return error codes otherwise. - KSession Session = new KSession(ServiceFactory.MakeService(Name), Name); - - ulong Handle = (ulong)Process.HandleTable.OpenHandle(Session); - - ThreadState.X0 = 0; - ThreadState.X1 = Handle; - } - - private void SvcSendSyncRequest(AThreadState ThreadState) - { - SendSyncRequest(ThreadState, ThreadState.Tpidr, 0x100, (int)ThreadState.X0); - } - - private void SvcSendSyncRequestWithUserBuffer(AThreadState ThreadState) - { - SendSyncRequest( - ThreadState, - (long)ThreadState.X0, - (long)ThreadState.X1, - (int)ThreadState.X2); - } - - private void SendSyncRequest(AThreadState ThreadState, long CmdPtr, long Size, int Handle) - { - KThread CurrThread = Process.GetThread(ThreadState.Tpidr); - - byte[] CmdData = Memory.ReadBytes(CmdPtr, Size); - - KSession Session = Process.HandleTable.GetData(Handle); - - if (Session != null) - { - Process.Scheduler.Suspend(CurrThread); - - IpcMessage Cmd = new IpcMessage(CmdData, CmdPtr); - - long Result = IpcHandler.IpcCall(Ns, Process, Memory, Session, Cmd, CmdPtr); - - Thread.Yield(); - - Process.Scheduler.Resume(CurrThread); - - ThreadState.X0 = (ulong)Result; - } - else - { - Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid session handle 0x{Handle:x8}!"); - - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle); - } - } - - private void SvcBreak(AThreadState ThreadState) - { - long Reason = (long)ThreadState.X0; - long Unknown = (long)ThreadState.X1; - long Info = (long)ThreadState.X2; - - Process.PrintStackTrace(ThreadState); - - throw new GuestBrokeExecutionException(); - } - - private void SvcOutputDebugString(AThreadState ThreadState) - { - long Position = (long)ThreadState.X0; - long Size = (long)ThreadState.X1; - - string Str = AMemoryHelper.ReadAsciiString(Memory, Position, Size); - - Ns.Log.PrintWarning(LogClass.KernelSvc, Str); - - ThreadState.X0 = 0; - } - - private void SvcGetInfo(AThreadState ThreadState) - { - long StackPtr = (long)ThreadState.X0; - int InfoType = (int)ThreadState.X1; - long Handle = (long)ThreadState.X2; - int InfoId = (int)ThreadState.X3; - - //Fail for info not available on older Kernel versions. - if (InfoType == 18 || - InfoType == 19 || - InfoType == 20) - { - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidEnumValue); - - return; - } - - switch (InfoType) - { - case 0: - ThreadState.X1 = AllowedCpuIdBitmask; - break; - - case 2: - ThreadState.X1 = (ulong)Process.MemoryManager.MapRegionStart; - break; - - case 3: - ThreadState.X1 = (ulong)Process.MemoryManager.MapRegionEnd - - (ulong)Process.MemoryManager.MapRegionStart; - break; - - case 4: - ThreadState.X1 = (ulong)Process.MemoryManager.HeapRegionStart; - break; - - case 5: - ThreadState.X1 = (ulong)Process.MemoryManager.HeapRegionEnd - - (ulong)Process.MemoryManager.HeapRegionStart; - break; - - case 6: - ThreadState.X1 = (ulong)Process.Ns.Memory.Allocator.TotalAvailableSize; - break; - - case 7: - ThreadState.X1 = (ulong)Process.Ns.Memory.Allocator.TotalUsedSize; - break; - - case 8: - ThreadState.X1 = EnableProcessDebugging ? 1 : 0; - break; - - case 11: - ThreadState.X1 = (ulong)Rng.Next() + ((ulong)Rng.Next() << 32); - break; - - case 12: - ThreadState.X1 = (ulong)Process.MemoryManager.AddrSpaceStart; - break; - - case 13: - ThreadState.X1 = (ulong)Process.MemoryManager.AddrSpaceEnd - - (ulong)Process.MemoryManager.AddrSpaceStart; - break; - - case 14: - ThreadState.X1 = (ulong)Process.MemoryManager.NewMapRegionStart; - break; - - case 15: - ThreadState.X1 = (ulong)Process.MemoryManager.NewMapRegionEnd - - (ulong)Process.MemoryManager.NewMapRegionStart; - break; - - case 16: - ThreadState.X1 = (ulong)(Process.MetaData?.SystemResourceSize ?? 0); - break; - - case 17: - ThreadState.X1 = (ulong)Process.MemoryManager.PersonalMmHeapUsage; - break; - - default: - Process.PrintStackTrace(ThreadState); - - throw new NotImplementedException($"SvcGetInfo: {InfoType} {Handle:x8} {InfoId}"); - } - - ThreadState.X0 = 0; - } - } -} diff --git a/Ryujinx.HLE/OsHle/Kernel/SvcThread.cs b/Ryujinx.HLE/OsHle/Kernel/SvcThread.cs deleted file mode 100644 index 04524850..00000000 --- a/Ryujinx.HLE/OsHle/Kernel/SvcThread.cs +++ /dev/null @@ -1,386 +0,0 @@ -using ChocolArm64.State; -using Ryujinx.HLE.Logging; -using Ryujinx.HLE.OsHle.Handles; -using System.Threading; - -using static Ryujinx.HLE.OsHle.ErrorCode; - -namespace Ryujinx.HLE.OsHle.Kernel -{ - partial class SvcHandler - { - private void SvcCreateThread(AThreadState ThreadState) - { - long EntryPoint = (long)ThreadState.X1; - long ArgsPtr = (long)ThreadState.X2; - long StackTop = (long)ThreadState.X3; - int Priority = (int)ThreadState.X4; - int ProcessorId = (int)ThreadState.X5; - - if ((uint)Priority > 0x3f) - { - Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid priority 0x{Priority:x8}!"); - - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidPriority); - - return; - } - - if (ProcessorId == -2) - { - //TODO: Get this value from the NPDM file. - ProcessorId = 0; - } - else if ((uint)ProcessorId > 3) - { - Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid core id 0x{ProcessorId:x8}!"); - - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidCoreId); - - return; - } - - int Handle = Process.MakeThread( - EntryPoint, - StackTop, - ArgsPtr, - Priority, - ProcessorId); - - ThreadState.X0 = 0; - ThreadState.X1 = (ulong)Handle; - } - - private void SvcStartThread(AThreadState ThreadState) - { - int Handle = (int)ThreadState.X0; - - KThread NewThread = Process.HandleTable.GetData(Handle); - - if (NewThread != null) - { - Process.Scheduler.StartThread(NewThread); - Process.Scheduler.SetReschedule(NewThread.ProcessorId); - - ThreadState.X0 = 0; - } - else - { - Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{Handle:x8}!"); - - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle); - } - } - - private void SvcExitThread(AThreadState ThreadState) - { - KThread CurrThread = Process.GetThread(ThreadState.Tpidr); - - CurrThread.Thread.StopExecution(); - } - - private void SvcSleepThread(AThreadState ThreadState) - { - ulong TimeoutNs = ThreadState.X0; - - Ns.Log.PrintDebug(LogClass.KernelSvc, "Timeout = " + TimeoutNs.ToString("x16")); - - KThread CurrThread = Process.GetThread(ThreadState.Tpidr); - - if (TimeoutNs == 0 || TimeoutNs == ulong.MaxValue) - { - Process.Scheduler.Yield(CurrThread); - } - else - { - Process.Scheduler.Suspend(CurrThread); - - Thread.Sleep(NsTimeConverter.GetTimeMs(TimeoutNs)); - - Process.Scheduler.Resume(CurrThread); - } - } - - private void SvcGetThreadPriority(AThreadState ThreadState) - { - int Handle = (int)ThreadState.X1; - - KThread Thread = GetThread(ThreadState.Tpidr, Handle); - - if (Thread != null) - { - ThreadState.X0 = 0; - ThreadState.X1 = (ulong)Thread.ActualPriority; - } - else - { - Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{Handle:x8}!"); - - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle); - } - } - - private void SvcSetThreadPriority(AThreadState ThreadState) - { - int Handle = (int)ThreadState.X0; - int Priority = (int)ThreadState.X1; - - Ns.Log.PrintDebug(LogClass.KernelSvc, - "Handle = " + Handle .ToString("x8") + ", " + - "Priority = " + Priority.ToString("x8")); - - KThread Thread = GetThread(ThreadState.Tpidr, Handle); - - if (Thread != null) - { - Thread.SetPriority(Priority); - - ThreadState.X0 = 0; - } - else - { - Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{Handle:x8}!"); - - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle); - } - } - - private void SvcGetThreadCoreMask(AThreadState ThreadState) - { - int Handle = (int)ThreadState.X2; - - Ns.Log.PrintDebug(LogClass.KernelSvc, "Handle = " + Handle.ToString("x8")); - - KThread Thread = GetThread(ThreadState.Tpidr, Handle); - - if (Thread != null) - { - ThreadState.X0 = 0; - ThreadState.X1 = (ulong)Thread.IdealCore; - ThreadState.X2 = (ulong)Thread.CoreMask; - } - else - { - Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{Handle:x8}!"); - - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle); - } - } - - private void SvcSetThreadCoreMask(AThreadState ThreadState) - { - int Handle = (int)ThreadState.X0; - int IdealCore = (int)ThreadState.X1; - long CoreMask = (long)ThreadState.X2; - - Ns.Log.PrintDebug(LogClass.KernelSvc, - "Handle = " + Handle .ToString("x8") + ", " + - "IdealCore = " + IdealCore.ToString("x8") + ", " + - "CoreMask = " + CoreMask .ToString("x16")); - - KThread Thread = GetThread(ThreadState.Tpidr, Handle); - - if (IdealCore == -2) - { - //TODO: Get this value from the NPDM file. - IdealCore = 0; - - CoreMask = 1 << IdealCore; - } - else - { - if ((uint)IdealCore > 3) - { - if ((IdealCore | 2) != -1) - { - Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid core id 0x{IdealCore:x8}!"); - - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidCoreId); - - return; - } - } - else if ((CoreMask & (1 << IdealCore)) == 0) - { - Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid core mask 0x{CoreMask:x8}!"); - - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidMaskValue); - - return; - } - } - - if (Thread == null) - { - Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{Handle:x8}!"); - - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle); - - return; - } - - //-1 is used as "don't care", so the IdealCore value is ignored. - //-2 is used as "use NPDM default core id" (handled above). - //-3 is used as "don't update", the old IdealCore value is kept. - if (IdealCore == -3 && (CoreMask & (1 << Thread.IdealCore)) == 0) - { - Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid core mask 0x{CoreMask:x8}!"); - - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidMaskValue); - - return; - } - - Process.Scheduler.ChangeCore(Thread, IdealCore, (int)CoreMask); - - ThreadState.X0 = 0; - } - - private void SvcGetCurrentProcessorNumber(AThreadState ThreadState) - { - ThreadState.X0 = (ulong)Process.GetThread(ThreadState.Tpidr).ActualCore; - } - - private void SvcGetThreadId(AThreadState ThreadState) - { - int Handle = (int)ThreadState.X1; - - KThread Thread = GetThread(ThreadState.Tpidr, Handle); - - if (Thread != null) - { - ThreadState.X0 = 0; - ThreadState.X1 = (ulong)Thread.ThreadId; - } - else - { - Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{Handle:x8}!"); - - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle); - } - } - - private void SvcSetThreadActivity(AThreadState ThreadState) - { - int Handle = (int)ThreadState.X0; - bool Active = (int)ThreadState.X1 == 0; - - KThread Thread = Process.HandleTable.GetData(Handle); - - if (Thread != null) - { - Process.Scheduler.SetThreadActivity(Thread, Active); - - ThreadState.X0 = 0; - } - else - { - Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{Handle:x8}!"); - - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle); - } - } - - private void SvcGetThreadContext3(AThreadState ThreadState) - { - long Position = (long)ThreadState.X0; - int Handle = (int)ThreadState.X1; - - KThread Thread = Process.HandleTable.GetData(Handle); - - if (Thread == null) - { - Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{Handle:x8}!"); - - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle); - - return; - } - - if (Process.GetThread(ThreadState.Tpidr) == Thread) - { - Ns.Log.PrintWarning(LogClass.KernelSvc, $"Thread handle 0x{Handle:x8} is current thread!"); - - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidThread); - - return; - } - - Memory.WriteUInt64(Position + 0x0, ThreadState.X0); - Memory.WriteUInt64(Position + 0x8, ThreadState.X1); - Memory.WriteUInt64(Position + 0x10, ThreadState.X2); - Memory.WriteUInt64(Position + 0x18, ThreadState.X3); - Memory.WriteUInt64(Position + 0x20, ThreadState.X4); - Memory.WriteUInt64(Position + 0x28, ThreadState.X5); - Memory.WriteUInt64(Position + 0x30, ThreadState.X6); - Memory.WriteUInt64(Position + 0x38, ThreadState.X7); - Memory.WriteUInt64(Position + 0x40, ThreadState.X8); - Memory.WriteUInt64(Position + 0x48, ThreadState.X9); - Memory.WriteUInt64(Position + 0x50, ThreadState.X10); - Memory.WriteUInt64(Position + 0x58, ThreadState.X11); - Memory.WriteUInt64(Position + 0x60, ThreadState.X12); - Memory.WriteUInt64(Position + 0x68, ThreadState.X13); - Memory.WriteUInt64(Position + 0x70, ThreadState.X14); - Memory.WriteUInt64(Position + 0x78, ThreadState.X15); - Memory.WriteUInt64(Position + 0x80, ThreadState.X16); - Memory.WriteUInt64(Position + 0x88, ThreadState.X17); - Memory.WriteUInt64(Position + 0x90, ThreadState.X18); - Memory.WriteUInt64(Position + 0x98, ThreadState.X19); - Memory.WriteUInt64(Position + 0xa0, ThreadState.X20); - Memory.WriteUInt64(Position + 0xa8, ThreadState.X21); - Memory.WriteUInt64(Position + 0xb0, ThreadState.X22); - Memory.WriteUInt64(Position + 0xb8, ThreadState.X23); - Memory.WriteUInt64(Position + 0xc0, ThreadState.X24); - Memory.WriteUInt64(Position + 0xc8, ThreadState.X25); - Memory.WriteUInt64(Position + 0xd0, ThreadState.X26); - Memory.WriteUInt64(Position + 0xd8, ThreadState.X27); - Memory.WriteUInt64(Position + 0xe0, ThreadState.X28); - Memory.WriteUInt64(Position + 0xe8, ThreadState.X29); - Memory.WriteUInt64(Position + 0xf0, ThreadState.X30); - Memory.WriteUInt64(Position + 0xf8, ThreadState.X31); - - Memory.WriteInt64(Position + 0x100, Thread.LastPc); - - Memory.WriteUInt64(Position + 0x108, (ulong)ThreadState.Psr); - - Memory.WriteVector128(Position + 0x110, ThreadState.V0); - Memory.WriteVector128(Position + 0x120, ThreadState.V1); - Memory.WriteVector128(Position + 0x130, ThreadState.V2); - Memory.WriteVector128(Position + 0x140, ThreadState.V3); - Memory.WriteVector128(Position + 0x150, ThreadState.V4); - Memory.WriteVector128(Position + 0x160, ThreadState.V5); - Memory.WriteVector128(Position + 0x170, ThreadState.V6); - Memory.WriteVector128(Position + 0x180, ThreadState.V7); - Memory.WriteVector128(Position + 0x190, ThreadState.V8); - Memory.WriteVector128(Position + 0x1a0, ThreadState.V9); - Memory.WriteVector128(Position + 0x1b0, ThreadState.V10); - Memory.WriteVector128(Position + 0x1c0, ThreadState.V11); - Memory.WriteVector128(Position + 0x1d0, ThreadState.V12); - Memory.WriteVector128(Position + 0x1e0, ThreadState.V13); - Memory.WriteVector128(Position + 0x1f0, ThreadState.V14); - Memory.WriteVector128(Position + 0x200, ThreadState.V15); - Memory.WriteVector128(Position + 0x210, ThreadState.V16); - Memory.WriteVector128(Position + 0x220, ThreadState.V17); - Memory.WriteVector128(Position + 0x230, ThreadState.V18); - Memory.WriteVector128(Position + 0x240, ThreadState.V19); - Memory.WriteVector128(Position + 0x250, ThreadState.V20); - Memory.WriteVector128(Position + 0x260, ThreadState.V21); - Memory.WriteVector128(Position + 0x270, ThreadState.V22); - Memory.WriteVector128(Position + 0x280, ThreadState.V23); - Memory.WriteVector128(Position + 0x290, ThreadState.V24); - Memory.WriteVector128(Position + 0x2a0, ThreadState.V25); - Memory.WriteVector128(Position + 0x2b0, ThreadState.V26); - Memory.WriteVector128(Position + 0x2c0, ThreadState.V27); - Memory.WriteVector128(Position + 0x2d0, ThreadState.V28); - Memory.WriteVector128(Position + 0x2e0, ThreadState.V29); - Memory.WriteVector128(Position + 0x2f0, ThreadState.V30); - Memory.WriteVector128(Position + 0x300, ThreadState.V31); - - Memory.WriteInt32(Position + 0x310, ThreadState.Fpcr); - Memory.WriteInt32(Position + 0x314, ThreadState.Fpsr); - Memory.WriteInt64(Position + 0x318, ThreadState.Tpidr); - - ThreadState.X0 = 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Kernel/SvcThreadSync.cs b/Ryujinx.HLE/OsHle/Kernel/SvcThreadSync.cs deleted file mode 100644 index 164a85ca..00000000 --- a/Ryujinx.HLE/OsHle/Kernel/SvcThreadSync.cs +++ /dev/null @@ -1,524 +0,0 @@ -using ChocolArm64.State; -using Ryujinx.HLE.Logging; -using Ryujinx.HLE.OsHle.Handles; -using System; - -using static Ryujinx.HLE.OsHle.ErrorCode; - -namespace Ryujinx.HLE.OsHle.Kernel -{ - partial class SvcHandler - { - private const int MutexHasListenersMask = 0x40000000; - - private void SvcArbitrateLock(AThreadState ThreadState) - { - int OwnerThreadHandle = (int)ThreadState.X0; - long MutexAddress = (long)ThreadState.X1; - int WaitThreadHandle = (int)ThreadState.X2; - - Ns.Log.PrintDebug(LogClass.KernelSvc, - "OwnerThreadHandle = " + OwnerThreadHandle.ToString("x8") + ", " + - "MutexAddress = " + MutexAddress .ToString("x16") + ", " + - "WaitThreadHandle = " + WaitThreadHandle .ToString("x8")); - - if (IsPointingInsideKernel(MutexAddress)) - { - Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid mutex address 0x{MutexAddress:x16}!"); - - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); - - return; - } - - if (IsWordAddressUnaligned(MutexAddress)) - { - Ns.Log.PrintWarning(LogClass.KernelSvc, $"Unaligned mutex address 0x{MutexAddress:x16}!"); - - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress); - - return; - } - - KThread OwnerThread = Process.HandleTable.GetData(OwnerThreadHandle); - - if (OwnerThread == null) - { - Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid owner thread handle 0x{OwnerThreadHandle:x8}!"); - - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle); - - return; - } - - KThread WaitThread = Process.HandleTable.GetData(WaitThreadHandle); - - if (WaitThread == null) - { - Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid requesting thread handle 0x{WaitThreadHandle:x8}!"); - - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle); - - return; - } - - KThread CurrThread = Process.GetThread(ThreadState.Tpidr); - - MutexLock(CurrThread, WaitThread, OwnerThreadHandle, WaitThreadHandle, MutexAddress); - - ThreadState.X0 = 0; - } - - private void SvcArbitrateUnlock(AThreadState ThreadState) - { - long MutexAddress = (long)ThreadState.X0; - - Ns.Log.PrintDebug(LogClass.KernelSvc, "MutexAddress = " + MutexAddress.ToString("x16")); - - if (IsPointingInsideKernel(MutexAddress)) - { - Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid mutex address 0x{MutexAddress:x16}!"); - - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); - - return; - } - - if (IsWordAddressUnaligned(MutexAddress)) - { - Ns.Log.PrintWarning(LogClass.KernelSvc, $"Unaligned mutex address 0x{MutexAddress:x16}!"); - - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress); - - return; - } - - MutexUnlock(Process.GetThread(ThreadState.Tpidr), MutexAddress); - - ThreadState.X0 = 0; - } - - private void SvcWaitProcessWideKeyAtomic(AThreadState ThreadState) - { - long MutexAddress = (long)ThreadState.X0; - long CondVarAddress = (long)ThreadState.X1; - int ThreadHandle = (int)ThreadState.X2; - ulong Timeout = ThreadState.X3; - - Ns.Log.PrintDebug(LogClass.KernelSvc, - "MutexAddress = " + MutexAddress .ToString("x16") + ", " + - "CondVarAddress = " + CondVarAddress.ToString("x16") + ", " + - "ThreadHandle = " + ThreadHandle .ToString("x8") + ", " + - "Timeout = " + Timeout .ToString("x16")); - - if (IsPointingInsideKernel(MutexAddress)) - { - Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid mutex address 0x{MutexAddress:x16}!"); - - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); - - return; - } - - if (IsWordAddressUnaligned(MutexAddress)) - { - Ns.Log.PrintWarning(LogClass.KernelSvc, $"Unaligned mutex address 0x{MutexAddress:x16}!"); - - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress); - - return; - } - - KThread Thread = Process.HandleTable.GetData(ThreadHandle); - - if (Thread == null) - { - Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{ThreadHandle:x8}!"); - - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle); - - return; - } - - KThread WaitThread = Process.GetThread(ThreadState.Tpidr); - - if (!CondVarWait(WaitThread, ThreadHandle, MutexAddress, CondVarAddress, Timeout)) - { - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.Timeout); - - return; - } - - ThreadState.X0 = 0; - } - - private void SvcSignalProcessWideKey(AThreadState ThreadState) - { - long CondVarAddress = (long)ThreadState.X0; - int Count = (int)ThreadState.X1; - - Ns.Log.PrintDebug(LogClass.KernelSvc, - "CondVarAddress = " + CondVarAddress.ToString("x16") + ", " + - "Count = " + Count .ToString("x8")); - - KThread CurrThread = Process.GetThread(ThreadState.Tpidr); - - CondVarSignal(ThreadState, CurrThread, CondVarAddress, Count); - - ThreadState.X0 = 0; - } - - private void MutexLock( - KThread CurrThread, - KThread WaitThread, - int OwnerThreadHandle, - int WaitThreadHandle, - long MutexAddress) - { - lock (Process.ThreadSyncLock) - { - int MutexValue = Memory.ReadInt32(MutexAddress); - - Ns.Log.PrintDebug(LogClass.KernelSvc, "MutexValue = " + MutexValue.ToString("x8")); - - if (MutexValue != (OwnerThreadHandle | MutexHasListenersMask)) - { - return; - } - - CurrThread.WaitHandle = WaitThreadHandle; - CurrThread.MutexAddress = MutexAddress; - - InsertWaitingMutexThreadUnsafe(OwnerThreadHandle, WaitThread); - } - - Ns.Log.PrintDebug(LogClass.KernelSvc, "Entering wait state..."); - - Process.Scheduler.EnterWait(CurrThread); - } - - private void SvcWaitForAddress(AThreadState ThreadState) - { - long Address = (long)ThreadState.X0; - ArbitrationType Type = (ArbitrationType)ThreadState.X1; - int Value = (int)ThreadState.X2; - ulong Timeout = ThreadState.X3; - - Ns.Log.PrintDebug(LogClass.KernelSvc, - "Address = " + Address.ToString("x16") + ", " + - "ArbitrationType = " + Type .ToString() + ", " + - "Value = " + Value .ToString("x8") + ", " + - "Timeout = " + Timeout.ToString("x16")); - - if (IsPointingInsideKernel(Address)) - { - Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid address 0x{Address:x16}!"); - - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); - - return; - } - - if (IsWordAddressUnaligned(Address)) - { - Ns.Log.PrintWarning(LogClass.KernelSvc, $"Unaligned address 0x{Address:x16}!"); - - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress); - - return; - } - - switch (Type) - { - case ArbitrationType.WaitIfLessThan: - ThreadState.X0 = AddressArbiter.WaitForAddressIfLessThan(Process, ThreadState, Memory, Address, Value, Timeout, false); - break; - - case ArbitrationType.DecrementAndWaitIfLessThan: - ThreadState.X0 = AddressArbiter.WaitForAddressIfLessThan(Process, ThreadState, Memory, Address, Value, Timeout, true); - break; - - case ArbitrationType.WaitIfEqual: - ThreadState.X0 = AddressArbiter.WaitForAddressIfEqual(Process, ThreadState, Memory, Address, Value, Timeout); - break; - - default: - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidEnumValue); - break; - } - } - - private void MutexUnlock(KThread CurrThread, long MutexAddress) - { - lock (Process.ThreadSyncLock) - { - //This is the new thread that will now own the mutex. - //If no threads are waiting for the lock, then it should be null. - (KThread OwnerThread, int Count) = PopMutexThreadUnsafe(CurrThread, MutexAddress); - - if (OwnerThread == CurrThread) - { - throw new InvalidOperationException(); - } - - if (OwnerThread != null) - { - //Remove all waiting mutex from the old owner, - //and insert then on the new owner. - UpdateMutexOwnerUnsafe(CurrThread, OwnerThread, MutexAddress); - - CurrThread.UpdatePriority(); - - int HasListeners = Count >= 2 ? MutexHasListenersMask : 0; - - Memory.WriteInt32ToSharedAddr(MutexAddress, HasListeners | OwnerThread.WaitHandle); - - OwnerThread.WaitHandle = 0; - OwnerThread.MutexAddress = 0; - OwnerThread.CondVarAddress = 0; - OwnerThread.MutexOwner = null; - - OwnerThread.UpdatePriority(); - - Process.Scheduler.WakeUp(OwnerThread); - - Ns.Log.PrintDebug(LogClass.KernelSvc, "Gave mutex to thread id " + OwnerThread.ThreadId + "!"); - } - else - { - Memory.WriteInt32ToSharedAddr(MutexAddress, 0); - - Ns.Log.PrintDebug(LogClass.KernelSvc, "No threads waiting mutex!"); - } - } - } - - private bool CondVarWait( - KThread WaitThread, - int WaitThreadHandle, - long MutexAddress, - long CondVarAddress, - ulong Timeout) - { - WaitThread.WaitHandle = WaitThreadHandle; - WaitThread.MutexAddress = MutexAddress; - WaitThread.CondVarAddress = CondVarAddress; - - lock (Process.ThreadSyncLock) - { - MutexUnlock(WaitThread, MutexAddress); - - WaitThread.CondVarSignaled = false; - - Process.ThreadArbiterList.Add(WaitThread); - } - - Ns.Log.PrintDebug(LogClass.KernelSvc, "Entering wait state..."); - - if (Timeout != ulong.MaxValue) - { - Process.Scheduler.EnterWait(WaitThread, NsTimeConverter.GetTimeMs(Timeout)); - - lock (Process.ThreadSyncLock) - { - if (!WaitThread.CondVarSignaled || WaitThread.MutexOwner != null) - { - if (WaitThread.MutexOwner != null) - { - WaitThread.MutexOwner.MutexWaiters.Remove(WaitThread); - WaitThread.MutexOwner.UpdatePriority(); - - WaitThread.MutexOwner = null; - } - - Process.ThreadArbiterList.Remove(WaitThread); - - Ns.Log.PrintDebug(LogClass.KernelSvc, "Timed out..."); - - return false; - } - } - } - else - { - Process.Scheduler.EnterWait(WaitThread); - } - - return true; - } - - private void CondVarSignal( - AThreadState ThreadState, - KThread CurrThread, - long CondVarAddress, - int Count) - { - lock (Process.ThreadSyncLock) - { - while (Count == -1 || Count-- > 0) - { - KThread WaitThread = PopCondVarThreadUnsafe(CondVarAddress); - - if (WaitThread == null) - { - Ns.Log.PrintDebug(LogClass.KernelSvc, "No more threads to wake up!"); - - break; - } - - WaitThread.CondVarSignaled = true; - - long MutexAddress = WaitThread.MutexAddress; - - Memory.SetExclusive(ThreadState, MutexAddress); - - int MutexValue = Memory.ReadInt32(MutexAddress); - - while (MutexValue != 0) - { - if (Memory.TestExclusive(ThreadState, MutexAddress)) - { - //Wait until the lock is released. - InsertWaitingMutexThreadUnsafe(MutexValue & ~MutexHasListenersMask, WaitThread); - - Memory.WriteInt32(MutexAddress, MutexValue | MutexHasListenersMask); - - Memory.ClearExclusiveForStore(ThreadState); - - break; - } - - Memory.SetExclusive(ThreadState, MutexAddress); - - MutexValue = Memory.ReadInt32(MutexAddress); - } - - Ns.Log.PrintDebug(LogClass.KernelSvc, "MutexValue = " + MutexValue.ToString("x8")); - - if (MutexValue == 0) - { - //Give the lock to this thread. - Memory.WriteInt32ToSharedAddr(MutexAddress, WaitThread.WaitHandle); - - WaitThread.WaitHandle = 0; - WaitThread.MutexAddress = 0; - WaitThread.CondVarAddress = 0; - - WaitThread.MutexOwner?.UpdatePriority(); - - WaitThread.MutexOwner = null; - - Process.Scheduler.WakeUp(WaitThread); - } - } - } - } - - private void UpdateMutexOwnerUnsafe(KThread CurrThread, KThread NewOwner, long MutexAddress) - { - //Go through all threads waiting for the mutex, - //and update the MutexOwner field to point to the new owner. - for (int Index = 0; Index < CurrThread.MutexWaiters.Count; Index++) - { - KThread Thread = CurrThread.MutexWaiters[Index]; - - if (Thread.MutexAddress == MutexAddress) - { - CurrThread.MutexWaiters.RemoveAt(Index--); - - InsertWaitingMutexThreadUnsafe(NewOwner, Thread); - } - } - } - - private void InsertWaitingMutexThreadUnsafe(int OwnerThreadHandle, KThread WaitThread) - { - KThread OwnerThread = Process.HandleTable.GetData(OwnerThreadHandle); - - if (OwnerThread == null) - { - Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{OwnerThreadHandle:x8}!"); - - return; - } - - InsertWaitingMutexThreadUnsafe(OwnerThread, WaitThread); - } - - private void InsertWaitingMutexThreadUnsafe(KThread OwnerThread, KThread WaitThread) - { - WaitThread.MutexOwner = OwnerThread; - - if (!OwnerThread.MutexWaiters.Contains(WaitThread)) - { - OwnerThread.MutexWaiters.Add(WaitThread); - - OwnerThread.UpdatePriority(); - } - } - - private (KThread, int) PopMutexThreadUnsafe(KThread OwnerThread, long MutexAddress) - { - int Count = 0; - - KThread WakeThread = null; - - foreach (KThread Thread in OwnerThread.MutexWaiters) - { - if (Thread.MutexAddress != MutexAddress) - { - continue; - } - - if (WakeThread == null || Thread.ActualPriority < WakeThread.ActualPriority) - { - WakeThread = Thread; - } - - Count++; - } - - if (WakeThread != null) - { - OwnerThread.MutexWaiters.Remove(WakeThread); - } - - return (WakeThread, Count); - } - - private KThread PopCondVarThreadUnsafe(long CondVarAddress) - { - KThread WakeThread = null; - - foreach (KThread Thread in Process.ThreadArbiterList) - { - if (Thread.CondVarAddress != CondVarAddress) - { - continue; - } - - if (WakeThread == null || Thread.ActualPriority < WakeThread.ActualPriority) - { - WakeThread = Thread; - } - } - - if (WakeThread != null) - { - Process.ThreadArbiterList.Remove(WakeThread); - } - - return WakeThread; - } - - private bool IsPointingInsideKernel(long Address) - { - return ((ulong)Address + 0x1000000000) < 0xffffff000; - } - - private bool IsWordAddressUnaligned(long Address) - { - return (Address & 3) != 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/MemoryType.cs b/Ryujinx.HLE/OsHle/MemoryType.cs deleted file mode 100644 index 64b07947..00000000 --- a/Ryujinx.HLE/OsHle/MemoryType.cs +++ /dev/null @@ -1,25 +0,0 @@ -namespace Ryujinx.HLE.OsHle -{ - enum MemoryType - { - Unmapped = 0, - Io = 1, - Normal = 2, - CodeStatic = 3, - CodeMutable = 4, - Heap = 5, - SharedMemory = 6, - ModCodeStatic = 8, - ModCodeMutable = 9, - IpcBuffer0 = 10, - MappedMemory = 11, - ThreadLocal = 12, - TransferMemoryIsolated = 13, - TransferMemory = 14, - ProcessMemory = 15, - Reserved = 16, - IpcBuffer1 = 17, - IpcBuffer3 = 18, - KernelStack = 19 - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Process.cs b/Ryujinx.HLE/OsHle/Process.cs deleted file mode 100644 index 96fe3610..00000000 --- a/Ryujinx.HLE/OsHle/Process.cs +++ /dev/null @@ -1,457 +0,0 @@ -using ChocolArm64; -using ChocolArm64.Events; -using ChocolArm64.Memory; -using ChocolArm64.State; -using Ryujinx.HLE.Loaders; -using Ryujinx.HLE.Loaders.Executables; -using Ryujinx.HLE.Loaders.Npdm; -using Ryujinx.HLE.Logging; -using Ryujinx.HLE.OsHle.Diagnostics; -using Ryujinx.HLE.OsHle.Exceptions; -using Ryujinx.HLE.OsHle.Handles; -using Ryujinx.HLE.OsHle.Kernel; -using Ryujinx.HLE.OsHle.Services.Nv; -using Ryujinx.HLE.OsHle.SystemState; -using Ryujinx.HLE.OsHle.Utilities; -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.IO; -using System.Text; - -namespace Ryujinx.HLE.OsHle -{ - class Process : IDisposable - { - private const int TickFreq = 19_200_000; - - public Switch Ns { get; private set; } - - public bool NeedsHbAbi { get; private set; } - - public long HbAbiDataPosition { get; private set; } - - public int ProcessId { get; private set; } - - private ATranslator Translator; - - public AMemory Memory { get; private set; } - - public KMemoryManager MemoryManager { get; private set; } - - private List TlsPages; - - public KProcessScheduler Scheduler { get; private set; } - - public List ThreadArbiterList { get; private set; } - - public object ThreadSyncLock { get; private set; } - - public Npdm MetaData { get; private set; } - - public KProcessHandleTable HandleTable { get; private set; } - - public AppletStateMgr AppletState { get; private set; } - - private SvcHandler SvcHandler; - - private ConcurrentDictionary Threads; - - private KThread MainThread; - - private List Executables; - - private Dictionary SymbolTable; - - private long ImageBase; - - private bool ShouldDispose; - - private bool Disposed; - - public Process(Switch Ns, KProcessScheduler Scheduler, int ProcessId, Npdm MetaData) - { - this.Ns = Ns; - this.Scheduler = Scheduler; - this.MetaData = MetaData; - this.ProcessId = ProcessId; - - Memory = new AMemory(Ns.Memory.RamPointer); - - MemoryManager = new KMemoryManager(this); - - TlsPages = new List(); - - ThreadArbiterList = new List(); - - ThreadSyncLock = new object(); - - HandleTable = new KProcessHandleTable(); - - AppletState = new AppletStateMgr(); - - SvcHandler = new SvcHandler(Ns, this); - - Threads = new ConcurrentDictionary(); - - Executables = new List(); - - ImageBase = MemoryManager.CodeRegionStart; - } - - public void LoadProgram(IExecutable Program) - { - if (Disposed) - { - throw new ObjectDisposedException(nameof(Process)); - } - - Ns.Log.PrintInfo(LogClass.Loader, $"Image base at 0x{ImageBase:x16}."); - - Executable Executable = new Executable(Program, MemoryManager, Memory, ImageBase); - - Executables.Add(Executable); - - ImageBase = IntUtils.AlignUp(Executable.ImageEnd, KMemoryManager.PageSize); - } - - public void SetEmptyArgs() - { - //TODO: This should be part of Run. - ImageBase += KMemoryManager.PageSize; - } - - public bool Run(bool NeedsHbAbi = false) - { - if (Disposed) - { - throw new ObjectDisposedException(nameof(Process)); - } - - this.NeedsHbAbi = NeedsHbAbi; - - if (Executables.Count == 0) - { - return false; - } - - MakeSymbolTable(); - - long MainStackTop = MemoryManager.CodeRegionEnd - KMemoryManager.PageSize; - - long MainStackSize = 1 * 1024 * 1024; - - long MainStackBottom = MainStackTop - MainStackSize; - - MemoryManager.HleMapCustom( - MainStackBottom, - MainStackSize, - MemoryState.MappedMemory, - MemoryPermission.ReadAndWrite); - - int Handle = MakeThread(Executables[0].ImageBase, MainStackTop, 0, 44, 0); - - if (Handle == -1) - { - return false; - } - - MainThread = HandleTable.GetData(Handle); - - if (NeedsHbAbi) - { - HbAbiDataPosition = IntUtils.AlignUp(Executables[0].ImageEnd, KMemoryManager.PageSize); - - const long HbAbiDataSize = KMemoryManager.PageSize; - - MemoryManager.HleMapCustom( - HbAbiDataPosition, - HbAbiDataSize, - MemoryState.MappedMemory, - MemoryPermission.ReadAndWrite); - - string SwitchPath = Ns.VFs.SystemPathToSwitchPath(Executables[0].FilePath); - - Homebrew.WriteHbAbiData(Memory, HbAbiDataPosition, Handle, SwitchPath); - - MainThread.Thread.ThreadState.X0 = (ulong)HbAbiDataPosition; - MainThread.Thread.ThreadState.X1 = ulong.MaxValue; - } - - Scheduler.StartThread(MainThread); - - return true; - } - - public void StopAllThreadsAsync() - { - if (Disposed) - { - throw new ObjectDisposedException(nameof(Process)); - } - - if (MainThread != null) - { - MainThread.Thread.StopExecution(); - } - - foreach (KThread Thread in Threads.Values) - { - Thread.Thread.StopExecution(); - } - } - - public int MakeThread( - long EntryPoint, - long StackTop, - long ArgsPtr, - int Priority, - int ProcessorId) - { - if (Disposed) - { - throw new ObjectDisposedException(nameof(Process)); - } - - AThread CpuThread = new AThread(GetTranslator(), Memory, EntryPoint); - - KThread Thread = new KThread(CpuThread, this, ProcessorId, Priority); - - Thread.LastPc = EntryPoint; - - int Handle = HandleTable.OpenHandle(Thread); - - long Tpidr = GetFreeTls(); - - int ThreadId = (int)((Tpidr - MemoryManager.TlsIoRegionStart) / 0x200) + 1; - - CpuThread.ThreadState.ProcessId = ProcessId; - CpuThread.ThreadState.ThreadId = ThreadId; - CpuThread.ThreadState.CntfrqEl0 = TickFreq; - CpuThread.ThreadState.Tpidr = Tpidr; - - CpuThread.ThreadState.X0 = (ulong)ArgsPtr; - CpuThread.ThreadState.X1 = (ulong)Handle; - CpuThread.ThreadState.X31 = (ulong)StackTop; - - CpuThread.ThreadState.Break += BreakHandler; - CpuThread.ThreadState.SvcCall += SvcHandler.SvcCall; - CpuThread.ThreadState.Undefined += UndefinedHandler; - - CpuThread.WorkFinished += ThreadFinished; - - Threads.TryAdd(CpuThread.ThreadState.Tpidr, Thread); - - return Handle; - } - - private long GetFreeTls() - { - long Position; - - lock (TlsPages) - { - for (int Index = 0; Index < TlsPages.Count; Index++) - { - if (TlsPages[Index].TryGetFreeTlsAddr(out Position)) - { - return Position; - } - } - - long PagePosition = MemoryManager.HleMapTlsPage(); - - KTlsPageManager TlsPage = new KTlsPageManager(PagePosition); - - TlsPages.Add(TlsPage); - - TlsPage.TryGetFreeTlsAddr(out Position); - } - - return Position; - } - - private void BreakHandler(object sender, AInstExceptionEventArgs e) - { - throw new GuestBrokeExecutionException(); - } - - private void UndefinedHandler(object sender, AInstUndefinedEventArgs e) - { - throw new UndefinedInstructionException(e.Position, e.RawOpCode); - } - - private void MakeSymbolTable() - { - SymbolTable = new Dictionary(); - - foreach (Executable Exe in Executables) - { - foreach (KeyValuePair KV in Exe.SymbolTable) - { - SymbolTable.TryAdd(Exe.ImageBase + KV.Key, KV.Value); - } - } - } - - private ATranslator GetTranslator() - { - if (Translator == null) - { - Translator = new ATranslator(SymbolTable); - - Translator.CpuTrace += CpuTraceHandler; - } - - return Translator; - } - - public void EnableCpuTracing() - { - Translator.EnableCpuTrace = true; - } - - public void DisableCpuTracing() - { - Translator.EnableCpuTrace = false; - } - - private void CpuTraceHandler(object sender, ACpuTraceEventArgs e) - { - string NsoName = string.Empty; - - for (int Index = Executables.Count - 1; Index >= 0; Index--) - { - if (e.Position >= Executables[Index].ImageBase) - { - NsoName = $"{(e.Position - Executables[Index].ImageBase):x16}"; - - break; - } - } - - Ns.Log.PrintDebug(LogClass.Cpu, $"Executing at 0x{e.Position:x16} {e.SubName} {NsoName}"); - } - - public void PrintStackTrace(AThreadState ThreadState) - { - long[] Positions = ThreadState.GetCallStack(); - - StringBuilder Trace = new StringBuilder(); - - Trace.AppendLine("Guest stack trace:"); - - foreach (long Position in Positions) - { - if (!SymbolTable.TryGetValue(Position, out string SubName)) - { - SubName = $"Sub{Position:x16}"; - } - else if (SubName.StartsWith("_Z")) - { - SubName = Demangler.Parse(SubName); - } - - Trace.AppendLine(" " + SubName + " (" + GetNsoNameAndAddress(Position) + ")"); - } - - Ns.Log.PrintInfo(LogClass.Cpu, Trace.ToString()); - } - - private string GetNsoNameAndAddress(long Position) - { - string Name = string.Empty; - - for (int Index = Executables.Count - 1; Index >= 0; Index--) - { - if (Position >= Executables[Index].ImageBase) - { - long Offset = Position - Executables[Index].ImageBase; - - Name = $"{Executables[Index].Name}:{Offset:x8}"; - - break; - } - } - - return Name; - } - - private void ThreadFinished(object sender, EventArgs e) - { - if (sender is AThread Thread) - { - Threads.TryRemove(Thread.ThreadState.Tpidr, out KThread KernelThread); - - Scheduler.RemoveThread(KernelThread); - - KernelThread.WaitEvent.Set(); - } - - if (Threads.Count == 0) - { - if (ShouldDispose) - { - Dispose(); - } - - Ns.Os.ExitProcess(ProcessId); - } - } - - public KThread GetThread(long Tpidr) - { - if (!Threads.TryGetValue(Tpidr, out KThread Thread)) - { - throw new InvalidOperationException(); - } - - return Thread; - } - - public void Dispose() - { - Dispose(true); - } - - protected virtual void Dispose(bool Disposing) - { - if (Disposing && !Disposed) - { - //If there is still some thread running, disposing the objects is not - //safe as the thread may try to access those resources. Instead, we set - //the flag to have the Process disposed when all threads finishes. - //Note: This may not happen if the guest code gets stuck on a infinite loop. - if (Threads.Count > 0) - { - ShouldDispose = true; - - Ns.Log.PrintInfo(LogClass.Loader, $"Process {ProcessId} waiting all threads terminate..."); - - return; - } - - Disposed = true; - - foreach (object Obj in HandleTable.Clear()) - { - if (Obj is KSession Session) - { - Session.Dispose(); - } - } - - if (NeedsHbAbi && Executables.Count > 0 && Executables[0].FilePath.EndsWith(Homebrew.TemporaryNroSuffix)) - { - File.Delete(Executables[0].FilePath); - } - - INvDrvServices.UnloadProcess(this); - - AppletState.Dispose(); - - Ns.Log.PrintInfo(LogClass.Loader, $"Process {ProcessId} exiting..."); - } - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/ServiceCtx.cs b/Ryujinx.HLE/OsHle/ServiceCtx.cs deleted file mode 100644 index eb9ff5fd..00000000 --- a/Ryujinx.HLE/OsHle/ServiceCtx.cs +++ /dev/null @@ -1,39 +0,0 @@ -using ChocolArm64.Memory; -using Ryujinx.HLE.OsHle.Handles; -using Ryujinx.HLE.OsHle.Ipc; -using System.IO; - -namespace Ryujinx.HLE.OsHle -{ - class ServiceCtx - { - public Switch Ns { get; private set; } - public Process Process { get; private set; } - public AMemory Memory { get; private set; } - public KSession Session { get; private set; } - public IpcMessage Request { get; private set; } - public IpcMessage Response { get; private set; } - public BinaryReader RequestData { get; private set; } - public BinaryWriter ResponseData { get; private set; } - - public ServiceCtx( - Switch Ns, - Process Process, - AMemory Memory, - KSession Session, - IpcMessage Request, - IpcMessage Response, - BinaryReader RequestData, - BinaryWriter ResponseData) - { - this.Ns = Ns; - this.Process = Process; - this.Memory = Memory; - this.Session = Session; - this.Request = Request; - this.Response = Response; - this.RequestData = RequestData; - this.ResponseData = ResponseData; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Acc/AccErr.cs b/Ryujinx.HLE/OsHle/Services/Acc/AccErr.cs deleted file mode 100644 index 5daef1aa..00000000 --- a/Ryujinx.HLE/OsHle/Services/Acc/AccErr.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Ryujinx.HLE.OsHle.Services.Acc -{ - static class AccErr - { - public const int UserNotFound = 100; - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Acc/IAccountServiceForApplication.cs b/Ryujinx.HLE/OsHle/Services/Acc/IAccountServiceForApplication.cs deleted file mode 100644 index 34376a7b..00000000 --- a/Ryujinx.HLE/OsHle/Services/Acc/IAccountServiceForApplication.cs +++ /dev/null @@ -1,126 +0,0 @@ -using ChocolArm64.Memory; -using Ryujinx.HLE.Logging; -using Ryujinx.HLE.OsHle.Ipc; -using Ryujinx.HLE.OsHle.SystemState; -using System.Collections.Generic; - -using static Ryujinx.HLE.OsHle.ErrorCode; - -namespace Ryujinx.HLE.OsHle.Services.Acc -{ - class IAccountServiceForApplication : IpcService - { - private Dictionary m_Commands; - - public override IReadOnlyDictionary Commands => m_Commands; - - public IAccountServiceForApplication() - { - m_Commands = new Dictionary() - { - { 0, GetUserCount }, - { 1, GetUserExistence }, - { 2, ListAllUsers }, - { 3, ListOpenUsers }, - { 4, GetLastOpenedUser }, - { 5, GetProfile }, - { 100, InitializeApplicationInfo }, - { 101, GetBaasAccountManagerForApplication } - }; - } - - public long GetUserCount(ServiceCtx Context) - { - Context.ResponseData.Write(Context.Ns.Os.SystemState.GetUserCount()); - - return 0; - } - - public long GetUserExistence(ServiceCtx Context) - { - UserId Uuid = new UserId( - Context.RequestData.ReadInt64(), - Context.RequestData.ReadInt64()); - - Context.ResponseData.Write(Context.Ns.Os.SystemState.TryGetUser(Uuid, out _) ? 1 : 0); - - return 0; - } - - public long ListAllUsers(ServiceCtx Context) - { - return WriteUserList(Context, Context.Ns.Os.SystemState.GetAllUsers()); - } - - public long ListOpenUsers(ServiceCtx Context) - { - return WriteUserList(Context, Context.Ns.Os.SystemState.GetOpenUsers()); - } - - private long WriteUserList(ServiceCtx Context, IEnumerable Profiles) - { - long OutputPosition = Context.Request.RecvListBuff[0].Position; - long OutputSize = Context.Request.RecvListBuff[0].Size; - - long Offset = 0; - - foreach (UserProfile Profile in Profiles) - { - if ((ulong)Offset + 16 > (ulong)OutputSize) - { - break; - } - - byte[] Uuid = Profile.Uuid.Bytes; - - for (int Index = Uuid.Length - 1; Index >= 0; Index--) - { - Context.Memory.WriteByte(OutputPosition + Offset++, Uuid[Index]); - } - } - - return 0; - } - - public long GetLastOpenedUser(ServiceCtx Context) - { - UserProfile LastOpened = Context.Ns.Os.SystemState.LastOpenUser; - - LastOpened.Uuid.Write(Context.ResponseData); - - return 0; - } - - public long GetProfile(ServiceCtx Context) - { - UserId Uuid = new UserId( - Context.RequestData.ReadInt64(), - Context.RequestData.ReadInt64()); - - if (!Context.Ns.Os.SystemState.TryGetUser(Uuid, out UserProfile Profile)) - { - Context.Ns.Log.PrintWarning(LogClass.ServiceAcc, $"User 0x{Uuid} not found!"); - - return MakeError(ErrorModule.Account, AccErr.UserNotFound); - } - - MakeObject(Context, new IProfile(Profile)); - - return 0; - } - - public long InitializeApplicationInfo(ServiceCtx Context) - { - Context.Ns.Log.PrintStub(LogClass.ServiceAcc, "Stubbed."); - - return 0; - } - - public long GetBaasAccountManagerForApplication(ServiceCtx Context) - { - MakeObject(Context, new IManagerForApplication()); - - return 0; - } - } -} diff --git a/Ryujinx.HLE/OsHle/Services/Acc/IManagerForApplication.cs b/Ryujinx.HLE/OsHle/Services/Acc/IManagerForApplication.cs deleted file mode 100644 index ce3865f4..00000000 --- a/Ryujinx.HLE/OsHle/Services/Acc/IManagerForApplication.cs +++ /dev/null @@ -1,38 +0,0 @@ -using Ryujinx.HLE.Logging; -using Ryujinx.HLE.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.HLE.OsHle.Services.Acc -{ - class IManagerForApplication : IpcService - { - private Dictionary m_Commands; - - public override IReadOnlyDictionary Commands => m_Commands; - - public IManagerForApplication() - { - m_Commands = new Dictionary() - { - { 0, CheckAvailability }, - { 1, GetAccountId } - }; - } - - public long CheckAvailability(ServiceCtx Context) - { - Context.Ns.Log.PrintStub(LogClass.ServiceAcc, "Stubbed."); - - return 0; - } - - public long GetAccountId(ServiceCtx Context) - { - Context.Ns.Log.PrintStub(LogClass.ServiceAcc, "Stubbed."); - - Context.ResponseData.Write(0xcafeL); - - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Acc/IProfile.cs b/Ryujinx.HLE/OsHle/Services/Acc/IProfile.cs deleted file mode 100644 index bb1e885e..00000000 --- a/Ryujinx.HLE/OsHle/Services/Acc/IProfile.cs +++ /dev/null @@ -1,58 +0,0 @@ -using ChocolArm64.Memory; -using Ryujinx.HLE.Logging; -using Ryujinx.HLE.OsHle.Ipc; -using Ryujinx.HLE.OsHle.SystemState; -using Ryujinx.HLE.OsHle.Utilities; -using System.Collections.Generic; -using System.Text; - -namespace Ryujinx.HLE.OsHle.Services.Acc -{ - class IProfile : IpcService - { - private Dictionary m_Commands; - - public override IReadOnlyDictionary Commands => m_Commands; - - private UserProfile Profile; - - public IProfile(UserProfile Profile) - { - m_Commands = new Dictionary() - { - { 0, Get }, - { 1, GetBase } - }; - - this.Profile = Profile; - } - - public long Get(ServiceCtx Context) - { - Context.Ns.Log.PrintStub(LogClass.ServiceAcc, "Stubbed."); - - long Position = Context.Request.ReceiveBuff[0].Position; - - AMemoryHelper.FillWithZeros(Context.Memory, Position, 0x80); - - Context.Memory.WriteInt32(Position, 0); - Context.Memory.WriteInt32(Position + 4, 1); - Context.Memory.WriteInt64(Position + 8, 1); - - return GetBase(Context); - } - - public long GetBase(ServiceCtx Context) - { - Profile.Uuid.Write(Context.ResponseData); - - Context.ResponseData.Write(Profile.LastModifiedTimestamp); - - byte[] Username = StringUtils.GetFixedLengthBytes(Profile.Name, 0x20, Encoding.UTF8); - - Context.ResponseData.Write(Username); - - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Am/AmErr.cs b/Ryujinx.HLE/OsHle/Services/Am/AmErr.cs deleted file mode 100644 index 66224639..00000000 --- a/Ryujinx.HLE/OsHle/Services/Am/AmErr.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Ryujinx.HLE.OsHle.Services.Am -{ - static class AmErr - { - public const int NoMessages = 3; - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Am/FocusState.cs b/Ryujinx.HLE/OsHle/Services/Am/FocusState.cs deleted file mode 100644 index 074f159e..00000000 --- a/Ryujinx.HLE/OsHle/Services/Am/FocusState.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Ryujinx.HLE.OsHle.Services.Am -{ - enum FocusState - { - InFocus = 1, - OutOfFocus = 2 - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Am/IAllSystemAppletProxiesService.cs b/Ryujinx.HLE/OsHle/Services/Am/IAllSystemAppletProxiesService.cs deleted file mode 100644 index 8dc17cec..00000000 --- a/Ryujinx.HLE/OsHle/Services/Am/IAllSystemAppletProxiesService.cs +++ /dev/null @@ -1,27 +0,0 @@ -using Ryujinx.HLE.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.HLE.OsHle.Services.Am -{ - class IAllSystemAppletProxiesService : IpcService - { - private Dictionary m_Commands; - - public override IReadOnlyDictionary Commands => m_Commands; - - public IAllSystemAppletProxiesService() - { - m_Commands = new Dictionary() - { - { 100, OpenSystemAppletProxy } - }; - } - - public long OpenSystemAppletProxy(ServiceCtx Context) - { - MakeObject(Context, new ISystemAppletProxy()); - - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Am/IApplicationCreator.cs b/Ryujinx.HLE/OsHle/Services/Am/IApplicationCreator.cs deleted file mode 100644 index 6ee5b5c2..00000000 --- a/Ryujinx.HLE/OsHle/Services/Am/IApplicationCreator.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Ryujinx.HLE.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.HLE.OsHle.Services.Am -{ - class IApplicationCreator : IpcService - { - private Dictionary m_Commands; - - public override IReadOnlyDictionary Commands => m_Commands; - - public IApplicationCreator() - { - m_Commands = new Dictionary() - { - //... - }; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Am/IApplicationFunctions.cs b/Ryujinx.HLE/OsHle/Services/Am/IApplicationFunctions.cs deleted file mode 100644 index e25b524a..00000000 --- a/Ryujinx.HLE/OsHle/Services/Am/IApplicationFunctions.cs +++ /dev/null @@ -1,117 +0,0 @@ -using Ryujinx.HLE.Logging; -using Ryujinx.HLE.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.HLE.OsHle.Services.Am -{ - class IApplicationFunctions : IpcService - { - private Dictionary m_Commands; - - public override IReadOnlyDictionary Commands => m_Commands; - - public IApplicationFunctions() - { - m_Commands = new Dictionary() - { - { 1, PopLaunchParameter }, - { 20, EnsureSaveData }, - { 21, GetDesiredLanguage }, - { 22, SetTerminateResult }, - { 23, GetDisplayVersion }, - { 40, NotifyRunning }, - { 50, GetPseudoDeviceId }, - { 66, InitializeGamePlayRecording }, - { 67, SetGamePlayRecordingState } - }; - } - - public long PopLaunchParameter(ServiceCtx Context) - { - //Only the first 0x18 bytes of the Data seems to be actually used. - MakeObject(Context, new IStorage(StorageHelper.MakeLaunchParams())); - - return 0; - } - - public long EnsureSaveData(ServiceCtx Context) - { - long UIdLow = Context.RequestData.ReadInt64(); - long UIdHigh = Context.RequestData.ReadInt64(); - - Context.Ns.Log.PrintStub(LogClass.ServiceAm, "Stubbed."); - - Context.ResponseData.Write(0L); - - return 0; - } - - public long GetDesiredLanguage(ServiceCtx Context) - { - Context.ResponseData.Write(Context.Ns.Os.SystemState.DesiredLanguageCode); - - return 0; - } - - public long SetTerminateResult(ServiceCtx Context) - { - int ErrorCode = Context.RequestData.ReadInt32(); - - string Result = GetFormattedErrorCode(ErrorCode); - - Context.Ns.Log.PrintInfo(LogClass.ServiceAm, $"Result = 0x{ErrorCode:x8} ({Result})."); - - return 0; - } - - private string GetFormattedErrorCode(int ErrorCode) - { - int Module = (ErrorCode >> 0) & 0x1ff; - int Description = (ErrorCode >> 9) & 0x1fff; - - return $"{(2000 + Module):d4}-{Description:d4}"; - } - - public long GetDisplayVersion(ServiceCtx Context) - { - //FIXME: Need to check correct version on a switch. - Context.ResponseData.Write(1L); - Context.ResponseData.Write(0L); - - return 0; - } - - public long NotifyRunning(ServiceCtx Context) - { - Context.ResponseData.Write(1); - - return 0; - } - - public long GetPseudoDeviceId(ServiceCtx Context) - { - Context.Ns.Log.PrintStub(LogClass.ServiceAm, "Stubbed."); - - Context.ResponseData.Write(0L); - Context.ResponseData.Write(0L); - - return 0; - } - - public long InitializeGamePlayRecording(ServiceCtx Context) - { - Context.Ns.Log.PrintStub(LogClass.ServiceAm, "Stubbed."); - - return 0; - } - - public long SetGamePlayRecordingState(ServiceCtx Context) - { - int State = Context.RequestData.ReadInt32(); - - Context.Ns.Log.PrintStub(LogClass.ServiceAm, "Stubbed."); - - return 0; - } - } -} diff --git a/Ryujinx.HLE/OsHle/Services/Am/IApplicationProxy.cs b/Ryujinx.HLE/OsHle/Services/Am/IApplicationProxy.cs deleted file mode 100644 index ec028502..00000000 --- a/Ryujinx.HLE/OsHle/Services/Am/IApplicationProxy.cs +++ /dev/null @@ -1,83 +0,0 @@ -using Ryujinx.HLE.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.HLE.OsHle.Services.Am -{ - class IApplicationProxy : IpcService - { - private Dictionary m_Commands; - - public override IReadOnlyDictionary Commands => m_Commands; - - public IApplicationProxy() - { - m_Commands = new Dictionary() - { - { 0, GetCommonStateGetter }, - { 1, GetSelfController }, - { 2, GetWindowController }, - { 3, GetAudioController }, - { 4, GetDisplayController }, - { 11, GetLibraryAppletCreator }, - { 20, GetApplicationFunctions }, - { 1000, GetDebugFunctions } - }; - } - - public long GetCommonStateGetter(ServiceCtx Context) - { - MakeObject(Context, new ICommonStateGetter()); - - return 0; - } - - public long GetSelfController(ServiceCtx Context) - { - MakeObject(Context, new ISelfController()); - - return 0; - } - - public long GetWindowController(ServiceCtx Context) - { - MakeObject(Context, new IWindowController()); - - return 0; - } - - public long GetAudioController(ServiceCtx Context) - { - MakeObject(Context, new IAudioController()); - - return 0; - } - - public long GetDisplayController(ServiceCtx Context) - { - MakeObject(Context, new IDisplayController()); - - return 0; - } - - public long GetLibraryAppletCreator(ServiceCtx Context) - { - MakeObject(Context, new ILibraryAppletCreator()); - - return 0; - } - - public long GetApplicationFunctions(ServiceCtx Context) - { - MakeObject(Context, new IApplicationFunctions()); - - return 0; - } - - public long GetDebugFunctions(ServiceCtx Context) - { - MakeObject(Context, new IDebugFunctions()); - - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Am/IApplicationProxyService.cs b/Ryujinx.HLE/OsHle/Services/Am/IApplicationProxyService.cs deleted file mode 100644 index 6b39b265..00000000 --- a/Ryujinx.HLE/OsHle/Services/Am/IApplicationProxyService.cs +++ /dev/null @@ -1,27 +0,0 @@ -using Ryujinx.HLE.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.HLE.OsHle.Services.Am -{ - class IApplicationProxyService : IpcService - { - private Dictionary m_Commands; - - public override IReadOnlyDictionary Commands => m_Commands; - - public IApplicationProxyService() - { - m_Commands = new Dictionary() - { - { 0, OpenApplicationProxy } - }; - } - - public long OpenApplicationProxy(ServiceCtx Context) - { - MakeObject(Context, new IApplicationProxy()); - - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Am/IAudioController.cs b/Ryujinx.HLE/OsHle/Services/Am/IAudioController.cs deleted file mode 100644 index 3cb63181..00000000 --- a/Ryujinx.HLE/OsHle/Services/Am/IAudioController.cs +++ /dev/null @@ -1,72 +0,0 @@ -using Ryujinx.HLE.Logging; -using Ryujinx.HLE.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.HLE.OsHle.Services.Am -{ - class IAudioController : IpcService - { - private Dictionary m_Commands; - - public override IReadOnlyDictionary Commands => m_Commands; - - public IAudioController() - { - m_Commands = new Dictionary() - { - { 0, SetExpectedMasterVolume }, - { 1, GetMainAppletExpectedMasterVolume }, - { 2, GetLibraryAppletExpectedMasterVolume }, - { 3, ChangeMainAppletMasterVolume }, - { 4, SetTransparentVolumeRate } - }; - } - - public long SetExpectedMasterVolume(ServiceCtx Context) - { - float AppletVolume = Context.RequestData.ReadSingle(); - float LibraryAppletVolume = Context.RequestData.ReadSingle(); - - Context.Ns.Log.PrintStub(LogClass.ServiceAm, "Stubbed."); - - return 0; - } - - public long GetMainAppletExpectedMasterVolume(ServiceCtx Context) - { - Context.ResponseData.Write(1f); - - Context.Ns.Log.PrintStub(LogClass.ServiceAm, "Stubbed."); - - return 0; - } - - public long GetLibraryAppletExpectedMasterVolume(ServiceCtx Context) - { - Context.ResponseData.Write(1f); - - Context.Ns.Log.PrintStub(LogClass.ServiceAm, "Stubbed."); - - return 0; - } - - public long ChangeMainAppletMasterVolume(ServiceCtx Context) - { - float Unknown0 = Context.RequestData.ReadSingle(); - long Unknown1 = Context.RequestData.ReadInt64(); - - Context.Ns.Log.PrintStub(LogClass.ServiceAm, "Stubbed."); - - return 0; - } - - public long SetTransparentVolumeRate(ServiceCtx Context) - { - float Unknown0 = Context.RequestData.ReadSingle(); - - Context.Ns.Log.PrintStub(LogClass.ServiceAm, "Stubbed."); - - return 0; - } - } -} diff --git a/Ryujinx.HLE/OsHle/Services/Am/ICommonStateGetter.cs b/Ryujinx.HLE/OsHle/Services/Am/ICommonStateGetter.cs deleted file mode 100644 index 2d04151c..00000000 --- a/Ryujinx.HLE/OsHle/Services/Am/ICommonStateGetter.cs +++ /dev/null @@ -1,115 +0,0 @@ -using Ryujinx.HLE.Logging; -using Ryujinx.HLE.OsHle.Handles; -using Ryujinx.HLE.OsHle.Ipc; -using System.Collections.Generic; - -using static Ryujinx.HLE.OsHle.ErrorCode; - -namespace Ryujinx.HLE.OsHle.Services.Am -{ - class ICommonStateGetter : IpcService - { - private Dictionary m_Commands; - - public override IReadOnlyDictionary Commands => m_Commands; - - private KEvent DisplayResolutionChangeEvent; - - public ICommonStateGetter() - { - m_Commands = new Dictionary() - { - { 0, GetEventHandle }, - { 1, ReceiveMessage }, - { 5, GetOperationMode }, - { 6, GetPerformanceMode }, - { 8, GetBootMode }, - { 9, GetCurrentFocusState }, - { 60, GetDefaultDisplayResolution }, - { 61, GetDefaultDisplayResolutionChangeEvent } - }; - - DisplayResolutionChangeEvent = new KEvent(); - } - - public long GetEventHandle(ServiceCtx Context) - { - KEvent Event = Context.Process.AppletState.MessageEvent; - - int Handle = Context.Process.HandleTable.OpenHandle(Event); - - Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle); - - return 0; - } - - public long ReceiveMessage(ServiceCtx Context) - { - if (!Context.Process.AppletState.TryDequeueMessage(out MessageInfo Message)) - { - return MakeError(ErrorModule.Am, AmErr.NoMessages); - } - - Context.ResponseData.Write((int)Message); - - return 0; - } - - public long GetOperationMode(ServiceCtx Context) - { - OperationMode Mode = Context.Ns.Os.SystemState.DockedMode - ? OperationMode.Docked - : OperationMode.Handheld; - - Context.ResponseData.Write((byte)Mode); - - return 0; - } - - public long GetPerformanceMode(ServiceCtx Context) - { - Apm.PerformanceMode Mode = Context.Ns.Os.SystemState.DockedMode - ? Apm.PerformanceMode.Docked - : Apm.PerformanceMode.Handheld; - - Context.ResponseData.Write((int)Mode); - - return 0; - } - - public long GetBootMode(ServiceCtx Context) - { - Context.ResponseData.Write((byte)0); //Unknown value. - - Context.Ns.Log.PrintStub(LogClass.ServiceAm, "Stubbed."); - - return 0; - } - - public long GetCurrentFocusState(ServiceCtx Context) - { - Context.ResponseData.Write((byte)Context.Process.AppletState.FocusState); - - return 0; - } - - public long GetDefaultDisplayResolution(ServiceCtx Context) - { - Context.ResponseData.Write(1280); - Context.ResponseData.Write(720); - - return 0; - } - - public long GetDefaultDisplayResolutionChangeEvent(ServiceCtx Context) - { - int Handle = Context.Process.HandleTable.OpenHandle(DisplayResolutionChangeEvent); - - Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle); - - Context.Ns.Log.PrintStub(LogClass.ServiceAm, "Stubbed."); - - return 0; - } - } -} diff --git a/Ryujinx.HLE/OsHle/Services/Am/IDebugFunctions.cs b/Ryujinx.HLE/OsHle/Services/Am/IDebugFunctions.cs deleted file mode 100644 index b07c68dd..00000000 --- a/Ryujinx.HLE/OsHle/Services/Am/IDebugFunctions.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Ryujinx.HLE.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.HLE.OsHle.Services.Am -{ - class IDebugFunctions : IpcService - { - private Dictionary m_Commands; - - public override IReadOnlyDictionary Commands => m_Commands; - - public IDebugFunctions() - { - m_Commands = new Dictionary() - { - //... - }; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Am/IDisplayController.cs b/Ryujinx.HLE/OsHle/Services/Am/IDisplayController.cs deleted file mode 100644 index 8785f071..00000000 --- a/Ryujinx.HLE/OsHle/Services/Am/IDisplayController.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Ryujinx.HLE.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.HLE.OsHle.Services.Am -{ - class IDisplayController : IpcService - { - private Dictionary m_Commands; - - public override IReadOnlyDictionary Commands => m_Commands; - - public IDisplayController() - { - m_Commands = new Dictionary() - { - //... - }; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Am/IGlobalStateController.cs b/Ryujinx.HLE/OsHle/Services/Am/IGlobalStateController.cs deleted file mode 100644 index 0fbcb284..00000000 --- a/Ryujinx.HLE/OsHle/Services/Am/IGlobalStateController.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Ryujinx.HLE.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.HLE.OsHle.Services.Am -{ - class IGlobalStateController : IpcService - { - private Dictionary m_Commands; - - public override IReadOnlyDictionary Commands => m_Commands; - - public IGlobalStateController() - { - m_Commands = new Dictionary() - { - //... - }; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Am/IHomeMenuFunctions.cs b/Ryujinx.HLE/OsHle/Services/Am/IHomeMenuFunctions.cs deleted file mode 100644 index 1005fe0c..00000000 --- a/Ryujinx.HLE/OsHle/Services/Am/IHomeMenuFunctions.cs +++ /dev/null @@ -1,46 +0,0 @@ -using Ryujinx.HLE.Logging; -using Ryujinx.HLE.OsHle.Handles; -using Ryujinx.HLE.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.HLE.OsHle.Services.Am -{ - class IHomeMenuFunctions : IpcService - { - private Dictionary m_Commands; - - public override IReadOnlyDictionary Commands => m_Commands; - - private KEvent ChannelEvent; - - public IHomeMenuFunctions() - { - m_Commands = new Dictionary() - { - { 10, RequestToGetForeground }, - { 21, GetPopFromGeneralChannelEvent } - }; - - //ToDo: Signal this Event somewhere in future. - ChannelEvent = new KEvent(); - } - - public long RequestToGetForeground(ServiceCtx Context) - { - Context.Ns.Log.PrintStub(LogClass.ServiceAm, "Stubbed."); - - return 0; - } - - public long GetPopFromGeneralChannelEvent(ServiceCtx Context) - { - int Handle = Context.Process.HandleTable.OpenHandle(ChannelEvent); - - Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle); - - Context.Ns.Log.PrintStub(LogClass.ServiceAm, "Stubbed."); - - return 0; - } - } -} diff --git a/Ryujinx.HLE/OsHle/Services/Am/ILibraryAppletAccessor.cs b/Ryujinx.HLE/OsHle/Services/Am/ILibraryAppletAccessor.cs deleted file mode 100644 index b1955cc6..00000000 --- a/Ryujinx.HLE/OsHle/Services/Am/ILibraryAppletAccessor.cs +++ /dev/null @@ -1,71 +0,0 @@ -using Ryujinx.HLE.Logging; -using Ryujinx.HLE.OsHle.Handles; -using Ryujinx.HLE.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.HLE.OsHle.Services.Am -{ - class ILibraryAppletAccessor : IpcService - { - private Dictionary m_Commands; - - public override IReadOnlyDictionary Commands => m_Commands; - - private KEvent StateChangedEvent; - - public ILibraryAppletAccessor() - { - m_Commands = new Dictionary() - { - { 0, GetAppletStateChangedEvent }, - { 10, Start }, - { 30, GetResult }, - { 100, PushInData }, - { 101, PopOutData } - }; - - StateChangedEvent = new KEvent(); - } - - public long GetAppletStateChangedEvent(ServiceCtx Context) - { - StateChangedEvent.WaitEvent.Set(); - - int Handle = Context.Process.HandleTable.OpenHandle(StateChangedEvent); - - Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle); - - Context.Ns.Log.PrintStub(LogClass.ServiceAm, "Stubbed."); - - return 0; - } - - public long Start(ServiceCtx Context) - { - Context.Ns.Log.PrintStub(LogClass.ServiceAm, "Stubbed."); - - return 0; - } - - public long GetResult(ServiceCtx Context) - { - Context.Ns.Log.PrintStub(LogClass.ServiceAm, "Stubbed."); - - return 0; - } - - public long PushInData(ServiceCtx Context) - { - Context.Ns.Log.PrintStub(LogClass.ServiceAm, "Stubbed."); - - return 0; - } - - public long PopOutData(ServiceCtx Context) - { - MakeObject(Context, new IStorage(StorageHelper.MakeLaunchParams())); - - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Am/ILibraryAppletCreator.cs b/Ryujinx.HLE/OsHle/Services/Am/ILibraryAppletCreator.cs deleted file mode 100644 index 66973fc6..00000000 --- a/Ryujinx.HLE/OsHle/Services/Am/ILibraryAppletCreator.cs +++ /dev/null @@ -1,37 +0,0 @@ -using Ryujinx.HLE.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.HLE.OsHle.Services.Am -{ - class ILibraryAppletCreator : IpcService - { - private Dictionary m_Commands; - - public override IReadOnlyDictionary Commands => m_Commands; - - public ILibraryAppletCreator() - { - m_Commands = new Dictionary() - { - { 0, CreateLibraryApplet }, - { 10, CreateStorage } - }; - } - - public long CreateLibraryApplet(ServiceCtx Context) - { - MakeObject(Context, new ILibraryAppletAccessor()); - - return 0; - } - - public long CreateStorage(ServiceCtx Context) - { - long Size = Context.RequestData.ReadInt64(); - - MakeObject(Context, new IStorage(new byte[Size])); - - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Am/ISelfController.cs b/Ryujinx.HLE/OsHle/Services/Am/ISelfController.cs deleted file mode 100644 index 9b3dded2..00000000 --- a/Ryujinx.HLE/OsHle/Services/Am/ISelfController.cs +++ /dev/null @@ -1,145 +0,0 @@ -using Ryujinx.HLE.Logging; -using Ryujinx.HLE.OsHle.Handles; -using Ryujinx.HLE.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.HLE.OsHle.Services.Am -{ - class ISelfController : IpcService - { - private Dictionary m_Commands; - - public override IReadOnlyDictionary Commands => m_Commands; - - private KEvent LaunchableEvent; - - public ISelfController() - { - m_Commands = new Dictionary() - { - { 0, Exit }, - { 1, LockExit }, - { 2, UnlockExit }, - { 9, GetLibraryAppletLaunchableEvent }, - { 10, SetScreenShotPermission }, - { 11, SetOperationModeChangedNotification }, - { 12, SetPerformanceModeChangedNotification }, - { 13, SetFocusHandlingMode }, - { 14, SetRestartMessageEnabled }, - { 16, SetOutOfFocusSuspendingEnabled }, - { 19, SetScreenShotImageOrientation }, - { 50, SetHandlesRequestToDisplay } - }; - - LaunchableEvent = new KEvent(); - } - - public long Exit(ServiceCtx Context) - { - Context.Ns.Log.PrintStub(LogClass.ServiceAm, "Stubbed."); - - return 0; - } - - public long LockExit(ServiceCtx Context) - { - Context.Ns.Log.PrintStub(LogClass.ServiceAm, "Stubbed."); - - return 0; - } - - public long UnlockExit(ServiceCtx Context) - { - Context.Ns.Log.PrintStub(LogClass.ServiceAm, "Stubbed."); - - return 0; - } - - public long GetLibraryAppletLaunchableEvent(ServiceCtx Context) - { - LaunchableEvent.WaitEvent.Set(); - - int Handle = Context.Process.HandleTable.OpenHandle(LaunchableEvent); - - Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle); - - Context.Ns.Log.PrintStub(LogClass.ServiceAm, "Stubbed."); - - return 0; - } - - public long SetScreenShotPermission(ServiceCtx Context) - { - bool Enable = Context.RequestData.ReadByte() != 0 ? true : false; - - Context.Ns.Log.PrintStub(LogClass.ServiceAm, "Stubbed."); - - return 0; - } - - public long SetOperationModeChangedNotification(ServiceCtx Context) - { - bool Enable = Context.RequestData.ReadByte() != 0 ? true : false; - - Context.Ns.Log.PrintStub(LogClass.ServiceAm, "Stubbed."); - - return 0; - } - - public long SetPerformanceModeChangedNotification(ServiceCtx Context) - { - bool Enable = Context.RequestData.ReadByte() != 0 ? true : false; - - Context.Ns.Log.PrintStub(LogClass.ServiceAm, "Stubbed."); - - return 0; - } - - public long SetFocusHandlingMode(ServiceCtx Context) - { - bool Flag1 = Context.RequestData.ReadByte() != 0 ? true : false; - bool Flag2 = Context.RequestData.ReadByte() != 0 ? true : false; - bool Flag3 = Context.RequestData.ReadByte() != 0 ? true : false; - - Context.Ns.Log.PrintStub(LogClass.ServiceAm, "Stubbed."); - - return 0; - } - - public long SetRestartMessageEnabled(ServiceCtx Context) - { - bool Enable = Context.RequestData.ReadByte() != 0 ? true : false; - - Context.Ns.Log.PrintStub(LogClass.ServiceAm, "Stubbed."); - - return 0; - } - - public long SetOutOfFocusSuspendingEnabled(ServiceCtx Context) - { - bool Enable = Context.RequestData.ReadByte() != 0 ? true : false; - - Context.Ns.Log.PrintStub(LogClass.ServiceAm, "Stubbed."); - - return 0; - } - - public long SetScreenShotImageOrientation(ServiceCtx Context) - { - int Orientation = Context.RequestData.ReadInt32(); - - Context.Ns.Log.PrintStub(LogClass.ServiceAm, "Stubbed."); - - return 0; - } - - public long SetHandlesRequestToDisplay(ServiceCtx Context) - { - bool Enable = Context.RequestData.ReadByte() != 0 ? true : false; - - Context.Ns.Log.PrintStub(LogClass.ServiceAm, "Stubbed."); - - return 0; - } - } -} diff --git a/Ryujinx.HLE/OsHle/Services/Am/IStorage.cs b/Ryujinx.HLE/OsHle/Services/Am/IStorage.cs deleted file mode 100644 index 0aa1f571..00000000 --- a/Ryujinx.HLE/OsHle/Services/Am/IStorage.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Ryujinx.HLE.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.HLE.OsHle.Services.Am -{ - class IStorage : IpcService - { - private Dictionary m_Commands; - - public override IReadOnlyDictionary Commands => m_Commands; - - public byte[] Data { get; private set; } - - public IStorage(byte[] Data) - { - m_Commands = new Dictionary() - { - { 0, Open } - }; - - this.Data = Data; - } - - public long Open(ServiceCtx Context) - { - MakeObject(Context, new IStorageAccessor(this)); - - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Am/IStorageAccessor.cs b/Ryujinx.HLE/OsHle/Services/Am/IStorageAccessor.cs deleted file mode 100644 index c2a8c11e..00000000 --- a/Ryujinx.HLE/OsHle/Services/Am/IStorageAccessor.cs +++ /dev/null @@ -1,83 +0,0 @@ -using Ryujinx.HLE.OsHle.Ipc; -using System; -using System.Collections.Generic; - -namespace Ryujinx.HLE.OsHle.Services.Am -{ - class IStorageAccessor : IpcService - { - private Dictionary m_Commands; - - public override IReadOnlyDictionary Commands => m_Commands; - - private IStorage Storage; - - public IStorageAccessor(IStorage Storage) - { - m_Commands = new Dictionary() - { - { 0, GetSize }, - { 10, Write }, - { 11, Read } - }; - - this.Storage = Storage; - } - - public long GetSize(ServiceCtx Context) - { - Context.ResponseData.Write((long)Storage.Data.Length); - - return 0; - } - - public long Write(ServiceCtx Context) - { - //TODO: Error conditions. - long WritePosition = Context.RequestData.ReadInt64(); - - (long Position, long Size) = Context.Request.GetBufferType0x21(); - - if (Size > 0) - { - long MaxSize = Storage.Data.Length - WritePosition; - - if (Size > MaxSize) - { - Size = MaxSize; - } - - byte[] Data = Context.Memory.ReadBytes(Position, Size); - - Buffer.BlockCopy(Data, 0, Storage.Data, (int)WritePosition, (int)Size); - } - - return 0; - } - - public long Read(ServiceCtx Context) - { - //TODO: Error conditions. - long ReadPosition = Context.RequestData.ReadInt64(); - - (long Position, long Size) = Context.Request.GetBufferType0x22(); - - byte[] Data; - - if (Storage.Data.Length > Size) - { - Data = new byte[Size]; - - Buffer.BlockCopy(Storage.Data, 0, Data, 0, (int)Size); - } - else - { - Data = Storage.Data; - } - - Context.Memory.WriteBytes(Position, Data); - - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Am/ISystemAppletProxy.cs b/Ryujinx.HLE/OsHle/Services/Am/ISystemAppletProxy.cs deleted file mode 100644 index e0d78e34..00000000 --- a/Ryujinx.HLE/OsHle/Services/Am/ISystemAppletProxy.cs +++ /dev/null @@ -1,99 +0,0 @@ -using Ryujinx.HLE.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.HLE.OsHle.Services.Am -{ - class ISystemAppletProxy : IpcService - { - private Dictionary m_Commands; - - public override IReadOnlyDictionary Commands => m_Commands; - - public ISystemAppletProxy() - { - m_Commands = new Dictionary() - { - { 0, GetCommonStateGetter }, - { 1, GetSelfController }, - { 2, GetWindowController }, - { 3, GetAudioController }, - { 4, GetDisplayController }, - { 11, GetLibraryAppletCreator }, - { 20, GetHomeMenuFunctions }, - { 21, GetGlobalStateController }, - { 22, GetApplicationCreator }, - { 1000, GetDebugFunctions } - }; - } - - public long GetCommonStateGetter(ServiceCtx Context) - { - MakeObject(Context, new ICommonStateGetter()); - - return 0; - } - - public long GetSelfController(ServiceCtx Context) - { - MakeObject(Context, new ISelfController()); - - return 0; - } - - public long GetWindowController(ServiceCtx Context) - { - MakeObject(Context, new IWindowController()); - - return 0; - } - - public long GetAudioController(ServiceCtx Context) - { - MakeObject(Context, new IAudioController()); - - return 0; - } - - public long GetDisplayController(ServiceCtx Context) - { - MakeObject(Context, new IDisplayController()); - - return 0; - } - - public long GetLibraryAppletCreator(ServiceCtx Context) - { - MakeObject(Context, new ILibraryAppletCreator()); - - return 0; - } - - public long GetHomeMenuFunctions(ServiceCtx Context) - { - MakeObject(Context, new IHomeMenuFunctions()); - - return 0; - } - - public long GetGlobalStateController(ServiceCtx Context) - { - MakeObject(Context, new IGlobalStateController()); - - return 0; - } - - public long GetApplicationCreator(ServiceCtx Context) - { - MakeObject(Context, new IApplicationCreator()); - - return 0; - } - - public long GetDebugFunctions(ServiceCtx Context) - { - MakeObject(Context, new IDebugFunctions()); - - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Am/IWindowController.cs b/Ryujinx.HLE/OsHle/Services/Am/IWindowController.cs deleted file mode 100644 index d9ab5db3..00000000 --- a/Ryujinx.HLE/OsHle/Services/Am/IWindowController.cs +++ /dev/null @@ -1,38 +0,0 @@ -using Ryujinx.HLE.Logging; -using Ryujinx.HLE.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.HLE.OsHle.Services.Am -{ - class IWindowController : IpcService - { - private Dictionary m_Commands; - - public override IReadOnlyDictionary Commands => m_Commands; - - public IWindowController() - { - m_Commands = new Dictionary() - { - { 1, GetAppletResourceUserId }, - { 10, AcquireForegroundRights } - }; - } - - public long GetAppletResourceUserId(ServiceCtx Context) - { - Context.Ns.Log.PrintStub(LogClass.ServiceAm, "Stubbed."); - - Context.ResponseData.Write(0L); - - return 0; - } - - public long AcquireForegroundRights(ServiceCtx Context) - { - Context.Ns.Log.PrintStub(LogClass.ServiceAm, "Stubbed."); - - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Am/MessageInfo.cs b/Ryujinx.HLE/OsHle/Services/Am/MessageInfo.cs deleted file mode 100644 index bae985fb..00000000 --- a/Ryujinx.HLE/OsHle/Services/Am/MessageInfo.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Ryujinx.HLE.OsHle.Services.Am -{ - enum MessageInfo - { - FocusStateChanged = 0xf, - OperationModeChanged = 0x1e, - PerformanceModeChanged = 0x1f - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Am/OperationMode.cs b/Ryujinx.HLE/OsHle/Services/Am/OperationMode.cs deleted file mode 100644 index 632ce931..00000000 --- a/Ryujinx.HLE/OsHle/Services/Am/OperationMode.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Ryujinx.HLE.OsHle.Services.Am -{ - enum OperationMode - { - Handheld = 0, - Docked = 1 - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Am/StorageHelper.cs b/Ryujinx.HLE/OsHle/Services/Am/StorageHelper.cs deleted file mode 100644 index 56e2a652..00000000 --- a/Ryujinx.HLE/OsHle/Services/Am/StorageHelper.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System.IO; - -namespace Ryujinx.HLE.OsHle.Services.Am -{ - class StorageHelper - { - private const uint LaunchParamsMagic = 0xc79497ca; - - public static byte[] MakeLaunchParams() - { - //Size needs to be at least 0x88 bytes otherwise application errors. - using (MemoryStream MS = new MemoryStream()) - { - BinaryWriter Writer = new BinaryWriter(MS); - - MS.SetLength(0x88); - - Writer.Write(LaunchParamsMagic); - Writer.Write(1); //IsAccountSelected? Only lower 8 bits actually used. - Writer.Write(1L); //User Id Low (note: User Id needs to be != 0) - Writer.Write(0L); //User Id High - - return MS.ToArray(); - } - } - } -} diff --git a/Ryujinx.HLE/OsHle/Services/Apm/IManager.cs b/Ryujinx.HLE/OsHle/Services/Apm/IManager.cs deleted file mode 100644 index 22150d6e..00000000 --- a/Ryujinx.HLE/OsHle/Services/Apm/IManager.cs +++ /dev/null @@ -1,27 +0,0 @@ -using Ryujinx.HLE.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.HLE.OsHle.Services.Apm -{ - class IManager : IpcService - { - private Dictionary m_Commands; - - public override IReadOnlyDictionary Commands => m_Commands; - - public IManager() - { - m_Commands = new Dictionary() - { - { 0, OpenSession } - }; - } - - public long OpenSession(ServiceCtx Context) - { - MakeObject(Context, new ISession()); - - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Apm/ISession.cs b/Ryujinx.HLE/OsHle/Services/Apm/ISession.cs deleted file mode 100644 index 3c9bf07c..00000000 --- a/Ryujinx.HLE/OsHle/Services/Apm/ISession.cs +++ /dev/null @@ -1,41 +0,0 @@ -using Ryujinx.HLE.Logging; -using Ryujinx.HLE.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.HLE.OsHle.Services.Apm -{ - class ISession : IpcService - { - private Dictionary m_Commands; - - public override IReadOnlyDictionary Commands => m_Commands; - - public ISession() - { - m_Commands = new Dictionary() - { - { 0, SetPerformanceConfiguration }, - { 1, GetPerformanceConfiguration } - }; - } - - public long SetPerformanceConfiguration(ServiceCtx Context) - { - PerformanceMode PerfMode = (PerformanceMode)Context.RequestData.ReadInt32(); - PerformanceConfiguration PerfConfig = (PerformanceConfiguration)Context.RequestData.ReadInt32(); - - return 0; - } - - public long GetPerformanceConfiguration(ServiceCtx Context) - { - PerformanceMode PerfMode = (PerformanceMode)Context.RequestData.ReadInt32(); - - Context.ResponseData.Write((uint)PerformanceConfiguration.PerformanceConfiguration1); - - Context.Ns.Log.PrintStub(LogClass.ServiceApm, "Stubbed."); - - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Apm/PerformanceConfiguration.cs b/Ryujinx.HLE/OsHle/Services/Apm/PerformanceConfiguration.cs deleted file mode 100644 index 07d59285..00000000 --- a/Ryujinx.HLE/OsHle/Services/Apm/PerformanceConfiguration.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace Ryujinx.HLE.OsHle.Services.Apm -{ - enum PerformanceConfiguration : uint - { - PerformanceConfiguration1 = 0x00010000, - PerformanceConfiguration2 = 0x00010001, - PerformanceConfiguration3 = 0x00010002, - PerformanceConfiguration4 = 0x00020000, - PerformanceConfiguration5 = 0x00020001, - PerformanceConfiguration6 = 0x00020002, - PerformanceConfiguration7 = 0x00020003, - PerformanceConfiguration8 = 0x00020004, - PerformanceConfiguration9 = 0x00020005, - PerformanceConfiguration10 = 0x00020006, - PerformanceConfiguration11 = 0x92220007, - PerformanceConfiguration12 = 0x92220008 - } -} diff --git a/Ryujinx.HLE/OsHle/Services/Apm/PerformanceMode.cs b/Ryujinx.HLE/OsHle/Services/Apm/PerformanceMode.cs deleted file mode 100644 index d89e2760..00000000 --- a/Ryujinx.HLE/OsHle/Services/Apm/PerformanceMode.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Ryujinx.HLE.OsHle.Services.Apm -{ - enum PerformanceMode - { - Handheld = 0, - Docked = 1 - } -} diff --git a/Ryujinx.HLE/OsHle/Services/Aud/AudErr.cs b/Ryujinx.HLE/OsHle/Services/Aud/AudErr.cs deleted file mode 100644 index 72c3e65e..00000000 --- a/Ryujinx.HLE/OsHle/Services/Aud/AudErr.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Ryujinx.HLE.OsHle.Services.Aud -{ - static class AudErr - { - public const int DeviceNotFound = 1; - public const int UnsupportedRevision = 2; - public const int UnsupportedSampleRate = 3; - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Aud/AudioOut/AudioOutData.cs b/Ryujinx.HLE/OsHle/Services/Aud/AudioOut/AudioOutData.cs deleted file mode 100644 index 6887a38b..00000000 --- a/Ryujinx.HLE/OsHle/Services/Aud/AudioOut/AudioOutData.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System.Runtime.InteropServices; - -namespace Ryujinx.HLE.OsHle.Services.Aud.AudioOut -{ - [StructLayout(LayoutKind.Sequential)] - struct AudioOutData - { - public long NextBufferPtr; - public long SampleBufferPtr; - public long SampleBufferCapacity; - public long SampleBufferSize; - public long SampleBufferInnerOffset; - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Aud/AudioOut/IAudioOut.cs b/Ryujinx.HLE/OsHle/Services/Aud/AudioOut/IAudioOut.cs deleted file mode 100644 index d89fc293..00000000 --- a/Ryujinx.HLE/OsHle/Services/Aud/AudioOut/IAudioOut.cs +++ /dev/null @@ -1,163 +0,0 @@ -using ChocolArm64.Memory; -using Ryujinx.Audio; -using Ryujinx.HLE.OsHle.Handles; -using Ryujinx.HLE.OsHle.Ipc; -using System; -using System.Collections.Generic; - -namespace Ryujinx.HLE.OsHle.Services.Aud.AudioOut -{ - class IAudioOut : IpcService, IDisposable - { - private Dictionary m_Commands; - - public override IReadOnlyDictionary Commands => m_Commands; - - private IAalOutput AudioOut; - - private KEvent ReleaseEvent; - - private int Track; - - public IAudioOut(IAalOutput AudioOut, KEvent ReleaseEvent, int Track) - { - m_Commands = new Dictionary() - { - { 0, GetAudioOutState }, - { 1, StartAudioOut }, - { 2, StopAudioOut }, - { 3, AppendAudioOutBuffer }, - { 4, RegisterBufferEvent }, - { 5, GetReleasedAudioOutBuffer }, - { 6, ContainsAudioOutBuffer }, - { 7, AppendAudioOutBufferAuto }, - { 8, GetReleasedAudioOutBufferAuto } - }; - - this.AudioOut = AudioOut; - this.ReleaseEvent = ReleaseEvent; - this.Track = Track; - } - - public long GetAudioOutState(ServiceCtx Context) - { - Context.ResponseData.Write((int)AudioOut.GetState(Track)); - - return 0; - } - - public long StartAudioOut(ServiceCtx Context) - { - AudioOut.Start(Track); - - return 0; - } - - public long StopAudioOut(ServiceCtx Context) - { - AudioOut.Stop(Track); - - return 0; - } - - public long AppendAudioOutBuffer(ServiceCtx Context) - { - return AppendAudioOutBufferImpl(Context, Context.Request.SendBuff[0].Position); - } - - public long RegisterBufferEvent(ServiceCtx Context) - { - int Handle = Context.Process.HandleTable.OpenHandle(ReleaseEvent); - - Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle); - - return 0; - } - - public long GetReleasedAudioOutBuffer(ServiceCtx Context) - { - long Position = Context.Request.ReceiveBuff[0].Position; - long Size = Context.Request.ReceiveBuff[0].Size; - - return GetReleasedAudioOutBufferImpl(Context, Position, Size); - } - - public long ContainsAudioOutBuffer(ServiceCtx Context) - { - long Tag = Context.RequestData.ReadInt64(); - - Context.ResponseData.Write(AudioOut.ContainsBuffer(Track, Tag) ? 1 : 0); - - return 0; - } - - public long AppendAudioOutBufferAuto(ServiceCtx Context) - { - (long Position, long Size) = Context.Request.GetBufferType0x21(); - - return AppendAudioOutBufferImpl(Context, Position); - } - - public long AppendAudioOutBufferImpl(ServiceCtx Context, long Position) - { - long Tag = Context.RequestData.ReadInt64(); - - AudioOutData Data = AMemoryHelper.Read( - Context.Memory, - Position); - - byte[] Buffer = Context.Memory.ReadBytes( - Data.SampleBufferPtr, - Data.SampleBufferSize); - - AudioOut.AppendBuffer(Track, Tag, Buffer); - - return 0; - } - - public long GetReleasedAudioOutBufferAuto(ServiceCtx Context) - { - (long Position, long Size) = Context.Request.GetBufferType0x22(); - - return GetReleasedAudioOutBufferImpl(Context, Position, Size); - } - - public long GetReleasedAudioOutBufferImpl(ServiceCtx Context, long Position, long Size) - { - uint Count = (uint)((ulong)Size >> 3); - - long[] ReleasedBuffers = AudioOut.GetReleasedBuffers(Track, (int)Count); - - for (uint Index = 0; Index < Count; Index++) - { - long Tag = 0; - - if (Index < ReleasedBuffers.Length) - { - Tag = ReleasedBuffers[Index]; - } - - Context.Memory.WriteInt64(Position + Index * 8, Tag); - } - - Context.ResponseData.Write(ReleasedBuffers.Length); - - return 0; - } - - public void Dispose() - { - Dispose(true); - } - - protected virtual void Dispose(bool Disposing) - { - if (Disposing) - { - AudioOut.CloseTrack(Track); - - ReleaseEvent.Dispose(); - } - } - } -} diff --git a/Ryujinx.HLE/OsHle/Services/Aud/AudioRenderer/AudioConsts.cs b/Ryujinx.HLE/OsHle/Services/Aud/AudioRenderer/AudioConsts.cs deleted file mode 100644 index fed41959..00000000 --- a/Ryujinx.HLE/OsHle/Services/Aud/AudioRenderer/AudioConsts.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Ryujinx.HLE.OsHle.Services.Aud.AudioRenderer -{ - static class AudioConsts - { - public const int HostSampleRate = 48000; - public const int HostChannelsCount = 2; - } -} diff --git a/Ryujinx.HLE/OsHle/Services/Aud/AudioRenderer/BehaviorIn.cs b/Ryujinx.HLE/OsHle/Services/Aud/AudioRenderer/BehaviorIn.cs deleted file mode 100644 index 4e33de62..00000000 --- a/Ryujinx.HLE/OsHle/Services/Aud/AudioRenderer/BehaviorIn.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Runtime.InteropServices; - -namespace Ryujinx.HLE.OsHle.Services.Aud.AudioRenderer -{ - [StructLayout(LayoutKind.Sequential, Size = 0x10, Pack = 4)] - struct BehaviorIn - { - public long Unknown0; - public long Unknown8; - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Aud/AudioRenderer/BiquadFilter.cs b/Ryujinx.HLE/OsHle/Services/Aud/AudioRenderer/BiquadFilter.cs deleted file mode 100644 index 9fa4cd33..00000000 --- a/Ryujinx.HLE/OsHle/Services/Aud/AudioRenderer/BiquadFilter.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System.Runtime.InteropServices; - -namespace Ryujinx.HLE.OsHle.Services.Aud.AudioRenderer -{ - [StructLayout(LayoutKind.Sequential, Size = 0xc, Pack = 1)] - struct BiquadFilter - { - public byte Enable; - public byte Padding; - public short B0; - public short B1; - public short B2; - public short A1; - public short A2; - } -} diff --git a/Ryujinx.HLE/OsHle/Services/Aud/AudioRenderer/IAudioRenderer.cs b/Ryujinx.HLE/OsHle/Services/Aud/AudioRenderer/IAudioRenderer.cs deleted file mode 100644 index f91a8da3..00000000 --- a/Ryujinx.HLE/OsHle/Services/Aud/AudioRenderer/IAudioRenderer.cs +++ /dev/null @@ -1,316 +0,0 @@ -using ChocolArm64.Memory; -using Ryujinx.Audio; -using Ryujinx.Audio.Adpcm; -using Ryujinx.HLE.Logging; -using Ryujinx.HLE.OsHle.Handles; -using Ryujinx.HLE.OsHle.Ipc; -using Ryujinx.HLE.OsHle.Utilities; -using System; -using System.Collections.Generic; -using System.Runtime.InteropServices; - -namespace Ryujinx.HLE.OsHle.Services.Aud.AudioRenderer -{ - class IAudioRenderer : IpcService, IDisposable - { - //This is the amount of samples that are going to be appended - //each time that RequestUpdateAudioRenderer is called. Ideally, - //this value shouldn't be neither too small (to avoid the player - //starving due to running out of samples) or too large (to avoid - //high latency). - private const int MixBufferSamplesCount = 960; - - private Dictionary m_Commands; - - public override IReadOnlyDictionary Commands => m_Commands; - - private KEvent UpdateEvent; - - private AMemory Memory; - - private IAalOutput AudioOut; - - private AudioRendererParameter Params; - - private MemoryPoolContext[] MemoryPools; - - private VoiceContext[] Voices; - - private int Track; - - public IAudioRenderer(AMemory Memory, IAalOutput AudioOut, AudioRendererParameter Params) - { - m_Commands = new Dictionary() - { - { 4, RequestUpdateAudioRenderer }, - { 5, StartAudioRenderer }, - { 6, StopAudioRenderer }, - { 7, QuerySystemEvent } - }; - - UpdateEvent = new KEvent(); - - this.Memory = Memory; - this.AudioOut = AudioOut; - this.Params = Params; - - Track = AudioOut.OpenTrack( - AudioConsts.HostSampleRate, - AudioConsts.HostChannelsCount, - AudioCallback); - - MemoryPools = CreateArray(Params.EffectCount + Params.VoiceCount * 4); - - Voices = CreateArray(Params.VoiceCount); - - InitializeAudioOut(); - } - - private void AudioCallback() - { - UpdateEvent.WaitEvent.Set(); - } - - private static T[] CreateArray(int Size) where T : new() - { - T[] Output = new T[Size]; - - for (int Index = 0; Index < Size; Index++) - { - Output[Index] = new T(); - } - - return Output; - } - - private void InitializeAudioOut() - { - AppendMixedBuffer(0); - AppendMixedBuffer(1); - AppendMixedBuffer(2); - - AudioOut.Start(Track); - } - - public long RequestUpdateAudioRenderer(ServiceCtx Context) - { - long OutputPosition = Context.Request.ReceiveBuff[0].Position; - long OutputSize = Context.Request.ReceiveBuff[0].Size; - - AMemoryHelper.FillWithZeros(Context.Memory, OutputPosition, (int)OutputSize); - - long InputPosition = Context.Request.SendBuff[0].Position; - - StructReader Reader = new StructReader(Context.Memory, InputPosition); - StructWriter Writer = new StructWriter(Context.Memory, OutputPosition); - - UpdateDataHeader InputHeader = Reader.Read(); - - Reader.Read(InputHeader.BehaviorSize); - - MemoryPoolIn[] MemoryPoolsIn = Reader.Read(InputHeader.MemoryPoolSize); - - for (int Index = 0; Index < MemoryPoolsIn.Length; Index++) - { - MemoryPoolIn MemoryPool = MemoryPoolsIn[Index]; - - if (MemoryPool.State == MemoryPoolState.RequestAttach) - { - MemoryPools[Index].OutStatus.State = MemoryPoolState.Attached; - } - else if (MemoryPool.State == MemoryPoolState.RequestDetach) - { - MemoryPools[Index].OutStatus.State = MemoryPoolState.Detached; - } - } - - Reader.Read(InputHeader.VoiceResourceSize); - - VoiceIn[] VoicesIn = Reader.Read(InputHeader.VoiceSize); - - for (int Index = 0; Index < VoicesIn.Length; Index++) - { - VoiceIn Voice = VoicesIn[Index]; - - VoiceContext VoiceCtx = Voices[Index]; - - VoiceCtx.SetAcquireState(Voice.Acquired != 0); - - if (Voice.Acquired == 0) - { - continue; - } - - if (Voice.FirstUpdate != 0) - { - VoiceCtx.AdpcmCtx = GetAdpcmDecoderContext( - Voice.AdpcmCoeffsPosition, - Voice.AdpcmCoeffsSize); - - VoiceCtx.SampleFormat = Voice.SampleFormat; - VoiceCtx.SampleRate = Voice.SampleRate; - VoiceCtx.ChannelsCount = Voice.ChannelsCount; - - VoiceCtx.SetBufferIndex(Voice.BaseWaveBufferIndex); - } - - VoiceCtx.WaveBuffers[0] = Voice.WaveBuffer0; - VoiceCtx.WaveBuffers[1] = Voice.WaveBuffer1; - VoiceCtx.WaveBuffers[2] = Voice.WaveBuffer2; - VoiceCtx.WaveBuffers[3] = Voice.WaveBuffer3; - VoiceCtx.Volume = Voice.Volume; - VoiceCtx.PlayState = Voice.PlayState; - } - - UpdateAudio(); - - UpdateDataHeader OutputHeader = new UpdateDataHeader(); - - int UpdateHeaderSize = Marshal.SizeOf(); - - OutputHeader.Revision = IAudioRendererManager.RevMagic; - OutputHeader.BehaviorSize = 0xb0; - OutputHeader.MemoryPoolSize = (Params.EffectCount + Params.VoiceCount * 4) * 0x10; - OutputHeader.VoiceSize = Params.VoiceCount * 0x10; - OutputHeader.EffectSize = Params.EffectCount * 0x10; - OutputHeader.SinkSize = Params.SinkCount * 0x20; - OutputHeader.PerformanceManagerSize = 0x10; - OutputHeader.TotalSize = UpdateHeaderSize + - OutputHeader.BehaviorSize + - OutputHeader.MemoryPoolSize + - OutputHeader.VoiceSize + - OutputHeader.EffectSize + - OutputHeader.SinkSize + - OutputHeader.PerformanceManagerSize; - - Writer.Write(OutputHeader); - - foreach (MemoryPoolContext MemoryPool in MemoryPools) - { - Writer.Write(MemoryPool.OutStatus); - } - - foreach (VoiceContext Voice in Voices) - { - Writer.Write(Voice.OutStatus); - } - - return 0; - } - - public long StartAudioRenderer(ServiceCtx Context) - { - Context.Ns.Log.PrintStub(LogClass.ServiceAudio, "Stubbed."); - - return 0; - } - - public long StopAudioRenderer(ServiceCtx Context) - { - Context.Ns.Log.PrintStub(LogClass.ServiceAudio, "Stubbed."); - - return 0; - } - - public long QuerySystemEvent(ServiceCtx Context) - { - int Handle = Context.Process.HandleTable.OpenHandle(UpdateEvent); - - Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle); - - return 0; - } - - private AdpcmDecoderContext GetAdpcmDecoderContext(long Position, long Size) - { - if (Size == 0) - { - return null; - } - - AdpcmDecoderContext Context = new AdpcmDecoderContext(); - - Context.Coefficients = new short[Size >> 1]; - - for (int Offset = 0; Offset < Size; Offset += 2) - { - Context.Coefficients[Offset >> 1] = Memory.ReadInt16(Position + Offset); - } - - return Context; - } - - private void UpdateAudio() - { - long[] Released = AudioOut.GetReleasedBuffers(Track, 2); - - for (int Index = 0; Index < Released.Length; Index++) - { - AppendMixedBuffer(Released[Index]); - } - } - - private void AppendMixedBuffer(long Tag) - { - int[] MixBuffer = new int[MixBufferSamplesCount * AudioConsts.HostChannelsCount]; - - foreach (VoiceContext Voice in Voices) - { - if (!Voice.Playing) - { - continue; - } - - int OutOffset = 0; - - int PendingSamples = MixBufferSamplesCount; - - while (PendingSamples > 0) - { - int[] Samples = Voice.GetBufferData(Memory, PendingSamples, out int ReturnedSamples); - - if (ReturnedSamples == 0) - { - break; - } - - PendingSamples -= ReturnedSamples; - - for (int Offset = 0; Offset < Samples.Length; Offset++) - { - int Sample = (int)(Samples[Offset] * Voice.Volume); - - MixBuffer[OutOffset++] += Sample; - } - } - } - - AudioOut.AppendBuffer(Track, Tag, GetFinalBuffer(MixBuffer)); - } - - private static short[] GetFinalBuffer(int[] Buffer) - { - short[] Output = new short[Buffer.Length]; - - for (int Offset = 0; Offset < Buffer.Length; Offset++) - { - Output[Offset] = DspUtils.Saturate(Buffer[Offset]); - } - - return Output; - } - - public void Dispose() - { - Dispose(true); - } - - protected virtual void Dispose(bool Disposing) - { - if (Disposing) - { - UpdateEvent.Dispose(); - } - } - } -} diff --git a/Ryujinx.HLE/OsHle/Services/Aud/AudioRenderer/MemoryPoolContext.cs b/Ryujinx.HLE/OsHle/Services/Aud/AudioRenderer/MemoryPoolContext.cs deleted file mode 100644 index b7af1d3f..00000000 --- a/Ryujinx.HLE/OsHle/Services/Aud/AudioRenderer/MemoryPoolContext.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace Ryujinx.HLE.OsHle.Services.Aud.AudioRenderer -{ - class MemoryPoolContext - { - public MemoryPoolOut OutStatus; - - public MemoryPoolContext() - { - OutStatus.State = MemoryPoolState.Detached; - } - } -} diff --git a/Ryujinx.HLE/OsHle/Services/Aud/AudioRenderer/MemoryPoolIn.cs b/Ryujinx.HLE/OsHle/Services/Aud/AudioRenderer/MemoryPoolIn.cs deleted file mode 100644 index c852b519..00000000 --- a/Ryujinx.HLE/OsHle/Services/Aud/AudioRenderer/MemoryPoolIn.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System.Runtime.InteropServices; - -namespace Ryujinx.HLE.OsHle.Services.Aud.AudioRenderer -{ - [StructLayout(LayoutKind.Sequential, Size = 0x20, Pack = 4)] - struct MemoryPoolIn - { - public long Address; - public long Size; - public MemoryPoolState State; - public int Unknown14; - public long Unknown18; - } -} diff --git a/Ryujinx.HLE/OsHle/Services/Aud/AudioRenderer/MemoryPoolOut.cs b/Ryujinx.HLE/OsHle/Services/Aud/AudioRenderer/MemoryPoolOut.cs deleted file mode 100644 index dd65df86..00000000 --- a/Ryujinx.HLE/OsHle/Services/Aud/AudioRenderer/MemoryPoolOut.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Runtime.InteropServices; - -namespace Ryujinx.HLE.OsHle.Services.Aud.AudioRenderer -{ - [StructLayout(LayoutKind.Sequential, Size = 0x10, Pack = 4)] - struct MemoryPoolOut - { - public MemoryPoolState State; - public int Unknown14; - public long Unknown18; - } -} diff --git a/Ryujinx.HLE/OsHle/Services/Aud/AudioRenderer/MemoryPoolState.cs b/Ryujinx.HLE/OsHle/Services/Aud/AudioRenderer/MemoryPoolState.cs deleted file mode 100644 index f96a0c09..00000000 --- a/Ryujinx.HLE/OsHle/Services/Aud/AudioRenderer/MemoryPoolState.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace Ryujinx.HLE.OsHle.Services.Aud.AudioRenderer -{ - enum MemoryPoolState : int - { - Invalid = 0, - Unknown = 1, - RequestDetach = 2, - Detached = 3, - RequestAttach = 4, - Attached = 5, - Released = 6 - } -} diff --git a/Ryujinx.HLE/OsHle/Services/Aud/AudioRenderer/PlayState.cs b/Ryujinx.HLE/OsHle/Services/Aud/AudioRenderer/PlayState.cs deleted file mode 100644 index e8bcf64f..00000000 --- a/Ryujinx.HLE/OsHle/Services/Aud/AudioRenderer/PlayState.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Ryujinx.HLE.OsHle.Services.Aud.AudioRenderer -{ - enum PlayState : byte - { - Playing = 0, - Stopped = 1, - Paused = 2 - } -} diff --git a/Ryujinx.HLE/OsHle/Services/Aud/AudioRenderer/Resampler.cs b/Ryujinx.HLE/OsHle/Services/Aud/AudioRenderer/Resampler.cs deleted file mode 100644 index 31e0ebec..00000000 --- a/Ryujinx.HLE/OsHle/Services/Aud/AudioRenderer/Resampler.cs +++ /dev/null @@ -1,191 +0,0 @@ -using System; - -namespace Ryujinx.HLE.OsHle.Services.Aud.AudioRenderer -{ - static class Resampler - { -#region "LookUp Tables" - private static short[] CurveLut0 = new short[] - { - 6600, 19426, 6722, 3, 6479, 19424, 6845, 9, 6359, 19419, 6968, 15, 6239, 19412, 7093, 22, - 6121, 19403, 7219, 28, 6004, 19391, 7345, 34, 5888, 19377, 7472, 41, 5773, 19361, 7600, 48, - 5659, 19342, 7728, 55, 5546, 19321, 7857, 62, 5434, 19298, 7987, 69, 5323, 19273, 8118, 77, - 5213, 19245, 8249, 84, 5104, 19215, 8381, 92, 4997, 19183, 8513, 101, 4890, 19148, 8646, 109, - 4785, 19112, 8780, 118, 4681, 19073, 8914, 127, 4579, 19031, 9048, 137, 4477, 18988, 9183, 147, - 4377, 18942, 9318, 157, 4277, 18895, 9454, 168, 4179, 18845, 9590, 179, 4083, 18793, 9726, 190, - 3987, 18738, 9863, 202, 3893, 18682, 10000, 215, 3800, 18624, 10137, 228, 3709, 18563, 10274, 241, - 3618, 18500, 10411, 255, 3529, 18436, 10549, 270, 3441, 18369, 10687, 285, 3355, 18300, 10824, 300, - 3269, 18230, 10962, 317, 3186, 18157, 11100, 334, 3103, 18082, 11238, 351, 3022, 18006, 11375, 369, - 2942, 17927, 11513, 388, 2863, 17847, 11650, 408, 2785, 17765, 11788, 428, 2709, 17681, 11925, 449, - 2635, 17595, 12062, 471, 2561, 17507, 12198, 494, 2489, 17418, 12334, 517, 2418, 17327, 12470, 541, - 2348, 17234, 12606, 566, 2280, 17140, 12741, 592, 2213, 17044, 12876, 619, 2147, 16946, 13010, 647, - 2083, 16846, 13144, 675, 2020, 16745, 13277, 704, 1958, 16643, 13409, 735, 1897, 16539, 13541, 766, - 1838, 16434, 13673, 798, 1780, 16327, 13803, 832, 1723, 16218, 13933, 866, 1667, 16109, 14062, 901, - 1613, 15998, 14191, 937, 1560, 15885, 14318, 975, 1508, 15772, 14445, 1013, 1457, 15657, 14571, 1052, - 1407, 15540, 14695, 1093, 1359, 15423, 14819, 1134, 1312, 15304, 14942, 1177, 1266, 15185, 15064, 1221, - 1221, 15064, 15185, 1266, 1177, 14942, 15304, 1312, 1134, 14819, 15423, 1359, 1093, 14695, 15540, 1407, - 1052, 14571, 15657, 1457, 1013, 14445, 15772, 1508, 975, 14318, 15885, 1560, 937, 14191, 15998, 1613, - 901, 14062, 16109, 1667, 866, 13933, 16218, 1723, 832, 13803, 16327, 1780, 798, 13673, 16434, 1838, - 766, 13541, 16539, 1897, 735, 13409, 16643, 1958, 704, 13277, 16745, 2020, 675, 13144, 16846, 2083, - 647, 13010, 16946, 2147, 619, 12876, 17044, 2213, 592, 12741, 17140, 2280, 566, 12606, 17234, 2348, - 541, 12470, 17327, 2418, 517, 12334, 17418, 2489, 494, 12198, 17507, 2561, 471, 12062, 17595, 2635, - 449, 11925, 17681, 2709, 428, 11788, 17765, 2785, 408, 11650, 17847, 2863, 388, 11513, 17927, 2942, - 369, 11375, 18006, 3022, 351, 11238, 18082, 3103, 334, 11100, 18157, 3186, 317, 10962, 18230, 3269, - 300, 10824, 18300, 3355, 285, 10687, 18369, 3441, 270, 10549, 18436, 3529, 255, 10411, 18500, 3618, - 241, 10274, 18563, 3709, 228, 10137, 18624, 3800, 215, 10000, 18682, 3893, 202, 9863, 18738, 3987, - 190, 9726, 18793, 4083, 179, 9590, 18845, 4179, 168, 9454, 18895, 4277, 157, 9318, 18942, 4377, - 147, 9183, 18988, 4477, 137, 9048, 19031, 4579, 127, 8914, 19073, 4681, 118, 8780, 19112, 4785, - 109, 8646, 19148, 4890, 101, 8513, 19183, 4997, 92, 8381, 19215, 5104, 84, 8249, 19245, 5213, - 77, 8118, 19273, 5323, 69, 7987, 19298, 5434, 62, 7857, 19321, 5546, 55, 7728, 19342, 5659, - 48, 7600, 19361, 5773, 41, 7472, 19377, 5888, 34, 7345, 19391, 6004, 28, 7219, 19403, 6121, - 22, 7093, 19412, 6239, 15, 6968, 19419, 6359, 9, 6845, 19424, 6479, 3, 6722, 19426, 6600 - }; - - private static short[] CurveLut1 = new short[] - { - -68, 32639, 69, -5, -200, 32630, 212, -15, -328, 32613, 359, -26, -450, 32586, 512, -36, - -568, 32551, 669, -47, -680, 32507, 832, -58, -788, 32454, 1000, -69, -891, 32393, 1174, -80, - -990, 32323, 1352, -92, -1084, 32244, 1536, -103, -1173, 32157, 1724, -115, -1258, 32061, 1919, -128, - -1338, 31956, 2118, -140, -1414, 31844, 2322, -153, -1486, 31723, 2532, -167, -1554, 31593, 2747, -180, - -1617, 31456, 2967, -194, -1676, 31310, 3192, -209, -1732, 31157, 3422, -224, -1783, 30995, 3657, -240, - -1830, 30826, 3897, -256, -1874, 30649, 4143, -272, -1914, 30464, 4393, -289, -1951, 30272, 4648, -307, - -1984, 30072, 4908, -325, -2014, 29866, 5172, -343, -2040, 29652, 5442, -362, -2063, 29431, 5716, -382, - -2083, 29203, 5994, -403, -2100, 28968, 6277, -424, -2114, 28727, 6565, -445, -2125, 28480, 6857, -468, - -2133, 28226, 7153, -490, -2139, 27966, 7453, -514, -2142, 27700, 7758, -538, -2142, 27428, 8066, -563, - -2141, 27151, 8378, -588, -2136, 26867, 8694, -614, -2130, 26579, 9013, -641, -2121, 26285, 9336, -668, - -2111, 25987, 9663, -696, -2098, 25683, 9993, -724, -2084, 25375, 10326, -753, -2067, 25063, 10662, -783, - -2049, 24746, 11000, -813, -2030, 24425, 11342, -844, -2009, 24100, 11686, -875, -1986, 23771, 12033, -907, - -1962, 23438, 12382, -939, -1937, 23103, 12733, -972, -1911, 22764, 13086, -1005, -1883, 22422, 13441, -1039, - -1855, 22077, 13798, -1072, -1825, 21729, 14156, -1107, -1795, 21380, 14516, -1141, -1764, 21027, 14877, -1176, - -1732, 20673, 15239, -1211, -1700, 20317, 15602, -1246, -1667, 19959, 15965, -1282, -1633, 19600, 16329, -1317, - -1599, 19239, 16694, -1353, -1564, 18878, 17058, -1388, -1530, 18515, 17423, -1424, -1495, 18151, 17787, -1459, - -1459, 17787, 18151, -1495, -1424, 17423, 18515, -1530, -1388, 17058, 18878, -1564, -1353, 16694, 19239, -1599, - -1317, 16329, 19600, -1633, -1282, 15965, 19959, -1667, -1246, 15602, 20317, -1700, -1211, 15239, 20673, -1732, - -1176, 14877, 21027, -1764, -1141, 14516, 21380, -1795, -1107, 14156, 21729, -1825, -1072, 13798, 22077, -1855, - -1039, 13441, 22422, -1883, -1005, 13086, 22764, -1911, -972, 12733, 23103, -1937, -939, 12382, 23438, -1962, - -907, 12033, 23771, -1986, -875, 11686, 24100, -2009, -844, 11342, 24425, -2030, -813, 11000, 24746, -2049, - -783, 10662, 25063, -2067, -753, 10326, 25375, -2084, -724, 9993, 25683, -2098, -696, 9663, 25987, -2111, - -668, 9336, 26285, -2121, -641, 9013, 26579, -2130, -614, 8694, 26867, -2136, -588, 8378, 27151, -2141, - -563, 8066, 27428, -2142, -538, 7758, 27700, -2142, -514, 7453, 27966, -2139, -490, 7153, 28226, -2133, - -468, 6857, 28480, -2125, -445, 6565, 28727, -2114, -424, 6277, 28968, -2100, -403, 5994, 29203, -2083, - -382, 5716, 29431, -2063, -362, 5442, 29652, -2040, -343, 5172, 29866, -2014, -325, 4908, 30072, -1984, - -307, 4648, 30272, -1951, -289, 4393, 30464, -1914, -272, 4143, 30649, -1874, -256, 3897, 30826, -1830, - -240, 3657, 30995, -1783, -224, 3422, 31157, -1732, -209, 3192, 31310, -1676, -194, 2967, 31456, -1617, - -180, 2747, 31593, -1554, -167, 2532, 31723, -1486, -153, 2322, 31844, -1414, -140, 2118, 31956, -1338, - -128, 1919, 32061, -1258, -115, 1724, 32157, -1173, -103, 1536, 32244, -1084, -92, 1352, 32323, -990, - -80, 1174, 32393, -891, -69, 1000, 32454, -788, -58, 832, 32507, -680, -47, 669, 32551, -568, - -36, 512, 32586, -450, -26, 359, 32613, -328, -15, 212, 32630, -200, -5, 69, 32639, -68 - }; - - private static short[] CurveLut2 = new short[] - { - 3195, 26287, 3329, -32, 3064, 26281, 3467, -34, 2936, 26270, 3608, -38, 2811, 26253, 3751, -42, - 2688, 26230, 3897, -46, 2568, 26202, 4046, -50, 2451, 26169, 4199, -54, 2338, 26130, 4354, -58, - 2227, 26085, 4512, -63, 2120, 26035, 4673, -67, 2015, 25980, 4837, -72, 1912, 25919, 5004, -76, - 1813, 25852, 5174, -81, 1716, 25780, 5347, -87, 1622, 25704, 5522, -92, 1531, 25621, 5701, -98, - 1442, 25533, 5882, -103, 1357, 25440, 6066, -109, 1274, 25342, 6253, -115, 1193, 25239, 6442, -121, - 1115, 25131, 6635, -127, 1040, 25018, 6830, -133, 967, 24899, 7027, -140, 897, 24776, 7227, -146, - 829, 24648, 7430, -153, 764, 24516, 7635, -159, 701, 24379, 7842, -166, 641, 24237, 8052, -174, - 583, 24091, 8264, -181, 526, 23940, 8478, -187, 472, 23785, 8695, -194, 420, 23626, 8914, -202, - 371, 23462, 9135, -209, 324, 23295, 9358, -215, 279, 23123, 9583, -222, 236, 22948, 9809, -230, - 194, 22769, 10038, -237, 154, 22586, 10269, -243, 117, 22399, 10501, -250, 81, 22208, 10735, -258, - 47, 22015, 10970, -265, 15, 21818, 11206, -271, -16, 21618, 11444, -277, -44, 21415, 11684, -283, - -71, 21208, 11924, -290, -97, 20999, 12166, -296, -121, 20786, 12409, -302, -143, 20571, 12653, -306, - -163, 20354, 12898, -311, -183, 20134, 13143, -316, -201, 19911, 13389, -321, -218, 19686, 13635, -325, - -234, 19459, 13882, -328, -248, 19230, 14130, -332, -261, 18998, 14377, -335, -273, 18765, 14625, -337, - -284, 18531, 14873, -339, -294, 18295, 15121, -341, -302, 18057, 15369, -341, -310, 17817, 15617, -341, - -317, 17577, 15864, -340, -323, 17335, 16111, -340, -328, 17092, 16357, -338, -332, 16848, 16603, -336, - -336, 16603, 16848, -332, -338, 16357, 17092, -328, -340, 16111, 17335, -323, -340, 15864, 17577, -317, - -341, 15617, 17817, -310, -341, 15369, 18057, -302, -341, 15121, 18295, -294, -339, 14873, 18531, -284, - -337, 14625, 18765, -273, -335, 14377, 18998, -261, -332, 14130, 19230, -248, -328, 13882, 19459, -234, - -325, 13635, 19686, -218, -321, 13389, 19911, -201, -316, 13143, 20134, -183, -311, 12898, 20354, -163, - -306, 12653, 20571, -143, -302, 12409, 20786, -121, -296, 12166, 20999, -97, -290, 11924, 21208, -71, - -283, 11684, 21415, -44, -277, 11444, 21618, -16, -271, 11206, 21818, 15, -265, 10970, 22015, 47, - -258, 10735, 22208, 81, -250, 10501, 22399, 117, -243, 10269, 22586, 154, -237, 10038, 22769, 194, - -230, 9809, 22948, 236, -222, 9583, 23123, 279, -215, 9358, 23295, 324, -209, 9135, 23462, 371, - -202, 8914, 23626, 420, -194, 8695, 23785, 472, -187, 8478, 23940, 526, -181, 8264, 24091, 583, - -174, 8052, 24237, 641, -166, 7842, 24379, 701, -159, 7635, 24516, 764, -153, 7430, 24648, 829, - -146, 7227, 24776, 897, -140, 7027, 24899, 967, -133, 6830, 25018, 1040, -127, 6635, 25131, 1115, - -121, 6442, 25239, 1193, -115, 6253, 25342, 1274, -109, 6066, 25440, 1357, -103, 5882, 25533, 1442, - -98, 5701, 25621, 1531, -92, 5522, 25704, 1622, -87, 5347, 25780, 1716, -81, 5174, 25852, 1813, - -76, 5004, 25919, 1912, -72, 4837, 25980, 2015, -67, 4673, 26035, 2120, -63, 4512, 26085, 2227, - -58, 4354, 26130, 2338, -54, 4199, 26169, 2451, -50, 4046, 26202, 2568, -46, 3897, 26230, 2688, - -42, 3751, 26253, 2811, -38, 3608, 26270, 2936, -34, 3467, 26281, 3064, -32, 3329, 26287, 3195 - }; -#endregion - - public static int[] Resample2Ch( - int[] Buffer, - int SrcSampleRate, - int DstSampleRate, - int SamplesCount, - ref int FracPart) - { - if (Buffer == null) - { - throw new ArgumentNullException(nameof(Buffer)); - } - - if (SrcSampleRate <= 0) - { - throw new ArgumentOutOfRangeException(nameof(SrcSampleRate)); - } - - if (DstSampleRate <= 0) - { - throw new ArgumentOutOfRangeException(nameof(DstSampleRate)); - } - - double Ratio = (double)SrcSampleRate / DstSampleRate; - - int NewSamplesCount = (int)(SamplesCount / Ratio); - - int Step = (int)(Ratio * 0x8000); - - int[] Output = new int[NewSamplesCount * 2]; - - short[] Lut; - - if (Step > 0xaaaa) - { - Lut = CurveLut0; - } - else if (Step <= 0x8000) - { - Lut = CurveLut1; - } - else - { - Lut = CurveLut2; - } - - int InOffs = 0; - - for (int OutOffs = 0; OutOffs < Output.Length; OutOffs += 2) - { - int LutIndex = (FracPart >> 8) * 4; - - int Sample0 = Buffer[(InOffs + 0) * 2 + 0] * Lut[LutIndex + 0] + - Buffer[(InOffs + 1) * 2 + 0] * Lut[LutIndex + 1] + - Buffer[(InOffs + 2) * 2 + 0] * Lut[LutIndex + 2] + - Buffer[(InOffs + 3) * 2 + 0] * Lut[LutIndex + 3]; - - int Sample1 = Buffer[(InOffs + 0) * 2 + 1] * Lut[LutIndex + 0] + - Buffer[(InOffs + 1) * 2 + 1] * Lut[LutIndex + 1] + - Buffer[(InOffs + 2) * 2 + 1] * Lut[LutIndex + 2] + - Buffer[(InOffs + 3) * 2 + 1] * Lut[LutIndex + 3]; - - int NewOffset = FracPart + Step; - - InOffs += NewOffset >> 15; - - FracPart = NewOffset & 0x7fff; - - Output[OutOffs + 0] = Sample0 >> 15; - Output[OutOffs + 1] = Sample1 >> 15; - } - - return Output; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Aud/AudioRenderer/UpdateDataHeader.cs b/Ryujinx.HLE/OsHle/Services/Aud/AudioRenderer/UpdateDataHeader.cs deleted file mode 100644 index a6dfbc0b..00000000 --- a/Ryujinx.HLE/OsHle/Services/Aud/AudioRenderer/UpdateDataHeader.cs +++ /dev/null @@ -1,22 +0,0 @@ -namespace Ryujinx.HLE.OsHle.Services.Aud.AudioRenderer -{ - struct UpdateDataHeader - { - public int Revision; - public int BehaviorSize; - public int MemoryPoolSize; - public int VoiceSize; - public int VoiceResourceSize; - public int EffectSize; - public int MixeSize; - public int SinkSize; - public int PerformanceManagerSize; - public int Unknown24; - public int Unknown28; - public int Unknown2C; - public int Unknown30; - public int Unknown34; - public int Unknown38; - public int TotalSize; - } -} diff --git a/Ryujinx.HLE/OsHle/Services/Aud/AudioRenderer/VoiceChannelResourceIn.cs b/Ryujinx.HLE/OsHle/Services/Aud/AudioRenderer/VoiceChannelResourceIn.cs deleted file mode 100644 index 0916b03e..00000000 --- a/Ryujinx.HLE/OsHle/Services/Aud/AudioRenderer/VoiceChannelResourceIn.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System.Runtime.InteropServices; - -namespace Ryujinx.HLE.OsHle.Services.Aud.AudioRenderer -{ - [StructLayout(LayoutKind.Sequential, Size = 0x70, Pack = 1)] - struct VoiceChannelResourceIn - { - //??? - } -} diff --git a/Ryujinx.HLE/OsHle/Services/Aud/AudioRenderer/VoiceContext.cs b/Ryujinx.HLE/OsHle/Services/Aud/AudioRenderer/VoiceContext.cs deleted file mode 100644 index 1bf9ed73..00000000 --- a/Ryujinx.HLE/OsHle/Services/Aud/AudioRenderer/VoiceContext.cs +++ /dev/null @@ -1,188 +0,0 @@ -using ChocolArm64.Memory; -using Ryujinx.Audio.Adpcm; -using System; - -namespace Ryujinx.HLE.OsHle.Services.Aud.AudioRenderer -{ - class VoiceContext - { - private bool Acquired; - private bool BufferReload; - - private int ResamplerFracPart; - - private int BufferIndex; - private int Offset; - - public int SampleRate; - public int ChannelsCount; - - public float Volume; - - public PlayState PlayState; - - public SampleFormat SampleFormat; - - public AdpcmDecoderContext AdpcmCtx; - - public WaveBuffer[] WaveBuffers; - - public VoiceOut OutStatus; - - private int[] Samples; - - public bool Playing => Acquired && PlayState == PlayState.Playing; - - public VoiceContext() - { - WaveBuffers = new WaveBuffer[4]; - } - - public void SetAcquireState(bool NewState) - { - if (Acquired && !NewState) - { - //Release. - Reset(); - } - - Acquired = NewState; - } - - private void Reset() - { - BufferReload = true; - - BufferIndex = 0; - Offset = 0; - - OutStatus.PlayedSamplesCount = 0; - OutStatus.PlayedWaveBuffersCount = 0; - OutStatus.VoiceDropsCount = 0; - } - - public int[] GetBufferData(AMemory Memory, int MaxSamples, out int SamplesCount) - { - if (!Playing) - { - SamplesCount = 0; - - return null; - } - - if (BufferReload) - { - BufferReload = false; - - UpdateBuffer(Memory); - } - - WaveBuffer Wb = WaveBuffers[BufferIndex]; - - int MaxSize = Samples.Length - Offset; - - int Size = MaxSamples * AudioConsts.HostChannelsCount; - - if (Size > MaxSize) - { - Size = MaxSize; - } - - int[] Output = new int[Size]; - - Array.Copy(Samples, Offset, Output, 0, Size); - - SamplesCount = Size / AudioConsts.HostChannelsCount; - - OutStatus.PlayedSamplesCount += SamplesCount; - - Offset += Size; - - if (Offset == Samples.Length) - { - Offset = 0; - - if (Wb.Looping == 0) - { - SetBufferIndex((BufferIndex + 1) & 3); - } - - OutStatus.PlayedWaveBuffersCount++; - - if (Wb.LastBuffer != 0) - { - PlayState = PlayState.Paused; - } - } - - return Output; - } - - private void UpdateBuffer(AMemory Memory) - { - //TODO: Implement conversion for formats other - //than interleaved stereo (2 channels). - //As of now, it assumes that HostChannelsCount == 2. - WaveBuffer Wb = WaveBuffers[BufferIndex]; - - if (SampleFormat == SampleFormat.PcmInt16) - { - int SamplesCount = (int)(Wb.Size / (sizeof(short) * ChannelsCount)); - - Samples = new int[SamplesCount * AudioConsts.HostChannelsCount]; - - if (ChannelsCount == 1) - { - for (int Index = 0; Index < SamplesCount; Index++) - { - short Sample = Memory.ReadInt16(Wb.Position + Index * 2); - - Samples[Index * 2 + 0] = Sample; - Samples[Index * 2 + 1] = Sample; - } - } - else - { - for (int Index = 0; Index < SamplesCount * 2; Index++) - { - Samples[Index] = Memory.ReadInt16(Wb.Position + Index * 2); - } - } - } - else if (SampleFormat == SampleFormat.Adpcm) - { - byte[] Buffer = Memory.ReadBytes(Wb.Position, Wb.Size); - - Samples = AdpcmDecoder.Decode(Buffer, AdpcmCtx); - } - else - { - throw new InvalidOperationException(); - } - - if (SampleRate != AudioConsts.HostSampleRate) - { - //TODO: We should keep the frames being discarded (see the 4 below) - //on a buffer and include it on the next samples buffer, to allow - //the resampler to do seamless interpolation between wave buffers. - int SamplesCount = Samples.Length / AudioConsts.HostChannelsCount; - - SamplesCount = Math.Max(SamplesCount - 4, 0); - - Samples = Resampler.Resample2Ch( - Samples, - SampleRate, - AudioConsts.HostSampleRate, - SamplesCount, - ref ResamplerFracPart); - } - } - - public void SetBufferIndex(int Index) - { - BufferIndex = Index & 3; - - BufferReload = true; - } - } -} diff --git a/Ryujinx.HLE/OsHle/Services/Aud/AudioRenderer/VoiceIn.cs b/Ryujinx.HLE/OsHle/Services/Aud/AudioRenderer/VoiceIn.cs deleted file mode 100644 index 790affb2..00000000 --- a/Ryujinx.HLE/OsHle/Services/Aud/AudioRenderer/VoiceIn.cs +++ /dev/null @@ -1,49 +0,0 @@ -using System.Runtime.InteropServices; - -namespace Ryujinx.HLE.OsHle.Services.Aud.AudioRenderer -{ - [StructLayout(LayoutKind.Sequential, Size = 0x170, Pack = 1)] - struct VoiceIn - { - public int VoiceSlot; - public int NodeId; - - public byte FirstUpdate; - public byte Acquired; - - public PlayState PlayState; - - public SampleFormat SampleFormat; - - public int SampleRate; - - public int Priority; - - public int Unknown14; - - public int ChannelsCount; - - public float Pitch; - public float Volume; - - public BiquadFilter BiquadFilter0; - public BiquadFilter BiquadFilter1; - - public int AppendedWaveBuffersCount; - - public int BaseWaveBufferIndex; - - public int Unknown44; - - public long AdpcmCoeffsPosition; - public long AdpcmCoeffsSize; - - public int VoiceDestination; - public int Padding; - - public WaveBuffer WaveBuffer0; - public WaveBuffer WaveBuffer1; - public WaveBuffer WaveBuffer2; - public WaveBuffer WaveBuffer3; - } -} diff --git a/Ryujinx.HLE/OsHle/Services/Aud/AudioRenderer/VoiceOut.cs b/Ryujinx.HLE/OsHle/Services/Aud/AudioRenderer/VoiceOut.cs deleted file mode 100644 index 1fcf929f..00000000 --- a/Ryujinx.HLE/OsHle/Services/Aud/AudioRenderer/VoiceOut.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Runtime.InteropServices; - -namespace Ryujinx.HLE.OsHle.Services.Aud.AudioRenderer -{ - [StructLayout(LayoutKind.Sequential, Size = 0x10, Pack = 4)] - struct VoiceOut - { - public long PlayedSamplesCount; - public int PlayedWaveBuffersCount; - public int VoiceDropsCount; //? - } -} diff --git a/Ryujinx.HLE/OsHle/Services/Aud/AudioRenderer/WaveBuffer.cs b/Ryujinx.HLE/OsHle/Services/Aud/AudioRenderer/WaveBuffer.cs deleted file mode 100644 index 6b56b908..00000000 --- a/Ryujinx.HLE/OsHle/Services/Aud/AudioRenderer/WaveBuffer.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System.Runtime.InteropServices; - -namespace Ryujinx.HLE.OsHle.Services.Aud.AudioRenderer -{ - [StructLayout(LayoutKind.Sequential, Size = 0x38, Pack = 1)] - struct WaveBuffer - { - public long Position; - public long Size; - public int FirstSampleOffset; - public int LastSampleOffset; - public byte Looping; - public byte LastBuffer; - public short Unknown1A; - public int Unknown1C; - public long AdpcmLoopContextPosition; - public long AdpcmLoopContextSize; - public long Unknown30; - } -} diff --git a/Ryujinx.HLE/OsHle/Services/Aud/AudioRendererParameter.cs b/Ryujinx.HLE/OsHle/Services/Aud/AudioRendererParameter.cs deleted file mode 100644 index d7e1df01..00000000 --- a/Ryujinx.HLE/OsHle/Services/Aud/AudioRendererParameter.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System.Runtime.InteropServices; - -namespace Ryujinx.HLE.OsHle.Services.Aud -{ - [StructLayout(LayoutKind.Sequential)] - struct AudioRendererParameter - { - public int SampleRate; - public int SampleCount; - public int Unknown8; - public int MixCount; - public int VoiceCount; - public int SinkCount; - public int EffectCount; - public int PerformanceManagerCount; - public int VoiceDropEnable; - public int SplitterCount; - public int SplitterDestinationDataCount; - public int Unknown2C; - public int Revision; - } -} diff --git a/Ryujinx.HLE/OsHle/Services/Aud/IAudioDevice.cs b/Ryujinx.HLE/OsHle/Services/Aud/IAudioDevice.cs deleted file mode 100644 index cc5fc244..00000000 --- a/Ryujinx.HLE/OsHle/Services/Aud/IAudioDevice.cs +++ /dev/null @@ -1,223 +0,0 @@ -using Ryujinx.HLE.Logging; -using Ryujinx.HLE.OsHle.Handles; -using Ryujinx.HLE.OsHle.Ipc; -using Ryujinx.HLE.OsHle.SystemState; -using System.Collections.Generic; -using System.Text; - -namespace Ryujinx.HLE.OsHle.Services.Aud -{ - class IAudioDevice : IpcService - { - private Dictionary m_Commands; - - public override IReadOnlyDictionary Commands => m_Commands; - - private KEvent SystemEvent; - - public IAudioDevice() - { - m_Commands = new Dictionary() - { - { 0, ListAudioDeviceName }, - { 1, SetAudioDeviceOutputVolume }, - { 3, GetActiveAudioDeviceName }, - { 4, QueryAudioDeviceSystemEvent }, - { 5, GetActiveChannelCount }, - { 6, ListAudioDeviceNameAuto }, - { 7, SetAudioDeviceOutputVolumeAuto }, - { 8, GetAudioDeviceOutputVolumeAuto }, - { 10, GetActiveAudioDeviceNameAuto }, - { 11, QueryAudioDeviceInputEvent }, - { 12, QueryAudioDeviceOutputEvent } - }; - - SystemEvent = new KEvent(); - - //TODO: We shouldn't be signaling this here. - SystemEvent.WaitEvent.Set(); - } - - public long ListAudioDeviceName(ServiceCtx Context) - { - string[] DeviceNames = SystemStateMgr.AudioOutputs; - - Context.ResponseData.Write(DeviceNames.Length); - - long Position = Context.Request.ReceiveBuff[0].Position; - long Size = Context.Request.ReceiveBuff[0].Size; - - long BasePosition = Position; - - foreach (string Name in DeviceNames) - { - byte[] Buffer = Encoding.ASCII.GetBytes(Name + "\0"); - - if ((Position - BasePosition) + Buffer.Length > Size) - { - Context.Ns.Log.PrintError(LogClass.ServiceAudio, $"Output buffer size {Size} too small!"); - - break; - } - - Context.Memory.WriteBytes(Position, Buffer); - - Position += Buffer.Length; - } - - return 0; - } - - public long SetAudioDeviceOutputVolume(ServiceCtx Context) - { - float Volume = Context.RequestData.ReadSingle(); - - long Position = Context.Request.SendBuff[0].Position; - long Size = Context.Request.SendBuff[0].Size; - - byte[] DeviceNameBuffer = Context.Memory.ReadBytes(Position, Size); - - string DeviceName = Encoding.ASCII.GetString(DeviceNameBuffer); - - Context.Ns.Log.PrintStub(LogClass.ServiceAudio, "Stubbed."); - - return 0; - } - - public long GetActiveAudioDeviceName(ServiceCtx Context) - { - string Name = Context.Ns.Os.SystemState.ActiveAudioOutput; - - long Position = Context.Request.ReceiveBuff[0].Position; - long Size = Context.Request.ReceiveBuff[0].Size; - - byte[] DeviceNameBuffer = Encoding.ASCII.GetBytes(Name + "\0"); - - if ((ulong)DeviceNameBuffer.Length <= (ulong)Size) - { - Context.Memory.WriteBytes(Position, DeviceNameBuffer); - } - else - { - Context.Ns.Log.PrintError(LogClass.ServiceAudio, $"Output buffer size {Size} too small!"); - } - - return 0; - } - - public long QueryAudioDeviceSystemEvent(ServiceCtx Context) - { - int Handle = Context.Process.HandleTable.OpenHandle(SystemEvent); - - Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle); - - Context.Ns.Log.PrintStub(LogClass.ServiceAudio, "Stubbed."); - - return 0; - } - - public long GetActiveChannelCount(ServiceCtx Context) - { - Context.ResponseData.Write(2); - - Context.Ns.Log.PrintStub(LogClass.ServiceAudio, "Stubbed."); - - return 0; - } - - public long ListAudioDeviceNameAuto(ServiceCtx Context) - { - string[] DeviceNames = SystemStateMgr.AudioOutputs; - - Context.ResponseData.Write(DeviceNames.Length); - - (long Position, long Size) = Context.Request.GetBufferType0x22(); - - long BasePosition = Position; - - foreach (string Name in DeviceNames) - { - byte[] Buffer = Encoding.UTF8.GetBytes(Name + '\0'); - - if ((Position - BasePosition) + Buffer.Length > Size) - { - Context.Ns.Log.PrintError(LogClass.ServiceAudio, $"Output buffer size {Size} too small!"); - - break; - } - - Context.Memory.WriteBytes(Position, Buffer); - - Position += Buffer.Length; - } - - return 0; - } - - public long SetAudioDeviceOutputVolumeAuto(ServiceCtx Context) - { - float Volume = Context.RequestData.ReadSingle(); - - (long Position, long Size) = Context.Request.GetBufferType0x21(); - - byte[] DeviceNameBuffer = Context.Memory.ReadBytes(Position, Size); - - string DeviceName = Encoding.UTF8.GetString(DeviceNameBuffer); - - Context.Ns.Log.PrintStub(LogClass.ServiceAudio, "Stubbed."); - - return 0; - } - - public long GetAudioDeviceOutputVolumeAuto(ServiceCtx Context) - { - Context.ResponseData.Write(1f); - - Context.Ns.Log.PrintStub(LogClass.ServiceAudio, "Stubbed."); - - return 0; - } - - public long GetActiveAudioDeviceNameAuto(ServiceCtx Context) - { - string Name = Context.Ns.Os.SystemState.ActiveAudioOutput; - - (long Position, long Size) = Context.Request.GetBufferType0x22(); - - byte[] DeviceNameBuffer = Encoding.UTF8.GetBytes(Name + '\0'); - - if ((ulong)DeviceNameBuffer.Length <= (ulong)Size) - { - Context.Memory.WriteBytes(Position, DeviceNameBuffer); - } - else - { - Context.Ns.Log.PrintError(LogClass.ServiceAudio, $"Output buffer size {Size} too small!"); - } - - return 0; - } - - public long QueryAudioDeviceInputEvent(ServiceCtx Context) - { - int Handle = Context.Process.HandleTable.OpenHandle(SystemEvent); - - Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle); - - Context.Ns.Log.PrintStub(LogClass.ServiceAudio, "Stubbed."); - - return 0; - } - - public long QueryAudioDeviceOutputEvent(ServiceCtx Context) - { - int Handle = Context.Process.HandleTable.OpenHandle(SystemEvent); - - Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle); - - Context.Ns.Log.PrintStub(LogClass.ServiceAudio, "Stubbed."); - - return 0; - } - } -} diff --git a/Ryujinx.HLE/OsHle/Services/Aud/IAudioOutManager.cs b/Ryujinx.HLE/OsHle/Services/Aud/IAudioOutManager.cs deleted file mode 100644 index 7a3bc4d4..00000000 --- a/Ryujinx.HLE/OsHle/Services/Aud/IAudioOutManager.cs +++ /dev/null @@ -1,170 +0,0 @@ -using ChocolArm64.Memory; -using Ryujinx.Audio; -using Ryujinx.HLE.Logging; -using Ryujinx.HLE.OsHle.Handles; -using Ryujinx.HLE.OsHle.Ipc; -using Ryujinx.HLE.OsHle.Services.Aud.AudioOut; -using System.Collections.Generic; -using System.Text; - -using static Ryujinx.HLE.OsHle.ErrorCode; - -namespace Ryujinx.HLE.OsHle.Services.Aud -{ - class IAudioOutManager : IpcService - { - private const string DefaultAudioOutput = "DeviceOut"; - - private const int DefaultSampleRate = 48000; - - private const int DefaultChannelsCount = 2; - - private Dictionary m_Commands; - - public override IReadOnlyDictionary Commands => m_Commands; - - public IAudioOutManager() - { - m_Commands = new Dictionary() - { - { 0, ListAudioOuts }, - { 1, OpenAudioOut }, - { 2, ListAudioOutsAuto }, - { 3, OpenAudioOutAuto } - }; - } - - public long ListAudioOuts(ServiceCtx Context) - { - return ListAudioOutsImpl( - Context, - Context.Request.ReceiveBuff[0].Position, - Context.Request.ReceiveBuff[0].Size); - } - - public long OpenAudioOut(ServiceCtx Context) - { - return OpenAudioOutImpl( - Context, - Context.Request.SendBuff[0].Position, - Context.Request.SendBuff[0].Size, - Context.Request.ReceiveBuff[0].Position, - Context.Request.ReceiveBuff[0].Size); - } - - public long ListAudioOutsAuto(ServiceCtx Context) - { - (long RecvPosition, long RecvSize) = Context.Request.GetBufferType0x22(); - - return ListAudioOutsImpl(Context, RecvPosition, RecvSize); - } - - public long OpenAudioOutAuto(ServiceCtx Context) - { - (long SendPosition, long SendSize) = Context.Request.GetBufferType0x21(); - (long RecvPosition, long RecvSize) = Context.Request.GetBufferType0x22(); - - return OpenAudioOutImpl( - Context, - SendPosition, - SendSize, - RecvPosition, - RecvSize); - } - - private long ListAudioOutsImpl(ServiceCtx Context, long Position, long Size) - { - int NameCount = 0; - - byte[] DeviceNameBuffer = Encoding.ASCII.GetBytes(DefaultAudioOutput + "\0"); - - if ((ulong)DeviceNameBuffer.Length <= (ulong)Size) - { - Context.Memory.WriteBytes(Position, DeviceNameBuffer); - - NameCount++; - } - else - { - Context.Ns.Log.PrintError(LogClass.ServiceAudio, $"Output buffer size {Size} too small!"); - } - - Context.ResponseData.Write(NameCount); - - return 0; - } - - private long OpenAudioOutImpl(ServiceCtx Context, long SendPosition, long SendSize, long ReceivePosition, long ReceiveSize) - { - string DeviceName = AMemoryHelper.ReadAsciiString( - Context.Memory, - SendPosition, - SendSize); - - if (DeviceName == string.Empty) - { - DeviceName = DefaultAudioOutput; - } - - if (DeviceName != DefaultAudioOutput) - { - Context.Ns.Log.PrintWarning(LogClass.Audio, "Invalid device name!"); - - return MakeError(ErrorModule.Audio, AudErr.DeviceNotFound); - } - - byte[] DeviceNameBuffer = Encoding.ASCII.GetBytes(DeviceName + "\0"); - - if ((ulong)DeviceNameBuffer.Length <= (ulong)ReceiveSize) - { - Context.Memory.WriteBytes(ReceivePosition, DeviceNameBuffer); - } - else - { - Context.Ns.Log.PrintError(LogClass.ServiceAudio, $"Output buffer size {ReceiveSize} too small!"); - } - - int SampleRate = Context.RequestData.ReadInt32(); - int Channels = Context.RequestData.ReadInt32(); - - if (SampleRate == 0) - { - SampleRate = DefaultSampleRate; - } - - if (SampleRate != DefaultSampleRate) - { - Context.Ns.Log.PrintWarning(LogClass.Audio, "Invalid sample rate!"); - - return MakeError(ErrorModule.Audio, AudErr.UnsupportedSampleRate); - } - - Channels = (ushort)Channels; - - if (Channels == 0) - { - Channels = DefaultChannelsCount; - } - - KEvent ReleaseEvent = new KEvent(); - - ReleaseCallback Callback = () => - { - ReleaseEvent.WaitEvent.Set(); - }; - - IAalOutput AudioOut = Context.Ns.AudioOut; - - int Track = AudioOut.OpenTrack(SampleRate, Channels, Callback); - - MakeObject(Context, new IAudioOut(AudioOut, ReleaseEvent, Track)); - - Context.ResponseData.Write(SampleRate); - Context.ResponseData.Write(Channels); - Context.ResponseData.Write((int)SampleFormat.PcmInt16); - Context.ResponseData.Write((int)PlaybackState.Stopped); - - return 0; - } - } -} diff --git a/Ryujinx.HLE/OsHle/Services/Aud/IAudioRendererManager.cs b/Ryujinx.HLE/OsHle/Services/Aud/IAudioRendererManager.cs deleted file mode 100644 index 5e2dec9f..00000000 --- a/Ryujinx.HLE/OsHle/Services/Aud/IAudioRendererManager.cs +++ /dev/null @@ -1,169 +0,0 @@ -using Ryujinx.Audio; -using Ryujinx.HLE.Logging; -using Ryujinx.HLE.OsHle.Ipc; -using Ryujinx.HLE.OsHle.Services.Aud.AudioRenderer; -using Ryujinx.HLE.OsHle.Utilities; -using System.Collections.Generic; - -using static Ryujinx.HLE.OsHle.ErrorCode; - -namespace Ryujinx.HLE.OsHle.Services.Aud -{ - class IAudioRendererManager : IpcService - { - private const int Rev0Magic = ('R' << 0) | - ('E' << 8) | - ('V' << 16) | - ('0' << 24); - - private const int Rev = 4; - - public const int RevMagic = Rev0Magic + (Rev << 24); - - private Dictionary m_Commands; - - public override IReadOnlyDictionary Commands => m_Commands; - - public IAudioRendererManager() - { - m_Commands = new Dictionary() - { - { 0, OpenAudioRenderer }, - { 1, GetAudioRendererWorkBufferSize }, - { 2, GetAudioDevice } - }; - } - - public long OpenAudioRenderer(ServiceCtx Context) - { - IAalOutput AudioOut = Context.Ns.AudioOut; - - AudioRendererParameter Params = GetAudioRendererParameter(Context); - - MakeObject(Context, new IAudioRenderer(Context.Memory, AudioOut, Params)); - - return 0; - } - - public long GetAudioRendererWorkBufferSize(ServiceCtx Context) - { - AudioRendererParameter Params = GetAudioRendererParameter(Context); - - int Revision = (Params.Revision - Rev0Magic) >> 24; - - if (Revision <= Rev) - { - bool IsSplitterSupported = Revision >= 3; - - long Size; - - Size = IntUtils.AlignUp(Params.Unknown8 * 4, 64); - Size += Params.MixCount * 0x400; - Size += (Params.MixCount + 1) * 0x940; - Size += Params.VoiceCount * 0x3F0; - Size += IntUtils.AlignUp((Params.MixCount + 1) * 8, 16); - Size += IntUtils.AlignUp(Params.VoiceCount * 8, 16); - Size += IntUtils.AlignUp( - ((Params.SinkCount + Params.MixCount) * 0x3C0 + Params.SampleCount * 4) * - (Params.Unknown8 + 6), 64); - Size += (Params.SinkCount + Params.MixCount) * 0x2C0; - Size += (Params.EffectCount + Params.VoiceCount * 4) * 0x30 + 0x50; - - if (IsSplitterSupported) - { - Size += IntUtils.AlignUp(( - NodeStatesGetWorkBufferSize(Params.MixCount + 1) + - EdgeMatrixGetWorkBufferSize(Params.MixCount + 1)), 16); - - Size += Params.SplitterDestinationDataCount * 0xE0; - Size += Params.SplitterCount * 0x20; - Size += IntUtils.AlignUp(Params.SplitterDestinationDataCount * 4, 16); - } - - Size = Params.EffectCount * 0x4C0 + - Params.SinkCount * 0x170 + - Params.VoiceCount * 0x100 + - IntUtils.AlignUp(Size, 64) + 0x40; - - if (Params.PerformanceManagerCount >= 1) - { - Size += (((Params.EffectCount + - Params.SinkCount + - Params.VoiceCount + - Params.MixCount + 1) * 16 + 0x658) * - (Params.PerformanceManagerCount + 1) + 0x13F) & ~0x3FL; - } - - Size = (Size + 0x1907D) & ~0xFFFL; - - Context.ResponseData.Write(Size); - - Context.Ns.Log.PrintDebug(LogClass.ServiceAudio, $"WorkBufferSize is 0x{Size:x16}."); - - return 0; - } - else - { - Context.ResponseData.Write(0L); - - Context.Ns.Log.PrintWarning(LogClass.ServiceAudio, $"Library Revision 0x{Params.Revision:x8} is not supported!"); - - return MakeError(ErrorModule.Audio, AudErr.UnsupportedRevision); - } - } - - private AudioRendererParameter GetAudioRendererParameter(ServiceCtx Context) - { - AudioRendererParameter Params = new AudioRendererParameter(); - - Params.SampleRate = Context.RequestData.ReadInt32(); - Params.SampleCount = Context.RequestData.ReadInt32(); - Params.Unknown8 = Context.RequestData.ReadInt32(); - Params.MixCount = Context.RequestData.ReadInt32(); - Params.VoiceCount = Context.RequestData.ReadInt32(); - Params.SinkCount = Context.RequestData.ReadInt32(); - Params.EffectCount = Context.RequestData.ReadInt32(); - Params.PerformanceManagerCount = Context.RequestData.ReadInt32(); - Params.VoiceDropEnable = Context.RequestData.ReadInt32(); - Params.SplitterCount = Context.RequestData.ReadInt32(); - Params.SplitterDestinationDataCount = Context.RequestData.ReadInt32(); - Params.Unknown2C = Context.RequestData.ReadInt32(); - Params.Revision = Context.RequestData.ReadInt32(); - - return Params; - } - - private static int NodeStatesGetWorkBufferSize(int Value) - { - int Result = IntUtils.AlignUp(Value, 64); - - if (Result < 0) - { - Result |= 7; - } - - return 4 * (Value * Value) + 0x12 * Value + 2 * (Result / 8); - } - - private static int EdgeMatrixGetWorkBufferSize(int Value) - { - int Result = IntUtils.AlignUp(Value * Value, 64); - - if (Result < 0) - { - Result |= 7; - } - - return Result / 8; - } - - public long GetAudioDevice(ServiceCtx Context) - { - long UserId = Context.RequestData.ReadInt64(); - - MakeObject(Context, new IAudioDevice()); - - return 0; - } - } -} diff --git a/Ryujinx.HLE/OsHle/Services/Aud/SampleFormat.cs b/Ryujinx.HLE/OsHle/Services/Aud/SampleFormat.cs deleted file mode 100644 index 06ab4929..00000000 --- a/Ryujinx.HLE/OsHle/Services/Aud/SampleFormat.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace Ryujinx.HLE.OsHle.Services.Aud -{ - enum SampleFormat : byte - { - Invalid = 0, - PcmInt8 = 1, - PcmInt16 = 2, - PcmInt24 = 3, - PcmInt32 = 4, - PcmFloat = 5, - Adpcm = 6 - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Bcat/IBcatService.cs b/Ryujinx.HLE/OsHle/Services/Bcat/IBcatService.cs deleted file mode 100644 index b7754d6b..00000000 --- a/Ryujinx.HLE/OsHle/Services/Bcat/IBcatService.cs +++ /dev/null @@ -1,21 +0,0 @@ -using Ryujinx.HLE.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.HLE.OsHle.Services.Bcat -{ - class IBcatService : IpcService - { - private Dictionary m_Commands; - - public override IReadOnlyDictionary Commands => m_Commands; - - public IBcatService() - { - m_Commands = new Dictionary() - { - //... - }; - } - - } -} diff --git a/Ryujinx.HLE/OsHle/Services/Bcat/IDeliveryCacheStorageService.cs b/Ryujinx.HLE/OsHle/Services/Bcat/IDeliveryCacheStorageService.cs deleted file mode 100644 index 0b84d809..00000000 --- a/Ryujinx.HLE/OsHle/Services/Bcat/IDeliveryCacheStorageService.cs +++ /dev/null @@ -1,21 +0,0 @@ -using Ryujinx.HLE.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.HLE.OsHle.Services.Bcat -{ - class IDeliveryCacheStorageService : IpcService - { - private Dictionary m_Commands; - - public override IReadOnlyDictionary Commands => m_Commands; - - public IDeliveryCacheStorageService() - { - m_Commands = new Dictionary() - { - //... - }; - } - - } -} diff --git a/Ryujinx.HLE/OsHle/Services/Bcat/IServiceCreator.cs b/Ryujinx.HLE/OsHle/Services/Bcat/IServiceCreator.cs deleted file mode 100644 index cc1fc6f8..00000000 --- a/Ryujinx.HLE/OsHle/Services/Bcat/IServiceCreator.cs +++ /dev/null @@ -1,39 +0,0 @@ -using Ryujinx.HLE.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.HLE.OsHle.Services.Bcat -{ - class IServiceCreator : IpcService - { - private Dictionary m_Commands; - - public override IReadOnlyDictionary Commands => m_Commands; - - public IServiceCreator() - { - m_Commands = new Dictionary() - { - { 0, CreateBcatService }, - { 1, CreateDeliveryCacheStorageService } - }; - } - - public long CreateBcatService(ServiceCtx Context) - { - long Id = Context.RequestData.ReadInt64(); - - MakeObject(Context, new IBcatService()); - - return 0; - } - - public long CreateDeliveryCacheStorageService(ServiceCtx Context) - { - long Id = Context.RequestData.ReadInt64(); - - MakeObject(Context, new IDeliveryCacheStorageService()); - - return 0; - } - } -} diff --git a/Ryujinx.HLE/OsHle/Services/Bsd/BsdError.cs b/Ryujinx.HLE/OsHle/Services/Bsd/BsdError.cs deleted file mode 100644 index 114130dc..00000000 --- a/Ryujinx.HLE/OsHle/Services/Bsd/BsdError.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Ryujinx.HLE.OsHle.Services.Bsd -{ - //bsd_errno == (SocketException.ErrorCode - 10000) - public enum BsdError - { - Timeout = 60 - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Bsd/BsdSocket.cs b/Ryujinx.HLE/OsHle/Services/Bsd/BsdSocket.cs deleted file mode 100644 index 9cde9947..00000000 --- a/Ryujinx.HLE/OsHle/Services/Bsd/BsdSocket.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System.Net; -using System.Net.Sockets; - -namespace Ryujinx.HLE.OsHle.Services.Bsd -{ - class BsdSocket - { - public int Family; - public int Type; - public int Protocol; - - public IPAddress IpAddress; - - public IPEndPoint RemoteEP; - - public Socket Handle; - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Bsd/IClient.cs b/Ryujinx.HLE/OsHle/Services/Bsd/IClient.cs deleted file mode 100644 index 15ce92a1..00000000 --- a/Ryujinx.HLE/OsHle/Services/Bsd/IClient.cs +++ /dev/null @@ -1,445 +0,0 @@ -using Ryujinx.HLE.OsHle.Ipc; -using Ryujinx.HLE.OsHle.Utilities; -using System.Collections.Generic; -using System.IO; -using System.Net; -using System.Net.Sockets; -using System.Threading.Tasks; - -namespace Ryujinx.HLE.OsHle.Services.Bsd -{ - class IClient : IpcService - { - private Dictionary m_Commands; - - public override IReadOnlyDictionary Commands => m_Commands; - - private List Sockets = new List(); - - public IClient() - { - m_Commands = new Dictionary() - { - { 0, Initialize }, - { 1, StartMonitoring }, - { 2, Socket }, - { 6, Poll }, - { 8, Recv }, - { 10, Send }, - { 11, SendTo }, - { 12, Accept }, - { 13, Bind }, - { 14, Connect }, - { 18, Listen }, - { 21, SetSockOpt }, - { 26, Close } - }; - } - - //(u32, u32, u32, u32, u32, u32, u32, u32, u64 pid, u64 transferMemorySize, pid, KObject) -> u32 bsd_errno - public long Initialize(ServiceCtx Context) - { - /* - typedef struct { - u32 version; // Observed 1 on 2.0 LibAppletWeb, 2 on 3.0. - u32 tcp_tx_buf_size; // Size of the TCP transfer (send) buffer (initial or fixed). - u32 tcp_rx_buf_size; // Size of the TCP recieve buffer (initial or fixed). - u32 tcp_tx_buf_max_size; // Maximum size of the TCP transfer (send) buffer. If it is 0, the size of the buffer is fixed to its initial value. - u32 tcp_rx_buf_max_size; // Maximum size of the TCP receive buffer. If it is 0, the size of the buffer is fixed to its initial value. - u32 udp_tx_buf_size; // Size of the UDP transfer (send) buffer (typically 0x2400 bytes). - u32 udp_rx_buf_size; // Size of the UDP receive buffer (typically 0xA500 bytes). - u32 sb_efficiency; // Number of buffers for each socket (standard values range from 1 to 8). - } BsdBufferConfig; - */ - - Context.ResponseData.Write(0); - - //Todo: Stub - - return 0; - } - - //(u64, pid) - public long StartMonitoring(ServiceCtx Context) - { - //Todo: Stub - - return 0; - } - - //(u32 domain, u32 type, u32 protocol) -> (i32 ret, u32 bsd_errno) - public long Socket(ServiceCtx Context) - { - BsdSocket NewBsdSocket = new BsdSocket - { - Family = Context.RequestData.ReadInt32(), - Type = Context.RequestData.ReadInt32(), - Protocol = Context.RequestData.ReadInt32() - }; - - Sockets.Add(NewBsdSocket); - - NewBsdSocket.Handle = new Socket((AddressFamily)NewBsdSocket.Family, - (SocketType)NewBsdSocket.Type, - (ProtocolType)NewBsdSocket.Protocol); - - Context.ResponseData.Write(Sockets.Count - 1); - Context.ResponseData.Write(0); - - return 0; - } - - //(u32, u32, buffer) -> (i32 ret, u32 bsd_errno, buffer) - public long Poll(ServiceCtx Context) - { - int PollCount = Context.RequestData.ReadInt32(); - int TimeOut = Context.RequestData.ReadInt32(); - - //https://github.com/torvalds/linux/blob/master/include/uapi/asm-generic/poll.h - //https://msdn.microsoft.com/fr-fr/library/system.net.sockets.socket.poll(v=vs.110).aspx - //https://github.com/switchbrew/libnx/blob/e0457c4534b3c37426d83e1a620f82cb28c3b528/nx/source/services/bsd.c#L343 - //https://github.com/TuxSH/ftpd/blob/switch_pr/source/ftp.c#L1634 - //https://linux.die.net/man/2/poll - - byte[] SentBuffer = Context.Memory.ReadBytes(Context.Request.SendBuff[0].Position, - Context.Request.SendBuff[0].Size); - - int SocketId = Get32(SentBuffer, 0); - int RequestedEvents = Get16(SentBuffer, 4); - int ReturnedEvents = Get16(SentBuffer, 6); - - //Todo: Stub - Need to implemented the Type-22 buffer. - - Context.ResponseData.Write(1); - Context.ResponseData.Write(0); - - return 0; - } - - //(u32 socket, u32 flags) -> (i32 ret, u32 bsd_errno, buffer message) - public long Recv(ServiceCtx Context) - { - int SocketId = Context.RequestData.ReadInt32(); - int SocketFlags = Context.RequestData.ReadInt32(); - - byte[] ReceivedBuffer = new byte[Context.Request.ReceiveBuff[0].Size]; - - try - { - int BytesRead = Sockets[SocketId].Handle.Receive(ReceivedBuffer); - - //Logging.Debug("Received Buffer:" + Environment.NewLine + Logging.HexDump(ReceivedBuffer)); - - Context.Memory.WriteBytes(Context.Request.ReceiveBuff[0].Position, ReceivedBuffer); - - Context.ResponseData.Write(BytesRead); - Context.ResponseData.Write(0); - } - catch (SocketException Ex) - { - Context.ResponseData.Write(-1); - Context.ResponseData.Write(Ex.ErrorCode - 10000); - } - - return 0; - } - - //(u32 socket, u32 flags, buffer) -> (i32 ret, u32 bsd_errno) - public long Send(ServiceCtx Context) - { - int SocketId = Context.RequestData.ReadInt32(); - int SocketFlags = Context.RequestData.ReadInt32(); - - byte[] SentBuffer = Context.Memory.ReadBytes(Context.Request.SendBuff[0].Position, - Context.Request.SendBuff[0].Size); - - try - { - //Logging.Debug("Sent Buffer:" + Environment.NewLine + Logging.HexDump(SentBuffer)); - - int BytesSent = Sockets[SocketId].Handle.Send(SentBuffer); - - Context.ResponseData.Write(BytesSent); - Context.ResponseData.Write(0); - } - catch (SocketException Ex) - { - Context.ResponseData.Write(-1); - Context.ResponseData.Write(Ex.ErrorCode - 10000); - } - - return 0; - } - - //(u32 socket, u32 flags, buffer, buffer) -> (i32 ret, u32 bsd_errno) - public long SendTo(ServiceCtx Context) - { - int SocketId = Context.RequestData.ReadInt32(); - int SocketFlags = Context.RequestData.ReadInt32(); - - byte[] SentBuffer = Context.Memory.ReadBytes(Context.Request.SendBuff[0].Position, - Context.Request.SendBuff[0].Size); - - byte[] AddressBuffer = Context.Memory.ReadBytes(Context.Request.SendBuff[1].Position, - Context.Request.SendBuff[1].Size); - - if (!Sockets[SocketId].Handle.Connected) - { - try - { - ParseAddrBuffer(SocketId, AddressBuffer); - - Sockets[SocketId].Handle.Connect(Sockets[SocketId].RemoteEP); - } - catch (SocketException Ex) - { - Context.ResponseData.Write(-1); - Context.ResponseData.Write(Ex.ErrorCode - 10000); - } - } - - try - { - //Logging.Debug("Sent Buffer:" + Environment.NewLine + Logging.HexDump(SentBuffer)); - - int BytesSent = Sockets[SocketId].Handle.Send(SentBuffer); - - Context.ResponseData.Write(BytesSent); - Context.ResponseData.Write(0); - } - catch (SocketException Ex) - { - Context.ResponseData.Write(-1); - Context.ResponseData.Write(Ex.ErrorCode - 10000); - } - - return 0; - } - - //(u32 socket) -> (i32 ret, u32 bsd_errno, u32 addrlen, buffer addr) - public long Accept(ServiceCtx Context) - { - int SocketId = Context.RequestData.ReadInt32(); - - long AddrBufferPtr = Context.Request.ReceiveBuff[0].Position; - - Socket HandleAccept = null; - - Task TimeOut = Task.Factory.StartNew(() => - { - try - { - HandleAccept = Sockets[SocketId].Handle.Accept(); - } - catch (SocketException Ex) - { - Context.ResponseData.Write(-1); - Context.ResponseData.Write(Ex.ErrorCode - 10000); - } - }); - - TimeOut.Wait(10000); - - if (HandleAccept != null) - { - BsdSocket NewBsdSocket = new BsdSocket - { - IpAddress = ((IPEndPoint)Sockets[SocketId].Handle.LocalEndPoint).Address, - RemoteEP = ((IPEndPoint)Sockets[SocketId].Handle.LocalEndPoint), - Handle = HandleAccept - }; - - Sockets.Add(NewBsdSocket); - - using (MemoryStream MS = new MemoryStream()) - { - BinaryWriter Writer = new BinaryWriter(MS); - - Writer.Write((byte)0); - - Writer.Write((byte)NewBsdSocket.Handle.AddressFamily); - - Writer.Write((short)((IPEndPoint)NewBsdSocket.Handle.LocalEndPoint).Port); - - byte[] IpAddress = NewBsdSocket.IpAddress.GetAddressBytes(); - - Writer.Write(IpAddress); - - Context.Memory.WriteBytes(AddrBufferPtr, MS.ToArray()); - - Context.ResponseData.Write(Sockets.Count - 1); - Context.ResponseData.Write(0); - Context.ResponseData.Write(MS.Length); - } - } - else - { - Context.ResponseData.Write(-1); - Context.ResponseData.Write((int)BsdError.Timeout); - } - - return 0; - } - - //(u32 socket, buffer) -> (i32 ret, u32 bsd_errno) - public long Bind(ServiceCtx Context) - { - int SocketId = Context.RequestData.ReadInt32(); - - byte[] AddressBuffer = Context.Memory.ReadBytes(Context.Request.SendBuff[0].Position, - Context.Request.SendBuff[0].Size); - - try - { - ParseAddrBuffer(SocketId, AddressBuffer); - - Context.ResponseData.Write(0); - Context.ResponseData.Write(0); - } - catch (SocketException Ex) - { - Context.ResponseData.Write(-1); - Context.ResponseData.Write(Ex.ErrorCode - 10000); - } - - return 0; - } - - //(u32 socket, buffer) -> (i32 ret, u32 bsd_errno) - public long Connect(ServiceCtx Context) - { - int SocketId = Context.RequestData.ReadInt32(); - - byte[] AddressBuffer = Context.Memory.ReadBytes(Context.Request.SendBuff[0].Position, - Context.Request.SendBuff[0].Size); - - try - { - ParseAddrBuffer(SocketId, AddressBuffer); - - Sockets[SocketId].Handle.Connect(Sockets[SocketId].RemoteEP); - - Context.ResponseData.Write(0); - Context.ResponseData.Write(0); - } - catch (SocketException Ex) - { - Context.ResponseData.Write(-1); - Context.ResponseData.Write(Ex.ErrorCode - 10000); - } - - return 0; - } - - //(u32 socket, u32 backlog) -> (i32 ret, u32 bsd_errno) - public long Listen(ServiceCtx Context) - { - int SocketId = Context.RequestData.ReadInt32(); - int BackLog = Context.RequestData.ReadInt32(); - - try - { - Sockets[SocketId].Handle.Bind(Sockets[SocketId].RemoteEP); - Sockets[SocketId].Handle.Listen(BackLog); - - Context.ResponseData.Write(0); - Context.ResponseData.Write(0); - } - catch (SocketException Ex) - { - Context.ResponseData.Write(-1); - Context.ResponseData.Write(Ex.ErrorCode - 10000); - } - - return 0; - } - - //(u32 socket, u32 level, u32 option_name, buffer) -> (i32 ret, u32 bsd_errno) - public long SetSockOpt(ServiceCtx Context) - { - int SocketId = Context.RequestData.ReadInt32(); - - SocketOptionLevel SocketLevel = (SocketOptionLevel)Context.RequestData.ReadInt32(); - SocketOptionName SocketOptionName = (SocketOptionName)Context.RequestData.ReadInt32(); - - byte[] SocketOptionValue = Context.Memory.ReadBytes(Context.Request.PtrBuff[0].Position, - Context.Request.PtrBuff[0].Size); - - int OptionValue = Get32(SocketOptionValue, 0); - - try - { - Sockets[SocketId].Handle.SetSocketOption(SocketLevel, SocketOptionName, OptionValue); - - Context.ResponseData.Write(0); - Context.ResponseData.Write(0); - } - catch (SocketException Ex) - { - Context.ResponseData.Write(-1); - Context.ResponseData.Write(Ex.ErrorCode - 10000); - } - - return 0; - } - - //(u32 socket) -> (i32 ret, u32 bsd_errno) - public long Close(ServiceCtx Context) - { - int SocketId = Context.RequestData.ReadInt32(); - - try - { - Sockets[SocketId].Handle.Close(); - Sockets[SocketId] = null; - - Context.ResponseData.Write(0); - Context.ResponseData.Write(0); - } - catch (SocketException Ex) - { - Context.ResponseData.Write(-1); - Context.ResponseData.Write(Ex.ErrorCode - 10000); - } - - return 0; - } - - public void ParseAddrBuffer(int SocketId, byte[] AddrBuffer) - { - using (MemoryStream MS = new MemoryStream(AddrBuffer)) - { - BinaryReader Reader = new BinaryReader(MS); - - int Size = Reader.ReadByte(); - int Family = Reader.ReadByte(); - int Port = EndianSwap.Swap16(Reader.ReadInt16()); - - string IpAddress = Reader.ReadByte().ToString() + "." + - Reader.ReadByte().ToString() + "." + - Reader.ReadByte().ToString() + "." + - Reader.ReadByte().ToString(); - - Sockets[SocketId].IpAddress = IPAddress.Parse(IpAddress); - - Sockets[SocketId].RemoteEP = new IPEndPoint(Sockets[SocketId].IpAddress, Port); - } - } - - private int Get16(byte[] Data, int Address) - { - return - Data[Address + 0] << 0 | - Data[Address + 1] << 8; - } - - private int Get32(byte[] Data, int Address) - { - return - Data[Address + 0] << 0 | - Data[Address + 1] << 8 | - Data[Address + 2] << 16 | - Data[Address + 3] << 24; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Caps/IAlbumAccessorService.cs b/Ryujinx.HLE/OsHle/Services/Caps/IAlbumAccessorService.cs deleted file mode 100644 index 04a81f90..00000000 --- a/Ryujinx.HLE/OsHle/Services/Caps/IAlbumAccessorService.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Ryujinx.HLE.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.HLE.OsHle.Services.Caps -{ - class IAlbumAccessorService : IpcService - { - private Dictionary m_Commands; - - public override IReadOnlyDictionary Commands => m_Commands; - - public IAlbumAccessorService() - { - m_Commands = new Dictionary() - { - //... - }; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Caps/IScreenshotService.cs b/Ryujinx.HLE/OsHle/Services/Caps/IScreenshotService.cs deleted file mode 100644 index 9b1005ed..00000000 --- a/Ryujinx.HLE/OsHle/Services/Caps/IScreenshotService.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Ryujinx.HLE.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.HLE.OsHle.Services.Caps -{ - class IScreenshotService : IpcService - { - private Dictionary m_Commands; - - public override IReadOnlyDictionary Commands => m_Commands; - - public IScreenshotService() - { - m_Commands = new Dictionary() - { - //... - }; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Friend/IFriendService.cs b/Ryujinx.HLE/OsHle/Services/Friend/IFriendService.cs deleted file mode 100644 index e241138f..00000000 --- a/Ryujinx.HLE/OsHle/Services/Friend/IFriendService.cs +++ /dev/null @@ -1,49 +0,0 @@ -using Ryujinx.HLE.Logging; -using Ryujinx.HLE.OsHle.Ipc; -using Ryujinx.HLE.OsHle.SystemState; -using System.Collections.Generic; - -namespace Ryujinx.HLE.OsHle.Services.Friend -{ - class IFriendService : IpcService - { - private Dictionary m_Commands; - - public override IReadOnlyDictionary Commands => m_Commands; - - public IFriendService() - { - m_Commands = new Dictionary() - { - { 10601, DeclareCloseOnlinePlaySession }, - { 10610, UpdateUserPresence } - }; - } - - public long DeclareCloseOnlinePlaySession(ServiceCtx Context) - { - UserId Uuid = new UserId( - Context.RequestData.ReadInt64(), - Context.RequestData.ReadInt64()); - - if (Context.Ns.Os.SystemState.TryGetUser(Uuid, out UserProfile Profile)) - { - Profile.OnlinePlayState = OpenCloseState.Closed; - } - - return 0; - } - - public long UpdateUserPresence(ServiceCtx Context) - { - UserId Uuid = new UserId( - Context.RequestData.ReadInt64(), - Context.RequestData.ReadInt64()); - - //TODO. - Context.Ns.Log.PrintStub(LogClass.ServiceFriend, "Stubbed."); - - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Friend/IServiceCreator.cs b/Ryujinx.HLE/OsHle/Services/Friend/IServiceCreator.cs deleted file mode 100644 index 6b9a265f..00000000 --- a/Ryujinx.HLE/OsHle/Services/Friend/IServiceCreator.cs +++ /dev/null @@ -1,27 +0,0 @@ -using Ryujinx.HLE.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.HLE.OsHle.Services.Friend -{ - class IServiceCreator : IpcService - { - private Dictionary m_Commands; - - public override IReadOnlyDictionary Commands => m_Commands; - - public IServiceCreator() - { - m_Commands = new Dictionary() - { - { 0, CreateFriendService } - }; - } - - public static long CreateFriendService(ServiceCtx Context) - { - MakeObject(Context, new IFriendService()); - - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/FspSrv/FsErr.cs b/Ryujinx.HLE/OsHle/Services/FspSrv/FsErr.cs deleted file mode 100644 index bdc70959..00000000 --- a/Ryujinx.HLE/OsHle/Services/FspSrv/FsErr.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Ryujinx.HLE.OsHle.Services.FspSrv -{ - static class FsErr - { - public const int PathDoesNotExist = 1; - public const int PathAlreadyExists = 2; - public const int PathAlreadyInUse = 7; - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/FspSrv/IDirectory.cs b/Ryujinx.HLE/OsHle/Services/FspSrv/IDirectory.cs deleted file mode 100644 index bb4b7a03..00000000 --- a/Ryujinx.HLE/OsHle/Services/FspSrv/IDirectory.cs +++ /dev/null @@ -1,116 +0,0 @@ -using Ryujinx.HLE.OsHle.Ipc; -using System; -using System.Collections.Generic; -using System.IO; -using System.Text; - -namespace Ryujinx.HLE.OsHle.Services.FspSrv -{ - class IDirectory : IpcService, IDisposable - { - private const int DirectoryEntrySize = 0x310; - - private Dictionary m_Commands; - - public override IReadOnlyDictionary Commands => m_Commands; - - private List DirectoryEntries; - - private int CurrentItemIndex; - - public event EventHandler Disposed; - - public string HostPath { get; private set; } - - public IDirectory(string HostPath, int Flags) - { - m_Commands = new Dictionary() - { - { 0, Read }, - { 1, GetEntryCount } - }; - - this.HostPath = HostPath; - - DirectoryEntries = new List(); - - if ((Flags & 1) != 0) - { - DirectoryEntries.AddRange(Directory.GetDirectories(HostPath)); - } - - if ((Flags & 2) != 0) - { - DirectoryEntries.AddRange(Directory.GetFiles(HostPath)); - } - - CurrentItemIndex = 0; - } - - public long Read(ServiceCtx Context) - { - long BufferPosition = Context.Request.ReceiveBuff[0].Position; - long BufferLen = Context.Request.ReceiveBuff[0].Size; - - int MaxReadCount = (int)(BufferLen / DirectoryEntrySize); - - int Count = Math.Min(DirectoryEntries.Count - CurrentItemIndex, MaxReadCount); - - for (int Index = 0; Index < Count; Index++) - { - long Position = BufferPosition + Index * DirectoryEntrySize; - - WriteDirectoryEntry(Context, Position, DirectoryEntries[CurrentItemIndex++]); - } - - Context.ResponseData.Write((long)Count); - - return 0; - } - - private void WriteDirectoryEntry(ServiceCtx Context, long Position, string FullPath) - { - for (int Offset = 0; Offset < 0x300; Offset += 8) - { - Context.Memory.WriteInt64(Position + Offset, 0); - } - - byte[] NameBuffer = Encoding.UTF8.GetBytes(Path.GetFileName(FullPath)); - - Context.Memory.WriteBytes(Position, NameBuffer); - - int Type = 0; - long Size = 0; - - if (File.Exists(FullPath)) - { - Type = 1; - Size = new FileInfo(FullPath).Length; - } - - Context.Memory.WriteInt32(Position + 0x300, 0); //Padding? - Context.Memory.WriteInt32(Position + 0x304, Type); - Context.Memory.WriteInt64(Position + 0x308, Size); - } - - public long GetEntryCount(ServiceCtx Context) - { - Context.ResponseData.Write((long)DirectoryEntries.Count); - - return 0; - } - - public void Dispose() - { - Dispose(true); - } - - protected virtual void Dispose(bool disposing) - { - if (disposing) - { - Disposed?.Invoke(this, EventArgs.Empty); - } - } - } -} diff --git a/Ryujinx.HLE/OsHle/Services/FspSrv/IFile.cs b/Ryujinx.HLE/OsHle/Services/FspSrv/IFile.cs deleted file mode 100644 index a610a3ab..00000000 --- a/Ryujinx.HLE/OsHle/Services/FspSrv/IFile.cs +++ /dev/null @@ -1,110 +0,0 @@ -using Ryujinx.HLE.OsHle.Ipc; -using System; -using System.Collections.Generic; -using System.IO; - -namespace Ryujinx.HLE.OsHle.Services.FspSrv -{ - class IFile : IpcService, IDisposable - { - private Dictionary m_Commands; - - public override IReadOnlyDictionary Commands => m_Commands; - - private Stream BaseStream; - - public event EventHandler Disposed; - - public string HostPath { get; private set; } - - public IFile(Stream BaseStream, string HostPath) - { - m_Commands = new Dictionary() - { - { 0, Read }, - { 1, Write }, - { 2, Flush }, - { 3, SetSize }, - { 4, GetSize } - }; - - this.BaseStream = BaseStream; - this.HostPath = HostPath; - } - - public long Read(ServiceCtx Context) - { - long Position = Context.Request.ReceiveBuff[0].Position; - - long Zero = Context.RequestData.ReadInt64(); - long Offset = Context.RequestData.ReadInt64(); - long Size = Context.RequestData.ReadInt64(); - - byte[] Data = new byte[Size]; - - BaseStream.Seek(Offset, SeekOrigin.Begin); - - int ReadSize = BaseStream.Read(Data, 0, (int)Size); - - Context.Memory.WriteBytes(Position, Data); - - Context.ResponseData.Write((long)ReadSize); - - return 0; - } - - public long Write(ServiceCtx Context) - { - long Position = Context.Request.SendBuff[0].Position; - - long Zero = Context.RequestData.ReadInt64(); - long Offset = Context.RequestData.ReadInt64(); - long Size = Context.RequestData.ReadInt64(); - - byte[] Data = Context.Memory.ReadBytes(Position, Size); - - BaseStream.Seek(Offset, SeekOrigin.Begin); - BaseStream.Write(Data, 0, (int)Size); - - return 0; - } - - public long Flush(ServiceCtx Context) - { - BaseStream.Flush(); - - return 0; - } - - public long SetSize(ServiceCtx Context) - { - long Size = Context.RequestData.ReadInt64(); - - BaseStream.SetLength(Size); - - return 0; - } - - public long GetSize(ServiceCtx Context) - { - Context.ResponseData.Write(BaseStream.Length); - - return 0; - } - - public void Dispose() - { - Dispose(true); - } - - protected virtual void Dispose(bool disposing) - { - if (disposing && BaseStream != null) - { - BaseStream.Dispose(); - - Disposed?.Invoke(this, EventArgs.Empty); - } - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/FspSrv/IFileSystem.cs b/Ryujinx.HLE/OsHle/Services/FspSrv/IFileSystem.cs deleted file mode 100644 index 61c6d115..00000000 --- a/Ryujinx.HLE/OsHle/Services/FspSrv/IFileSystem.cs +++ /dev/null @@ -1,412 +0,0 @@ -using Ryujinx.HLE.OsHle.Ipc; -using System; -using System.Collections.Generic; -using System.IO; -using System.Text; - -using static Ryujinx.HLE.OsHle.ErrorCode; - -namespace Ryujinx.HLE.OsHle.Services.FspSrv -{ - class IFileSystem : IpcService - { - private Dictionary m_Commands; - - public override IReadOnlyDictionary Commands => m_Commands; - - private HashSet OpenPaths; - - private string Path; - - public IFileSystem(string Path) - { - m_Commands = new Dictionary() - { - { 0, CreateFile }, - { 1, DeleteFile }, - { 2, CreateDirectory }, - { 3, DeleteDirectory }, - { 4, DeleteDirectoryRecursively }, - { 5, RenameFile }, - { 6, RenameDirectory }, - { 7, GetEntryType }, - { 8, OpenFile }, - { 9, OpenDirectory }, - { 10, Commit }, - { 11, GetFreeSpaceSize }, - { 12, GetTotalSpaceSize }, - { 13, CleanDirectoryRecursively }, - //{ 14, GetFileTimeStampRaw } - }; - - OpenPaths = new HashSet(); - - this.Path = Path; - } - - public long CreateFile(ServiceCtx Context) - { - string Name = ReadUtf8String(Context); - - long Mode = Context.RequestData.ReadInt64(); - int Size = Context.RequestData.ReadInt32(); - - string FileName = Context.Ns.VFs.GetFullPath(Path, Name); - - if (FileName == null) - { - return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist); - } - - if (File.Exists(FileName)) - { - return MakeError(ErrorModule.Fs, FsErr.PathAlreadyExists); - } - - if (IsPathAlreadyInUse(FileName)) - { - return MakeError(ErrorModule.Fs, FsErr.PathAlreadyInUse); - } - - using (FileStream NewFile = File.Create(FileName)) - { - NewFile.SetLength(Size); - } - - return 0; - } - - public long DeleteFile(ServiceCtx Context) - { - string Name = ReadUtf8String(Context); - - string FileName = Context.Ns.VFs.GetFullPath(Path, Name); - - if (!File.Exists(FileName)) - { - return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist); - } - - if (IsPathAlreadyInUse(FileName)) - { - return MakeError(ErrorModule.Fs, FsErr.PathAlreadyInUse); - } - - File.Delete(FileName); - - return 0; - } - - public long CreateDirectory(ServiceCtx Context) - { - string Name = ReadUtf8String(Context); - - string DirName = Context.Ns.VFs.GetFullPath(Path, Name); - - if (DirName == null) - { - return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist); - } - - if (Directory.Exists(DirName)) - { - return MakeError(ErrorModule.Fs, FsErr.PathAlreadyExists); - } - - if (IsPathAlreadyInUse(DirName)) - { - return MakeError(ErrorModule.Fs, FsErr.PathAlreadyInUse); - } - - Directory.CreateDirectory(DirName); - - return 0; - } - - public long DeleteDirectory(ServiceCtx Context) - { - return DeleteDirectory(Context, false); - } - - public long DeleteDirectoryRecursively(ServiceCtx Context) - { - return DeleteDirectory(Context, true); - } - - private long DeleteDirectory(ServiceCtx Context, bool Recursive) - { - string Name = ReadUtf8String(Context); - - string DirName = Context.Ns.VFs.GetFullPath(Path, Name); - - if (!Directory.Exists(DirName)) - { - return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist); - } - - if (IsPathAlreadyInUse(DirName)) - { - return MakeError(ErrorModule.Fs, FsErr.PathAlreadyInUse); - } - - Directory.Delete(DirName, Recursive); - - return 0; - } - - public long RenameFile(ServiceCtx Context) - { - string OldName = ReadUtf8String(Context, 0); - string NewName = ReadUtf8String(Context, 1); - - string OldFileName = Context.Ns.VFs.GetFullPath(Path, OldName); - string NewFileName = Context.Ns.VFs.GetFullPath(Path, NewName); - - if (!File.Exists(OldFileName)) - { - return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist); - } - - if (File.Exists(NewFileName)) - { - return MakeError(ErrorModule.Fs, FsErr.PathAlreadyExists); - } - - if (IsPathAlreadyInUse(OldFileName)) - { - return MakeError(ErrorModule.Fs, FsErr.PathAlreadyInUse); - } - - File.Move(OldFileName, NewFileName); - - return 0; - } - - public long RenameDirectory(ServiceCtx Context) - { - string OldName = ReadUtf8String(Context, 0); - string NewName = ReadUtf8String(Context, 1); - - string OldDirName = Context.Ns.VFs.GetFullPath(Path, OldName); - string NewDirName = Context.Ns.VFs.GetFullPath(Path, NewName); - - if (!Directory.Exists(OldDirName)) - { - return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist); - } - - if (Directory.Exists(NewDirName)) - { - return MakeError(ErrorModule.Fs, FsErr.PathAlreadyExists); - } - - if (IsPathAlreadyInUse(OldDirName)) - { - return MakeError(ErrorModule.Fs, FsErr.PathAlreadyInUse); - } - - Directory.Move(OldDirName, NewDirName); - - return 0; - } - - public long GetEntryType(ServiceCtx Context) - { - string Name = ReadUtf8String(Context); - - string FileName = Context.Ns.VFs.GetFullPath(Path, Name); - - if (File.Exists(FileName)) - { - Context.ResponseData.Write(1); - } - else if (Directory.Exists(FileName)) - { - Context.ResponseData.Write(0); - } - else - { - Context.ResponseData.Write(0); - - return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist); - } - - return 0; - } - - public long OpenFile(ServiceCtx Context) - { - int FilterFlags = Context.RequestData.ReadInt32(); - - string Name = ReadUtf8String(Context); - - string FileName = Context.Ns.VFs.GetFullPath(Path, Name); - - if (!File.Exists(FileName)) - { - return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist); - } - - if (IsPathAlreadyInUse(FileName)) - { - return MakeError(ErrorModule.Fs, FsErr.PathAlreadyInUse); - } - - FileStream Stream = new FileStream(FileName, FileMode.Open); - - IFile FileInterface = new IFile(Stream, FileName); - - FileInterface.Disposed += RemoveFileInUse; - - lock (OpenPaths) - { - OpenPaths.Add(FileName); - } - - MakeObject(Context, FileInterface); - - return 0; - } - - public long OpenDirectory(ServiceCtx Context) - { - int FilterFlags = Context.RequestData.ReadInt32(); - - string Name = ReadUtf8String(Context); - - string DirName = Context.Ns.VFs.GetFullPath(Path, Name); - - if (!Directory.Exists(DirName)) - { - return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist); - } - - if (IsPathAlreadyInUse(DirName)) - { - return MakeError(ErrorModule.Fs, FsErr.PathAlreadyInUse); - } - - IDirectory DirInterface = new IDirectory(DirName, FilterFlags); - - DirInterface.Disposed += RemoveDirectoryInUse; - - lock (OpenPaths) - { - OpenPaths.Add(DirName); - } - - MakeObject(Context, DirInterface); - - return 0; - } - - public long Commit(ServiceCtx Context) - { - return 0; - } - - public long GetFreeSpaceSize(ServiceCtx Context) - { - string Name = ReadUtf8String(Context); - - Context.ResponseData.Write(Context.Ns.VFs.GetDrive().AvailableFreeSpace); - - return 0; - } - - public long GetTotalSpaceSize(ServiceCtx Context) - { - string Name = ReadUtf8String(Context); - - Context.ResponseData.Write(Context.Ns.VFs.GetDrive().TotalSize); - - return 0; - } - - public long CleanDirectoryRecursively(ServiceCtx Context) - { - string Name = ReadUtf8String(Context); - - string DirName = Context.Ns.VFs.GetFullPath(Path, Name); - - if (!Directory.Exists(DirName)) - { - return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist); - } - - if (IsPathAlreadyInUse(DirName)) - { - return MakeError(ErrorModule.Fs, FsErr.PathAlreadyInUse); - } - - foreach (string Entry in Directory.EnumerateFileSystemEntries(DirName)) - { - if (Directory.Exists(Entry)) - { - Directory.Delete(Entry, true); - } - else if (File.Exists(Entry)) - { - File.Delete(Entry); - } - } - - return 0; - } - - private bool IsPathAlreadyInUse(string Path) - { - lock (OpenPaths) - { - return OpenPaths.Contains(Path); - } - } - - private void RemoveFileInUse(object sender, EventArgs e) - { - IFile FileInterface = (IFile)sender; - - lock (OpenPaths) - { - FileInterface.Disposed -= RemoveFileInUse; - - OpenPaths.Remove(FileInterface.HostPath); - } - } - - private void RemoveDirectoryInUse(object sender, EventArgs e) - { - IDirectory DirInterface = (IDirectory)sender; - - lock (OpenPaths) - { - DirInterface.Disposed -= RemoveDirectoryInUse; - - OpenPaths.Remove(DirInterface.HostPath); - } - } - - private string ReadUtf8String(ServiceCtx Context, int Index = 0) - { - long Position = Context.Request.PtrBuff[Index].Position; - long Size = Context.Request.PtrBuff[Index].Size; - - using (MemoryStream MS = new MemoryStream()) - { - while (Size-- > 0) - { - byte Value = Context.Memory.ReadByte(Position++); - - if (Value == 0) - { - break; - } - - MS.WriteByte(Value); - } - - return Encoding.UTF8.GetString(MS.ToArray()); - } - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/FspSrv/IFileSystemProxy.cs b/Ryujinx.HLE/OsHle/Services/FspSrv/IFileSystemProxy.cs deleted file mode 100644 index 84a0bc3d..00000000 --- a/Ryujinx.HLE/OsHle/Services/FspSrv/IFileSystemProxy.cs +++ /dev/null @@ -1,74 +0,0 @@ -using Ryujinx.HLE.Logging; -using Ryujinx.HLE.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.HLE.OsHle.Services.FspSrv -{ - class IFileSystemProxy : IpcService - { - private Dictionary m_Commands; - - public override IReadOnlyDictionary Commands => m_Commands; - - public IFileSystemProxy() - { - m_Commands = new Dictionary() - { - { 1, SetCurrentProcess }, - { 18, OpenSdCardFileSystem }, - { 22, CreateSaveDataFileSystem }, - { 51, OpenSaveDataFileSystem }, - { 200, OpenDataStorageByCurrentProcess }, - { 203, OpenPatchDataStorageByCurrentProcess }, - { 1005, GetGlobalAccessLogMode } - }; - } - - public long SetCurrentProcess(ServiceCtx Context) - { - return 0; - } - - public long OpenSdCardFileSystem(ServiceCtx Context) - { - MakeObject(Context, new IFileSystem(Context.Ns.VFs.GetSdCardPath())); - - return 0; - } - - public long CreateSaveDataFileSystem(ServiceCtx Context) - { - Context.Ns.Log.PrintStub(LogClass.ServiceFs, "Stubbed."); - - return 0; - } - - public long OpenSaveDataFileSystem(ServiceCtx Context) - { - MakeObject(Context, new IFileSystem(Context.Ns.VFs.GetGameSavesPath())); - - return 0; - } - - public long OpenDataStorageByCurrentProcess(ServiceCtx Context) - { - MakeObject(Context, new IStorage(Context.Ns.VFs.RomFs)); - - return 0; - } - - public long OpenPatchDataStorageByCurrentProcess(ServiceCtx Context) - { - MakeObject(Context, new IStorage(Context.Ns.VFs.RomFs)); - - return 0; - } - - public long GetGlobalAccessLogMode(ServiceCtx Context) - { - Context.ResponseData.Write(0); - - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/FspSrv/IStorage.cs b/Ryujinx.HLE/OsHle/Services/FspSrv/IStorage.cs deleted file mode 100644 index 56c27d03..00000000 --- a/Ryujinx.HLE/OsHle/Services/FspSrv/IStorage.cs +++ /dev/null @@ -1,51 +0,0 @@ -using Ryujinx.HLE.OsHle.Ipc; -using System.Collections.Generic; -using System.IO; - -namespace Ryujinx.HLE.OsHle.Services.FspSrv -{ - class IStorage : IpcService - { - private Dictionary m_Commands; - - public override IReadOnlyDictionary Commands => m_Commands; - - private Stream BaseStream; - - public IStorage(Stream BaseStream) - { - m_Commands = new Dictionary() - { - { 0, Read } - }; - - this.BaseStream = BaseStream; - } - - public long Read(ServiceCtx Context) - { - long Offset = Context.RequestData.ReadInt64(); - long Size = Context.RequestData.ReadInt64(); - - if (Context.Request.ReceiveBuff.Count > 0) - { - IpcBuffDesc BuffDesc = Context.Request.ReceiveBuff[0]; - - //Use smaller length to avoid overflows. - if (Size > BuffDesc.Size) - { - Size = BuffDesc.Size; - } - - byte[] Data = new byte[Size]; - - BaseStream.Seek(Offset, SeekOrigin.Begin); - BaseStream.Read(Data, 0, Data.Length); - - Context.Memory.WriteBytes(BuffDesc.Position, Data); - } - - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Hid/IActiveVibrationDeviceList.cs b/Ryujinx.HLE/OsHle/Services/Hid/IActiveVibrationDeviceList.cs deleted file mode 100644 index 12eaf706..00000000 --- a/Ryujinx.HLE/OsHle/Services/Hid/IActiveVibrationDeviceList.cs +++ /dev/null @@ -1,27 +0,0 @@ -using Ryujinx.HLE.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.HLE.OsHle.Services.Hid -{ - class IActiveApplicationDeviceList : IpcService - { - private Dictionary m_Commands; - - public override IReadOnlyDictionary Commands => m_Commands; - - public IActiveApplicationDeviceList() - { - m_Commands = new Dictionary() - { - { 0, ActivateVibrationDevice } - }; - } - - public long ActivateVibrationDevice(ServiceCtx Context) - { - int VibrationDeviceHandle = Context.RequestData.ReadInt32(); - - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Hid/IAppletResource.cs b/Ryujinx.HLE/OsHle/Services/Hid/IAppletResource.cs deleted file mode 100644 index 5c32ca83..00000000 --- a/Ryujinx.HLE/OsHle/Services/Hid/IAppletResource.cs +++ /dev/null @@ -1,34 +0,0 @@ -using Ryujinx.HLE.OsHle.Handles; -using Ryujinx.HLE.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.HLE.OsHle.Services.Hid -{ - class IAppletResource : IpcService - { - private Dictionary m_Commands; - - public override IReadOnlyDictionary Commands => m_Commands; - - private KSharedMemory HidSharedMem; - - public IAppletResource(KSharedMemory HidSharedMem) - { - m_Commands = new Dictionary() - { - { 0, GetSharedMemoryHandle } - }; - - this.HidSharedMem = HidSharedMem; - } - - public long GetSharedMemoryHandle(ServiceCtx Context) - { - int Handle = Context.Process.HandleTable.OpenHandle(HidSharedMem); - - Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle); - - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Hid/IHidServer.cs b/Ryujinx.HLE/OsHle/Services/Hid/IHidServer.cs deleted file mode 100644 index f23164ce..00000000 --- a/Ryujinx.HLE/OsHle/Services/Hid/IHidServer.cs +++ /dev/null @@ -1,299 +0,0 @@ -using Ryujinx.HLE.Input; -using Ryujinx.HLE.Logging; -using Ryujinx.HLE.OsHle.Ipc; -using Ryujinx.HLE.OsHle.Handles; -using System; -using System.Collections.Generic; - -namespace Ryujinx.HLE.OsHle.Services.Hid -{ - class IHidServer : IpcService, IDisposable - { - private Dictionary m_Commands; - - private KEvent NpadStyleSetUpdateEvent; - - public override IReadOnlyDictionary Commands => m_Commands; - - public IHidServer() - { - m_Commands = new Dictionary() - { - { 0, CreateAppletResource }, - { 1, ActivateDebugPad }, - { 11, ActivateTouchScreen }, - { 21, ActivateMouse }, - { 31, ActivateKeyboard }, - { 66, StartSixAxisSensor }, - { 79, SetGyroscopeZeroDriftMode }, - { 100, SetSupportedNpadStyleSet }, - { 101, GetSupportedNpadStyleSet }, - { 102, SetSupportedNpadIdType }, - { 103, ActivateNpad }, - { 106, AcquireNpadStyleSetUpdateEventHandle }, - { 108, GetPlayerLedPattern }, - { 120, SetNpadJoyHoldType }, - { 121, GetNpadJoyHoldType }, - { 122, SetNpadJoyAssignmentModeSingleByDefault }, - { 123, SetNpadJoyAssignmentModeSingle }, - { 124, SetNpadJoyAssignmentModeDual }, - { 125, MergeSingleJoyAsDualJoy }, - { 128, SetNpadHandheldActivationMode }, - { 200, GetVibrationDeviceInfo }, - { 201, SendVibrationValue }, - { 203, CreateActiveVibrationDeviceList }, - { 206, SendVibrationValues } - }; - - NpadStyleSetUpdateEvent = new KEvent(); - } - - public long CreateAppletResource(ServiceCtx Context) - { - MakeObject(Context, new IAppletResource(Context.Ns.Os.HidSharedMem)); - - return 0; - } - - public long ActivateDebugPad(ServiceCtx Context) - { - Context.Ns.Log.PrintStub(LogClass.ServiceHid, "Stubbed."); - - return 0; - } - - public long ActivateTouchScreen(ServiceCtx Context) - { - long AppletResourceUserId = Context.RequestData.ReadInt64(); - - Context.Ns.Log.PrintStub(LogClass.ServiceHid, "Stubbed."); - - return 0; - } - - public long ActivateMouse(ServiceCtx Context) - { - long AppletResourceUserId = Context.RequestData.ReadInt64(); - - Context.Ns.Log.PrintStub(LogClass.ServiceHid, "Stubbed."); - - return 0; - } - - public long ActivateKeyboard(ServiceCtx Context) - { - long AppletResourceUserId = Context.RequestData.ReadInt64(); - - Context.Ns.Log.PrintStub(LogClass.ServiceHid, "Stubbed."); - - return 0; - } - - public long StartSixAxisSensor(ServiceCtx Context) - { - int Handle = Context.RequestData.ReadInt32(); - - long AppletResourceUserId = Context.RequestData.ReadInt64(); - - Context.Ns.Log.PrintStub(LogClass.ServiceHid, "Stubbed."); - - return 0; - } - - public long SetGyroscopeZeroDriftMode(ServiceCtx Context) - { - int Handle = Context.RequestData.ReadInt32(); - int Unknown = Context.RequestData.ReadInt32(); - long AppletResourceUserId = Context.RequestData.ReadInt64(); - - Context.Ns.Log.PrintStub(LogClass.ServiceHid, "Stubbed."); - - return 0; - } - - public long AcquireNpadStyleSetUpdateEventHandle(ServiceCtx Context) - { - int Handle = Context.Process.HandleTable.OpenHandle(NpadStyleSetUpdateEvent); - - Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle); - - return 0; - } - - public long GetSupportedNpadStyleSet(ServiceCtx Context) - { - Context.ResponseData.Write(0); - - Context.Ns.Log.PrintStub(LogClass.ServiceHid, "Stubbed."); - - return 0; - } - - public long SetSupportedNpadStyleSet(ServiceCtx Context) - { - long Unknown0 = Context.RequestData.ReadInt64(); - long Unknown8 = Context.RequestData.ReadInt64(); - - Context.Ns.Log.PrintStub(LogClass.ServiceHid, "Stubbed."); - - return 0; - } - - public long SetSupportedNpadIdType(ServiceCtx Context) - { - long Unknown = Context.RequestData.ReadInt64(); - - Context.Ns.Log.PrintStub(LogClass.ServiceHid, "Stubbed."); - - return 0; - } - - public long ActivateNpad(ServiceCtx Context) - { - long Unknown = Context.RequestData.ReadInt64(); - - Context.Ns.Log.PrintStub(LogClass.ServiceHid, "Stubbed."); - - return 0; - } - - public long GetPlayerLedPattern(ServiceCtx Context) - { - long Unknown = Context.RequestData.ReadInt32(); - - Context.ResponseData.Write(0L); - - Context.Ns.Log.PrintStub(LogClass.ServiceHid, "Stubbed."); - - return 0; - } - - public long SetNpadJoyHoldType(ServiceCtx Context) - { - long Unknown0 = Context.RequestData.ReadInt64(); - long Unknown8 = Context.RequestData.ReadInt64(); - - Context.Ns.Log.PrintStub(LogClass.ServiceHid, "Stubbed."); - - return 0; - } - - public long GetNpadJoyHoldType(ServiceCtx Context) - { - Context.ResponseData.Write(0L); - - Context.Ns.Log.PrintStub(LogClass.ServiceHid, "Stubbed."); - - return 0; - } - - public long SetNpadJoyAssignmentModeSingleByDefault(ServiceCtx Context) - { - HidControllerId HidControllerId = (HidControllerId)Context.RequestData.ReadInt32(); - - long AppletUserResourceId = Context.RequestData.ReadInt64(); - - Context.Ns.Log.PrintStub(LogClass.ServiceHid, "Stubbed."); - - return 0; - } - - public long SetNpadJoyAssignmentModeSingle(ServiceCtx Context) - { - HidControllerId HidControllerId = (HidControllerId)Context.RequestData.ReadInt32(); - - long AppletUserResourceId = Context.RequestData.ReadInt64(); - long NpadJoyDeviceType = Context.RequestData.ReadInt64(); - - Context.Ns.Log.PrintStub(LogClass.ServiceHid, "Stubbed."); - - return 0; - } - - public long SetNpadJoyAssignmentModeDual(ServiceCtx Context) - { - HidControllerId HidControllerId = (HidControllerId)Context.RequestData.ReadInt32(); - - long AppletUserResourceId = Context.RequestData.ReadInt64(); - - Context.Ns.Log.PrintStub(LogClass.ServiceHid, "Stubbed."); - - return 0; - } - - public long MergeSingleJoyAsDualJoy(ServiceCtx Context) - { - long Unknown0 = Context.RequestData.ReadInt32(); - long Unknown8 = Context.RequestData.ReadInt32(); - long AppletUserResourceId = Context.RequestData.ReadInt64(); - - Context.Ns.Log.PrintStub(LogClass.ServiceHid, "Stubbed."); - - return 0; - } - - public long SetNpadHandheldActivationMode(ServiceCtx Context) - { - long AppletUserResourceId = Context.RequestData.ReadInt64(); - long Unknown = Context.RequestData.ReadInt64(); - - Context.Ns.Log.PrintStub(LogClass.ServiceHid, "Stubbed."); - - return 0; - } - - public long GetVibrationDeviceInfo(ServiceCtx Context) - { - int VibrationDeviceHandle = Context.RequestData.ReadInt32(); - - Context.Ns.Log.PrintStub(LogClass.ServiceHid, "Stubbed."); - - Context.ResponseData.Write(0L); //VibrationDeviceInfoForIpc - - return 0; - } - - public long SendVibrationValue(ServiceCtx Context) - { - int VibrationDeviceHandle = Context.RequestData.ReadInt32(); - - int VibrationValue1 = Context.RequestData.ReadInt32(); - int VibrationValue2 = Context.RequestData.ReadInt32(); - int VibrationValue3 = Context.RequestData.ReadInt32(); - int VibrationValue4 = Context.RequestData.ReadInt32(); - - long AppletUserResourceId = Context.RequestData.ReadInt64(); - - Context.Ns.Log.PrintStub(LogClass.ServiceHid, "Stubbed."); - - return 0; - } - - public long CreateActiveVibrationDeviceList(ServiceCtx Context) - { - MakeObject(Context, new IActiveApplicationDeviceList()); - - return 0; - } - - public long SendVibrationValues(ServiceCtx Context) - { - Context.Ns.Log.PrintStub(LogClass.ServiceHid, "Stubbed."); - - return 0; - } - - public void Dispose() - { - Dispose(true); - } - - protected virtual void Dispose(bool Disposing) - { - if (Disposing) - { - NpadStyleSetUpdateEvent.Dispose(); - } - } - } -} diff --git a/Ryujinx.HLE/OsHle/Services/IIpcService.cs b/Ryujinx.HLE/OsHle/Services/IIpcService.cs deleted file mode 100644 index 60675380..00000000 --- a/Ryujinx.HLE/OsHle/Services/IIpcService.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Ryujinx.HLE.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.HLE.OsHle.Services -{ - interface IIpcService - { - IReadOnlyDictionary Commands { get; } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/IpcService.cs b/Ryujinx.HLE/OsHle/Services/IpcService.cs deleted file mode 100644 index 3c1a136f..00000000 --- a/Ryujinx.HLE/OsHle/Services/IpcService.cs +++ /dev/null @@ -1,183 +0,0 @@ -using Ryujinx.HLE.Logging; -using Ryujinx.HLE.OsHle.Handles; -using Ryujinx.HLE.OsHle.Ipc; -using System; -using System.Collections.Generic; -using System.IO; - -namespace Ryujinx.HLE.OsHle.Services -{ - abstract class IpcService : IIpcService - { - public abstract IReadOnlyDictionary Commands { get; } - - private IdDictionary DomainObjects; - - private int SelfId; - - private bool IsDomain; - - public IpcService() - { - DomainObjects = new IdDictionary(); - - SelfId = -1; - } - - public int ConvertToDomain() - { - if (SelfId == -1) - { - SelfId = DomainObjects.Add(this); - } - - IsDomain = true; - - return SelfId; - } - - public void ConvertToSession() - { - IsDomain = false; - } - - public void CallMethod(ServiceCtx Context) - { - IIpcService Service = this; - - if (IsDomain) - { - int DomainWord0 = Context.RequestData.ReadInt32(); - int DomainObjId = Context.RequestData.ReadInt32(); - - int DomainCmd = (DomainWord0 >> 0) & 0xff; - int InputObjCount = (DomainWord0 >> 8) & 0xff; - int DataPayloadSize = (DomainWord0 >> 16) & 0xffff; - - Context.RequestData.BaseStream.Seek(0x10 + DataPayloadSize, SeekOrigin.Begin); - - for (int Index = 0; Index < InputObjCount; Index++) - { - Context.Request.ObjectIds.Add(Context.RequestData.ReadInt32()); - } - - Context.RequestData.BaseStream.Seek(0x10, SeekOrigin.Begin); - - if (DomainCmd == 1) - { - Service = GetObject(DomainObjId); - - Context.ResponseData.Write(0L); - Context.ResponseData.Write(0L); - } - else if (DomainCmd == 2) - { - Delete(DomainObjId); - - Context.ResponseData.Write(0L); - - return; - } - else - { - throw new NotImplementedException($"Domain command: {DomainCmd}"); - } - } - - long SfciMagic = Context.RequestData.ReadInt64(); - int CommandId = (int)Context.RequestData.ReadInt64(); - - if (Service.Commands.TryGetValue(CommandId, out ServiceProcessRequest ProcessRequest)) - { - Context.ResponseData.BaseStream.Seek(IsDomain ? 0x20 : 0x10, SeekOrigin.Begin); - - Context.Ns.Log.PrintDebug(LogClass.KernelIpc, $"{Service.GetType().Name}: {ProcessRequest.Method.Name}"); - - long Result = ProcessRequest(Context); - - if (IsDomain) - { - foreach (int Id in Context.Response.ObjectIds) - { - Context.ResponseData.Write(Id); - } - - Context.ResponseData.BaseStream.Seek(0, SeekOrigin.Begin); - - Context.ResponseData.Write(Context.Response.ObjectIds.Count); - } - - Context.ResponseData.BaseStream.Seek(IsDomain ? 0x10 : 0, SeekOrigin.Begin); - - Context.ResponseData.Write(IpcMagic.Sfco); - Context.ResponseData.Write(Result); - } - else - { - string DbgMessage = $"{Context.Session.ServiceName} {Service.GetType().Name}: {CommandId}"; - - throw new NotImplementedException(DbgMessage); - } - } - - protected static void MakeObject(ServiceCtx Context, IpcService Obj) - { - IpcService Service = Context.Session.Service; - - if (Service.IsDomain) - { - Context.Response.ObjectIds.Add(Service.Add(Obj)); - } - else - { - KSession Session = new KSession(Obj, Context.Session.ServiceName); - - int Handle = Context.Process.HandleTable.OpenHandle(Session); - - Context.Response.HandleDesc = IpcHandleDesc.MakeMove(Handle); - } - } - - protected static T GetObject(ServiceCtx Context, int Index) where T : IpcService - { - IpcService Service = Context.Session.Service; - - if (!Service.IsDomain) - { - int Handle = Context.Request.HandleDesc.ToMove[Index]; - - KSession Session = Context.Process.HandleTable.GetData(Handle); - - return Session?.Service is T ? (T)Session.Service : null; - } - - int ObjId = Context.Request.ObjectIds[Index]; - - IIpcService Obj = Service.GetObject(ObjId); - - return Obj is T ? (T)Obj : null; - } - - private int Add(IIpcService Obj) - { - return DomainObjects.Add(Obj); - } - - private bool Delete(int Id) - { - object Obj = DomainObjects.Delete(Id); - - if (Obj is IDisposable DisposableObj) - { - DisposableObj.Dispose(); - } - - return Obj != null; - } - - private IIpcService GetObject(int Id) - { - return DomainObjects.GetData(Id); - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Lm/ILogService.cs b/Ryujinx.HLE/OsHle/Services/Lm/ILogService.cs deleted file mode 100644 index c3aeb184..00000000 --- a/Ryujinx.HLE/OsHle/Services/Lm/ILogService.cs +++ /dev/null @@ -1,27 +0,0 @@ -using Ryujinx.HLE.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.HLE.OsHle.Services.Lm -{ - class ILogService : IpcService - { - private Dictionary m_Commands; - - public override IReadOnlyDictionary Commands => m_Commands; - - public ILogService() - { - m_Commands = new Dictionary() - { - { 0, Initialize } - }; - } - - public long Initialize(ServiceCtx Context) - { - MakeObject(Context, new ILogger()); - - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Lm/ILogger.cs b/Ryujinx.HLE/OsHle/Services/Lm/ILogger.cs deleted file mode 100644 index 90edf2ad..00000000 --- a/Ryujinx.HLE/OsHle/Services/Lm/ILogger.cs +++ /dev/null @@ -1,86 +0,0 @@ -using Ryujinx.HLE.Logging; -using Ryujinx.HLE.OsHle.Ipc; -using System.Collections.Generic; -using System.IO; -using System.Text; - -namespace Ryujinx.HLE.OsHle.Services.Lm -{ - class ILogger : IpcService - { - private Dictionary m_Commands; - - public override IReadOnlyDictionary Commands => m_Commands; - - public ILogger() - { - m_Commands = new Dictionary() - { - { 0, Log } - }; - } - - public long Log(ServiceCtx Context) - { - byte[] LogBuffer = Context.Memory.ReadBytes( - Context.Request.PtrBuff[0].Position, - Context.Request.PtrBuff[0].Size); - - using (MemoryStream MS = new MemoryStream(LogBuffer)) - { - BinaryReader Reader = new BinaryReader(MS); - - long Pid = Reader.ReadInt64(); - long ThreadContext = Reader.ReadInt64(); - short Flags = Reader.ReadInt16(); - byte Level = Reader.ReadByte(); - byte Verbosity = Reader.ReadByte(); - int PayloadLength = Reader.ReadInt32(); - - StringBuilder SB = new StringBuilder(); - - SB.AppendLine("Guest log:"); - - while (MS.Position < MS.Length) - { - byte Type = Reader.ReadByte(); - byte Size = Reader.ReadByte(); - - LmLogField Field = (LmLogField)Type; - - string FieldStr = string.Empty; - - if (Field == LmLogField.Skip) - { - Reader.ReadByte(); - - continue; - } - else if (Field == LmLogField.Line) - { - FieldStr = Field + ": " + Reader.ReadInt32(); - } - else - { - FieldStr = Field + ": \"" + Encoding.UTF8.GetString(Reader.ReadBytes(Size)) + "\""; - } - - SB.AppendLine(" " + FieldStr); - } - - string Text = SB.ToString(); - - switch((LmLogLevel)Level) - { - case LmLogLevel.Trace: Context.Ns.Log.PrintDebug (LogClass.ServiceLm, Text); break; - case LmLogLevel.Info: Context.Ns.Log.PrintInfo (LogClass.ServiceLm, Text); break; - case LmLogLevel.Warning: Context.Ns.Log.PrintWarning(LogClass.ServiceLm, Text); break; - case LmLogLevel.Error: Context.Ns.Log.PrintError (LogClass.ServiceLm, Text); break; - case LmLogLevel.Critical: Context.Ns.Log.PrintError (LogClass.ServiceLm, Text); break; - } - } - - return 0; - } - } -} diff --git a/Ryujinx.HLE/OsHle/Services/Lm/LmLogField.cs b/Ryujinx.HLE/OsHle/Services/Lm/LmLogField.cs deleted file mode 100644 index 33593103..00000000 --- a/Ryujinx.HLE/OsHle/Services/Lm/LmLogField.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace Ryujinx.HLE.OsHle.Services.Lm -{ - enum LmLogField - { - Skip = 1, - Message = 2, - Line = 3, - Filename = 4, - Function = 5, - Module = 6, - Thread = 7 - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Lm/LmLogLevel.cs b/Ryujinx.HLE/OsHle/Services/Lm/LmLogLevel.cs deleted file mode 100644 index d051a595..00000000 --- a/Ryujinx.HLE/OsHle/Services/Lm/LmLogLevel.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace Ryujinx.HLE.OsHle.Services.Lm -{ - enum LmLogLevel - { - Trace, - Info, - Warning, - Error, - Critical - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Mm/IRequest.cs b/Ryujinx.HLE/OsHle/Services/Mm/IRequest.cs deleted file mode 100644 index c60b7f52..00000000 --- a/Ryujinx.HLE/OsHle/Services/Mm/IRequest.cs +++ /dev/null @@ -1,46 +0,0 @@ -using Ryujinx.HLE.Logging; -using Ryujinx.HLE.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.HLE.OsHle.Services.Mm -{ - class IRequest : IpcService - { - private Dictionary m_Commands; - - public override IReadOnlyDictionary Commands => m_Commands; - - public IRequest() - { - m_Commands = new Dictionary() - { - { 4, Initialize }, - { 6, SetAndWait }, - { 7, Get } - }; - } - - public long Initialize(ServiceCtx Context) - { - Context.Ns.Log.PrintStub(LogClass.ServiceMm, "Stubbed."); - - return 0; - } - - public long SetAndWait(ServiceCtx Context) - { - Context.Ns.Log.PrintStub(LogClass.ServiceMm, "Stubbed."); - - return 0; - } - - public long Get(ServiceCtx Context) - { - Context.ResponseData.Write(0); - - Context.Ns.Log.PrintStub(LogClass.ServiceMm, "Stubbed."); - - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Nfp/DeviceState.cs b/Ryujinx.HLE/OsHle/Services/Nfp/DeviceState.cs deleted file mode 100644 index 1863e0d9..00000000 --- a/Ryujinx.HLE/OsHle/Services/Nfp/DeviceState.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Ryujinx.HLE.OsHle.Services.Nfp -{ - enum DeviceState - { - Initialized = 0 - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Nfp/IUser.cs b/Ryujinx.HLE/OsHle/Services/Nfp/IUser.cs deleted file mode 100644 index 4b423ba7..00000000 --- a/Ryujinx.HLE/OsHle/Services/Nfp/IUser.cs +++ /dev/null @@ -1,114 +0,0 @@ -using Ryujinx.HLE.Input; -using Ryujinx.HLE.Logging; -using Ryujinx.HLE.OsHle.Handles; -using Ryujinx.HLE.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.HLE.OsHle.Services.Nfp -{ - class IUser : IpcService - { - private Dictionary m_Commands; - - public override IReadOnlyDictionary Commands => m_Commands; - - private const HidControllerId NpadId = HidControllerId.CONTROLLER_PLAYER_1; - - private State State = State.NonInitialized; - - private DeviceState DeviceState = DeviceState.Initialized; - - private KEvent ActivateEvent; - - private KEvent DeactivateEvent; - - private KEvent AvailabilityChangeEvent; - - public IUser() - { - m_Commands = new Dictionary() - { - { 0, Initialize }, - { 17, AttachActivateEvent }, - { 18, AttachDeactivateEvent }, - { 19, GetState }, - { 20, GetDeviceState }, - { 21, GetNpadId }, - { 23, AttachAvailabilityChangeEvent } - }; - - ActivateEvent = new KEvent(); - DeactivateEvent = new KEvent(); - AvailabilityChangeEvent = new KEvent(); - } - - public long Initialize(ServiceCtx Context) - { - Context.Ns.Log.PrintStub(LogClass.ServiceNfp, "Stubbed."); - - State = State.Initialized; - - return 0; - } - - public long AttachActivateEvent(ServiceCtx Context) - { - Context.Ns.Log.PrintStub(LogClass.ServiceNfp, "Stubbed."); - - int Handle = Context.Process.HandleTable.OpenHandle(ActivateEvent); - - Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle);; - - return 0; - } - - public long AttachDeactivateEvent(ServiceCtx Context) - { - Context.Ns.Log.PrintStub(LogClass.ServiceNfp, "Stubbed."); - - int Handle = Context.Process.HandleTable.OpenHandle(DeactivateEvent); - - Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle); - - return 0; - } - - public long GetState(ServiceCtx Context) - { - Context.ResponseData.Write((int)State); - - Context.Ns.Log.PrintStub(LogClass.ServiceNfp, "Stubbed."); - - return 0; - } - - public long GetDeviceState(ServiceCtx Context) - { - Context.ResponseData.Write((int)DeviceState); - - Context.Ns.Log.PrintStub(LogClass.ServiceNfp, "Stubbed."); - - return 0; - } - - public long GetNpadId(ServiceCtx Context) - { - Context.ResponseData.Write((int)NpadId); - - Context.Ns.Log.PrintStub(LogClass.ServiceNfp, "Stubbed."); - - return 0; - } - - public long AttachAvailabilityChangeEvent(ServiceCtx Context) - { - Context.Ns.Log.PrintStub(LogClass.ServiceNfp, "Stubbed."); - - int Handle = Context.Process.HandleTable.OpenHandle(AvailabilityChangeEvent); - - Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle); - - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Nfp/IUserManager.cs b/Ryujinx.HLE/OsHle/Services/Nfp/IUserManager.cs deleted file mode 100644 index 845ce7cf..00000000 --- a/Ryujinx.HLE/OsHle/Services/Nfp/IUserManager.cs +++ /dev/null @@ -1,27 +0,0 @@ -using Ryujinx.HLE.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.HLE.OsHle.Services.Nfp -{ - class IUserManager : IpcService - { - private Dictionary m_Commands; - - public override IReadOnlyDictionary Commands => m_Commands; - - public IUserManager() - { - m_Commands = new Dictionary() - { - { 0, GetUserInterface } - }; - } - - public long GetUserInterface(ServiceCtx Context) - { - MakeObject(Context, new IUser()); - - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Nfp/State.cs b/Ryujinx.HLE/OsHle/Services/Nfp/State.cs deleted file mode 100644 index c1f0bb1a..00000000 --- a/Ryujinx.HLE/OsHle/Services/Nfp/State.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Ryujinx.HLE.OsHle.Services.Nfp -{ - enum State - { - NonInitialized = 0, - Initialized = 1 - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Nifm/IGeneralService.cs b/Ryujinx.HLE/OsHle/Services/Nifm/IGeneralService.cs deleted file mode 100644 index 83bb9f37..00000000 --- a/Ryujinx.HLE/OsHle/Services/Nifm/IGeneralService.cs +++ /dev/null @@ -1,58 +0,0 @@ -using Ryujinx.HLE.Logging; -using Ryujinx.HLE.OsHle.Ipc; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Net; -using System.Net.Sockets; -using System.Net.NetworkInformation; - -namespace Ryujinx.HLE.OsHle.Services.Nifm -{ - class IGeneralService : IpcService - { - private Dictionary m_Commands; - - public override IReadOnlyDictionary Commands => m_Commands; - - public IGeneralService() - { - m_Commands = new Dictionary() - { - { 4, CreateRequest }, - { 12, GetCurrentIpAddress } - }; - } - - public const int NoInternetConnection = 0x2586e; - - //CreateRequest(i32) - public long CreateRequest(ServiceCtx Context) - { - int Unknown = Context.RequestData.ReadInt32(); - - MakeObject(Context, new IRequest()); - - Context.Ns.Log.PrintStub(LogClass.ServiceNifm, "Stubbed."); - - return 0; - } - - public long GetCurrentIpAddress(ServiceCtx Context) - { - if (!NetworkInterface.GetIsNetworkAvailable()) - { - return NoInternetConnection; - } - - IPHostEntry Host = Dns.GetHostEntry(Dns.GetHostName()); - IPAddress Address = Host.AddressList.FirstOrDefault(A => A.AddressFamily == AddressFamily.InterNetwork); - - Context.ResponseData.Write(BitConverter.ToUInt32(Address.GetAddressBytes())); - - Context.Ns.Log.PrintInfo(LogClass.ServiceNifm, $"Console's local IP is {Address.ToString()}"); - - return 0; - } - } -} diff --git a/Ryujinx.HLE/OsHle/Services/Nifm/IRequest.cs b/Ryujinx.HLE/OsHle/Services/Nifm/IRequest.cs deleted file mode 100644 index 2056187d..00000000 --- a/Ryujinx.HLE/OsHle/Services/Nifm/IRequest.cs +++ /dev/null @@ -1,95 +0,0 @@ -using Ryujinx.HLE.Logging; -using Ryujinx.HLE.OsHle.Handles; -using Ryujinx.HLE.OsHle.Ipc; -using System; -using System.Collections.Generic; - -namespace Ryujinx.HLE.OsHle.Services.Nifm -{ - class IRequest : IpcService, IDisposable - { - private Dictionary m_Commands; - - public override IReadOnlyDictionary Commands => m_Commands; - - private KEvent Event0; - private KEvent Event1; - - public IRequest() - { - m_Commands = new Dictionary() - { - { 0, GetRequestState }, - { 1, GetResult }, - { 2, GetSystemEventReadableHandles }, - { 3, Cancel }, - { 4, Submit }, - { 11, SetConnectionConfirmationOption } - }; - - Event0 = new KEvent(); - Event1 = new KEvent(); - } - - public long GetRequestState(ServiceCtx Context) - { - Context.ResponseData.Write(1); - - Context.Ns.Log.PrintStub(LogClass.ServiceNifm, "Stubbed."); - - return 0; - } - - public long GetResult(ServiceCtx Context) - { - Context.Ns.Log.PrintStub(LogClass.ServiceNifm, "Stubbed."); - - return 0; - } - - public long GetSystemEventReadableHandles(ServiceCtx Context) - { - int Handle0 = Context.Process.HandleTable.OpenHandle(Event0); - int Handle1 = Context.Process.HandleTable.OpenHandle(Event1); - - Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle0, Handle1); - - return 0; - } - - public long Cancel(ServiceCtx Context) - { - Context.Ns.Log.PrintStub(LogClass.ServiceNifm, "Stubbed."); - - return 0; - } - - public long Submit(ServiceCtx Context) - { - Context.Ns.Log.PrintStub(LogClass.ServiceNifm, "Stubbed."); - - return 0; - } - - public long SetConnectionConfirmationOption(ServiceCtx Context) - { - Context.Ns.Log.PrintStub(LogClass.ServiceNifm, "Stubbed."); - - return 0; - } - - public void Dispose() - { - Dispose(true); - } - - protected virtual void Dispose(bool Disposing) - { - if (Disposing) - { - Event0.Dispose(); - Event1.Dispose(); - } - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Nifm/IStaticService.cs b/Ryujinx.HLE/OsHle/Services/Nifm/IStaticService.cs deleted file mode 100644 index c6d773f5..00000000 --- a/Ryujinx.HLE/OsHle/Services/Nifm/IStaticService.cs +++ /dev/null @@ -1,35 +0,0 @@ -using Ryujinx.HLE.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.HLE.OsHle.Services.Nifm -{ - class IStaticService : IpcService - { - private Dictionary m_Commands; - - public override IReadOnlyDictionary Commands => m_Commands; - - public IStaticService() - { - m_Commands = new Dictionary() - { - { 4, CreateGeneralServiceOld }, - { 5, CreateGeneralService } - }; - } - - public long CreateGeneralServiceOld(ServiceCtx Context) - { - MakeObject(Context, new IGeneralService()); - - return 0; - } - - public long CreateGeneralService(ServiceCtx Context) - { - MakeObject(Context, new IGeneralService()); - - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Ns/IAddOnContentManager.cs b/Ryujinx.HLE/OsHle/Services/Ns/IAddOnContentManager.cs deleted file mode 100644 index f3e7146e..00000000 --- a/Ryujinx.HLE/OsHle/Services/Ns/IAddOnContentManager.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Ryujinx.HLE.Logging; -using Ryujinx.HLE.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.HLE.OsHle.Services.Ns -{ - class IAddOnContentManager : IpcService - { - private Dictionary m_Commands; - - public override IReadOnlyDictionary Commands => m_Commands; - - public IAddOnContentManager() - { - m_Commands = new Dictionary() - { - { 2, CountAddOnContent }, - { 3, ListAddOnContent } - }; - } - - public static long CountAddOnContent(ServiceCtx Context) - { - Context.ResponseData.Write(0); - - Context.Ns.Log.PrintStub(LogClass.ServiceNs, "Stubbed."); - - return 0; - } - - public static long ListAddOnContent(ServiceCtx Context) - { - Context.Ns.Log.PrintStub(LogClass.ServiceNs, "Stubbed."); - - //TODO: This is supposed to write a u32 array aswell. - //It's unknown what it contains. - Context.ResponseData.Write(0); - - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Ns/IServiceGetterInterface.cs b/Ryujinx.HLE/OsHle/Services/Ns/IServiceGetterInterface.cs deleted file mode 100644 index 3650f8a4..00000000 --- a/Ryujinx.HLE/OsHle/Services/Ns/IServiceGetterInterface.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Ryujinx.HLE.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.HLE.OsHle.Services.Ns -{ - class IServiceGetterInterface : IpcService - { - private Dictionary m_Commands; - - public override IReadOnlyDictionary Commands => m_Commands; - - public IServiceGetterInterface() - { - m_Commands = new Dictionary() - { - //... - }; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Ns/ISystemUpdateInterface.cs b/Ryujinx.HLE/OsHle/Services/Ns/ISystemUpdateInterface.cs deleted file mode 100644 index adb6add9..00000000 --- a/Ryujinx.HLE/OsHle/Services/Ns/ISystemUpdateInterface.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Ryujinx.HLE.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.HLE.OsHle.Services.Ns -{ - class ISystemUpdateInterface : IpcService - { - private Dictionary m_Commands; - - public override IReadOnlyDictionary Commands => m_Commands; - - public ISystemUpdateInterface() - { - m_Commands = new Dictionary() - { - //... - }; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Ns/IVulnerabilityManagerInterface.cs b/Ryujinx.HLE/OsHle/Services/Ns/IVulnerabilityManagerInterface.cs deleted file mode 100644 index 6a2c3d3b..00000000 --- a/Ryujinx.HLE/OsHle/Services/Ns/IVulnerabilityManagerInterface.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Ryujinx.HLE.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.HLE.OsHle.Services.Ns -{ - class IVulnerabilityManagerInterface : IpcService - { - private Dictionary m_Commands; - - public override IReadOnlyDictionary Commands => m_Commands; - - public IVulnerabilityManagerInterface() - { - m_Commands = new Dictionary() - { - //... - }; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Nv/INvDrvServices.cs b/Ryujinx.HLE/OsHle/Services/Nv/INvDrvServices.cs deleted file mode 100644 index 4654d15f..00000000 --- a/Ryujinx.HLE/OsHle/Services/Nv/INvDrvServices.cs +++ /dev/null @@ -1,231 +0,0 @@ -using ChocolArm64.Memory; -using Ryujinx.HLE.Logging; -using Ryujinx.HLE.OsHle.Handles; -using Ryujinx.HLE.OsHle.Ipc; -using Ryujinx.HLE.OsHle.Services.Nv.NvGpuAS; -using Ryujinx.HLE.OsHle.Services.Nv.NvGpuGpu; -using Ryujinx.HLE.OsHle.Services.Nv.NvHostChannel; -using Ryujinx.HLE.OsHle.Services.Nv.NvHostCtrl; -using Ryujinx.HLE.OsHle.Services.Nv.NvMap; -using System; -using System.Collections.Generic; - -namespace Ryujinx.HLE.OsHle.Services.Nv -{ - class INvDrvServices : IpcService, IDisposable - { - private delegate int IoctlProcessor(ServiceCtx Context, int Cmd); - - private Dictionary m_Commands; - - public override IReadOnlyDictionary Commands => m_Commands; - - private static Dictionary IoctlProcessors = - new Dictionary() - { - { "/dev/nvhost-as-gpu", ProcessIoctlNvGpuAS }, - { "/dev/nvhost-ctrl", ProcessIoctlNvHostCtrl }, - { "/dev/nvhost-ctrl-gpu", ProcessIoctlNvGpuGpu }, - { "/dev/nvhost-gpu", ProcessIoctlNvHostGpu }, - { "/dev/nvmap", ProcessIoctlNvMap } - }; - - public static GlobalStateTable Fds { get; private set; } - - private KEvent Event; - - public INvDrvServices() - { - m_Commands = new Dictionary() - { - { 0, Open }, - { 1, Ioctl }, - { 2, Close }, - { 3, Initialize }, - { 4, QueryEvent }, - { 8, SetClientPid }, - { 11, Ioctl }, - { 13, FinishInitialize } - }; - - Event = new KEvent(); - } - - static INvDrvServices() - { - Fds = new GlobalStateTable(); - } - - public long Open(ServiceCtx Context) - { - long NamePtr = Context.Request.SendBuff[0].Position; - - string Name = AMemoryHelper.ReadAsciiString(Context.Memory, NamePtr); - - int Fd = Fds.Add(Context.Process, new NvFd(Name)); - - Context.ResponseData.Write(Fd); - Context.ResponseData.Write(0); - - return 0; - } - - public long Ioctl(ServiceCtx Context) - { - int Fd = Context.RequestData.ReadInt32(); - int Cmd = Context.RequestData.ReadInt32(); - - NvFd FdData = Fds.GetData(Context.Process, Fd); - - int Result; - - if (IoctlProcessors.TryGetValue(FdData.Name, out IoctlProcessor Process)) - { - Result = Process(Context, Cmd); - } - else - { - throw new NotImplementedException($"{FdData.Name} {Cmd:x4}"); - } - - //TODO: Verify if the error codes needs to be translated. - Context.ResponseData.Write(Result); - - return 0; - } - - public long Close(ServiceCtx Context) - { - int Fd = Context.RequestData.ReadInt32(); - - Fds.Delete(Context.Process, Fd); - - Context.ResponseData.Write(0); - - return 0; - } - - public long Initialize(ServiceCtx Context) - { - long TransferMemSize = Context.RequestData.ReadInt64(); - int TransferMemHandle = Context.Request.HandleDesc.ToCopy[0]; - - NvMapIoctl.InitializeNvMap(Context); - - Context.ResponseData.Write(0); - - return 0; - } - - public long QueryEvent(ServiceCtx Context) - { - int Fd = Context.RequestData.ReadInt32(); - int EventId = Context.RequestData.ReadInt32(); - - //TODO: Use Fd/EventId, different channels have different events. - int Handle = Context.Process.HandleTable.OpenHandle(Event); - - Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle); - - Context.ResponseData.Write(0); - - return 0; - } - - public long SetClientPid(ServiceCtx Context) - { - long Pid = Context.RequestData.ReadInt64(); - - Context.ResponseData.Write(0); - - return 0; - } - - public long FinishInitialize(ServiceCtx Context) - { - Context.Ns.Log.PrintStub(LogClass.ServiceNv, "Stubbed."); - - return 0; - } - - private static int ProcessIoctlNvGpuAS(ServiceCtx Context, int Cmd) - { - return ProcessIoctl(Context, Cmd, NvGpuASIoctl.ProcessIoctl); - } - - private static int ProcessIoctlNvHostCtrl(ServiceCtx Context, int Cmd) - { - return ProcessIoctl(Context, Cmd, NvHostCtrlIoctl.ProcessIoctl); - } - - private static int ProcessIoctlNvGpuGpu(ServiceCtx Context, int Cmd) - { - return ProcessIoctl(Context, Cmd, NvGpuGpuIoctl.ProcessIoctl); - } - - private static int ProcessIoctlNvHostGpu(ServiceCtx Context, int Cmd) - { - return ProcessIoctl(Context, Cmd, NvHostChannelIoctl.ProcessIoctlGpu); - } - - private static int ProcessIoctlNvMap(ServiceCtx Context, int Cmd) - { - return ProcessIoctl(Context, Cmd, NvMapIoctl.ProcessIoctl); - } - - private static int ProcessIoctl(ServiceCtx Context, int Cmd, IoctlProcessor Processor) - { - if (CmdIn(Cmd) && Context.Request.GetBufferType0x21().Position == 0) - { - Context.Ns.Log.PrintError(LogClass.ServiceNv, "Input buffer is null!"); - - return NvResult.InvalidInput; - } - - if (CmdOut(Cmd) && Context.Request.GetBufferType0x22().Position == 0) - { - Context.Ns.Log.PrintError(LogClass.ServiceNv, "Output buffer is null!"); - - return NvResult.InvalidInput; - } - - return Processor(Context, Cmd); - } - - private static bool CmdIn(int Cmd) - { - return ((Cmd >> 30) & 1) != 0; - } - - private static bool CmdOut(int Cmd) - { - return ((Cmd >> 31) & 1) != 0; - } - - public static void UnloadProcess(Process Process) - { - Fds.DeleteProcess(Process); - - NvGpuASIoctl.UnloadProcess(Process); - - NvHostChannelIoctl.UnloadProcess(Process); - - NvHostCtrlIoctl.UnloadProcess(Process); - - NvMapIoctl.UnloadProcess(Process); - } - - public void Dispose() - { - Dispose(true); - } - - protected virtual void Dispose(bool Disposing) - { - if (Disposing) - { - Event.Dispose(); - } - } - } -} diff --git a/Ryujinx.HLE/OsHle/Services/Nv/NvFd.cs b/Ryujinx.HLE/OsHle/Services/Nv/NvFd.cs deleted file mode 100644 index 96fce80a..00000000 --- a/Ryujinx.HLE/OsHle/Services/Nv/NvFd.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace Ryujinx.HLE.OsHle.Services.Nv -{ - class NvFd - { - public string Name { get; private set; } - - public NvFd(string Name) - { - this.Name = Name; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Nv/NvGpuAS/NvGpuASAllocSpace.cs b/Ryujinx.HLE/OsHle/Services/Nv/NvGpuAS/NvGpuASAllocSpace.cs deleted file mode 100644 index 9d955d62..00000000 --- a/Ryujinx.HLE/OsHle/Services/Nv/NvGpuAS/NvGpuASAllocSpace.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace Ryujinx.HLE.OsHle.Services.Nv.NvGpuAS -{ - struct NvGpuASAllocSpace - { - public int Pages; - public int PageSize; - public int Flags; - public int Padding; - public long Offset; - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Nv/NvGpuAS/NvGpuASCtx.cs b/Ryujinx.HLE/OsHle/Services/Nv/NvGpuAS/NvGpuASCtx.cs deleted file mode 100644 index e718182a..00000000 --- a/Ryujinx.HLE/OsHle/Services/Nv/NvGpuAS/NvGpuASCtx.cs +++ /dev/null @@ -1,198 +0,0 @@ -using ChocolArm64.Memory; -using Ryujinx.HLE.Gpu.Memory; -using System.Collections.Generic; - -namespace Ryujinx.HLE.OsHle.Services.Nv.NvGpuAS -{ - class NvGpuASCtx - { - public NvGpuVmm Vmm { get; private set; } - - private class Range - { - public ulong Start { get; private set; } - public ulong End { get; private set; } - - public Range(long Position, long Size) - { - Start = (ulong)Position; - End = (ulong)Size + Start; - } - } - - private class MappedMemory : Range - { - public long PhysicalAddress { get; private set; } - public bool VaAllocated { get; private set; } - - public MappedMemory( - long Position, - long Size, - long PhysicalAddress, - bool VaAllocated) : base(Position, Size) - { - this.PhysicalAddress = PhysicalAddress; - this.VaAllocated = VaAllocated; - } - } - - private SortedList Maps; - private SortedList Reservations; - - public NvGpuASCtx(ServiceCtx Context) - { - Vmm = new NvGpuVmm(Context.Memory); - - Maps = new SortedList(); - Reservations = new SortedList(); - } - - public bool ValidateFixedBuffer(long Position, long Size) - { - long MapEnd = Position + Size; - - //Check if size is valid (0 is also not allowed). - if ((ulong)MapEnd <= (ulong)Position) - { - return false; - } - - //Check if address is page aligned. - if ((Position & NvGpuVmm.PageMask) != 0) - { - return false; - } - - //Check if region is reserved. - if (BinarySearch(Reservations, Position) == null) - { - return false; - } - - //Check for overlap with already mapped buffers. - Range Map = BinarySearchLt(Maps, MapEnd); - - if (Map != null && Map.End > (ulong)Position) - { - return false; - } - - return true; - } - - public void AddMap( - long Position, - long Size, - long PhysicalAddress, - bool VaAllocated) - { - Maps.Add(Position, new MappedMemory(Position, Size, PhysicalAddress, VaAllocated)); - } - - public bool RemoveMap(long Position, out long Size) - { - Size = 0; - - if (Maps.Remove(Position, out Range Value)) - { - MappedMemory Map = (MappedMemory)Value; - - if (Map.VaAllocated) - { - Size = (long)(Map.End - Map.Start); - } - - return true; - } - - return false; - } - - public bool TryGetMapPhysicalAddress(long Position, out long PhysicalAddress) - { - Range Map = BinarySearch(Maps, Position); - - if (Map != null) - { - PhysicalAddress = ((MappedMemory)Map).PhysicalAddress; - - return true; - } - - PhysicalAddress = 0; - - return false; - } - - public void AddReservation(long Position, long Size) - { - Reservations.Add(Position, new Range(Position, Size)); - } - - public bool RemoveReservation(long Position) - { - return Reservations.Remove(Position); - } - - private Range BinarySearch(SortedList Lst, long Position) - { - int Left = 0; - int Right = Lst.Count - 1; - - while (Left <= Right) - { - int Size = Right - Left; - - int Middle = Left + (Size >> 1); - - Range Rg = Lst.Values[Middle]; - - if ((ulong)Position >= Rg.Start && (ulong)Position < Rg.End) - { - return Rg; - } - - if ((ulong)Position < Rg.Start) - { - Right = Middle - 1; - } - else - { - Left = Middle + 1; - } - } - - return null; - } - - private Range BinarySearchLt(SortedList Lst, long Position) - { - Range LtRg = null; - - int Left = 0; - int Right = Lst.Count - 1; - - while (Left <= Right) - { - int Size = Right - Left; - - int Middle = Left + (Size >> 1); - - Range Rg = Lst.Values[Middle]; - - if ((ulong)Position < Rg.Start) - { - Right = Middle - 1; - } - else - { - Left = Middle + 1; - - LtRg = Rg; - } - } - - return LtRg; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Nv/NvGpuAS/NvGpuASIoctl.cs b/Ryujinx.HLE/OsHle/Services/Nv/NvGpuAS/NvGpuASIoctl.cs deleted file mode 100644 index 3c67cef0..00000000 --- a/Ryujinx.HLE/OsHle/Services/Nv/NvGpuAS/NvGpuASIoctl.cs +++ /dev/null @@ -1,329 +0,0 @@ -using ChocolArm64.Memory; -using Ryujinx.HLE.Gpu.Memory; -using Ryujinx.HLE.Logging; -using Ryujinx.HLE.OsHle.Services.Nv.NvMap; -using System; -using System.Collections.Concurrent; - -namespace Ryujinx.HLE.OsHle.Services.Nv.NvGpuAS -{ - class NvGpuASIoctl - { - private const int FlagFixedOffset = 1; - - private const int FlagRemapSubRange = 0x100; - - private static ConcurrentDictionary ASCtxs; - - static NvGpuASIoctl() - { - ASCtxs = new ConcurrentDictionary(); - } - - public static int ProcessIoctl(ServiceCtx Context, int Cmd) - { - switch (Cmd & 0xffff) - { - case 0x4101: return BindChannel (Context); - case 0x4102: return AllocSpace (Context); - case 0x4103: return FreeSpace (Context); - case 0x4105: return UnmapBuffer (Context); - case 0x4106: return MapBufferEx (Context); - case 0x4108: return GetVaRegions(Context); - case 0x4109: return InitializeEx(Context); - case 0x4114: return Remap (Context, Cmd); - } - - throw new NotImplementedException(Cmd.ToString("x8")); - } - - private static int BindChannel(ServiceCtx Context) - { - long InputPosition = Context.Request.GetBufferType0x21().Position; - long OutputPosition = Context.Request.GetBufferType0x22().Position; - - Context.Ns.Log.PrintStub(LogClass.ServiceNv, "Stubbed."); - - return NvResult.Success; - } - - private static int AllocSpace(ServiceCtx Context) - { - long InputPosition = Context.Request.GetBufferType0x21().Position; - long OutputPosition = Context.Request.GetBufferType0x22().Position; - - NvGpuASAllocSpace Args = AMemoryHelper.Read(Context.Memory, InputPosition); - - NvGpuASCtx ASCtx = GetASCtx(Context); - - ulong Size = (ulong)Args.Pages * - (ulong)Args.PageSize; - - int Result = NvResult.Success; - - lock (ASCtx) - { - //Note: When the fixed offset flag is not set, - //the Offset field holds the alignment size instead. - if ((Args.Flags & FlagFixedOffset) != 0) - { - Args.Offset = ASCtx.Vmm.ReserveFixed(Args.Offset, (long)Size); - } - else - { - Args.Offset = ASCtx.Vmm.Reserve((long)Size, Args.Offset); - } - - if (Args.Offset < 0) - { - Args.Offset = 0; - - Context.Ns.Log.PrintWarning(LogClass.ServiceNv, $"Failed to allocate size {Size:x16}!"); - - Result = NvResult.OutOfMemory; - } - else - { - ASCtx.AddReservation(Args.Offset, (long)Size); - } - } - - AMemoryHelper.Write(Context.Memory, OutputPosition, Args); - - return Result; - } - - private static int FreeSpace(ServiceCtx Context) - { - long InputPosition = Context.Request.GetBufferType0x21().Position; - long OutputPosition = Context.Request.GetBufferType0x22().Position; - - NvGpuASAllocSpace Args = AMemoryHelper.Read(Context.Memory, InputPosition); - - NvGpuASCtx ASCtx = GetASCtx(Context); - - int Result = NvResult.Success; - - lock (ASCtx) - { - ulong Size = (ulong)Args.Pages * - (ulong)Args.PageSize; - - if (ASCtx.RemoveReservation(Args.Offset)) - { - ASCtx.Vmm.Free(Args.Offset, (long)Size); - } - else - { - Context.Ns.Log.PrintWarning(LogClass.ServiceNv, - $"Failed to free offset 0x{Args.Offset:x16} size 0x{Size:x16}!"); - - Result = NvResult.InvalidInput; - } - } - - return Result; - } - - private static int UnmapBuffer(ServiceCtx Context) - { - long InputPosition = Context.Request.GetBufferType0x21().Position; - long OutputPosition = Context.Request.GetBufferType0x22().Position; - - NvGpuASUnmapBuffer Args = AMemoryHelper.Read(Context.Memory, InputPosition); - - NvGpuASCtx ASCtx = GetASCtx(Context); - - lock (ASCtx) - { - if (ASCtx.RemoveMap(Args.Offset, out long Size)) - { - if (Size != 0) - { - ASCtx.Vmm.Free(Args.Offset, Size); - } - } - else - { - Context.Ns.Log.PrintWarning(LogClass.ServiceNv, $"Invalid buffer offset {Args.Offset:x16}!"); - } - } - - return NvResult.Success; - } - - private static int MapBufferEx(ServiceCtx Context) - { - const string MapErrorMsg = "Failed to map fixed buffer with offset 0x{0:x16} and size 0x{1:x16}!"; - - long InputPosition = Context.Request.GetBufferType0x21().Position; - long OutputPosition = Context.Request.GetBufferType0x22().Position; - - NvGpuASMapBufferEx Args = AMemoryHelper.Read(Context.Memory, InputPosition); - - NvGpuASCtx ASCtx = GetASCtx(Context); - - NvMapHandle Map = NvMapIoctl.GetNvMapWithFb(Context, Args.NvMapHandle); - - if (Map == null) - { - Context.Ns.Log.PrintWarning(LogClass.ServiceNv, $"Invalid NvMap handle 0x{Args.NvMapHandle:x8}!"); - - return NvResult.InvalidInput; - } - - long PA; - - if ((Args.Flags & FlagRemapSubRange) != 0) - { - lock (ASCtx) - { - if (ASCtx.TryGetMapPhysicalAddress(Args.Offset, out PA)) - { - long VA = Args.Offset + Args.BufferOffset; - - PA += Args.BufferOffset; - - if (ASCtx.Vmm.Map(PA, VA, Args.MappingSize) < 0) - { - string Msg = string.Format(MapErrorMsg, VA, Args.MappingSize); - - Context.Ns.Log.PrintWarning(LogClass.ServiceNv, Msg); - - return NvResult.InvalidInput; - } - - return NvResult.Success; - } - else - { - Context.Ns.Log.PrintWarning(LogClass.ServiceNv, $"Address 0x{Args.Offset:x16} not mapped!"); - - return NvResult.InvalidInput; - } - } - } - - PA = Map.Address + Args.BufferOffset; - - long Size = Args.MappingSize; - - if (Size == 0) - { - Size = (uint)Map.Size; - } - - int Result = NvResult.Success; - - lock (ASCtx) - { - //Note: When the fixed offset flag is not set, - //the Offset field holds the alignment size instead. - bool VaAllocated = (Args.Flags & FlagFixedOffset) == 0; - - if (!VaAllocated) - { - if (ASCtx.ValidateFixedBuffer(Args.Offset, Size)) - { - Args.Offset = ASCtx.Vmm.Map(PA, Args.Offset, Size); - } - else - { - string Msg = string.Format(MapErrorMsg, Args.Offset, Size); - - Context.Ns.Log.PrintWarning(LogClass.ServiceNv, Msg); - - Result = NvResult.InvalidInput; - } - } - else - { - Args.Offset = ASCtx.Vmm.Map(PA, Size); - } - - if (Args.Offset < 0) - { - Args.Offset = 0; - - Context.Ns.Log.PrintWarning(LogClass.ServiceNv, $"Failed to map size 0x{Size:x16}!"); - - Result = NvResult.InvalidInput; - } - else - { - ASCtx.AddMap(Args.Offset, Size, PA, VaAllocated); - } - } - - AMemoryHelper.Write(Context.Memory, OutputPosition, Args); - - return Result; - } - - private static int GetVaRegions(ServiceCtx Context) - { - long InputPosition = Context.Request.GetBufferType0x21().Position; - long OutputPosition = Context.Request.GetBufferType0x22().Position; - - Context.Ns.Log.PrintStub(LogClass.ServiceNv, "Stubbed."); - - return NvResult.Success; - } - - private static int InitializeEx(ServiceCtx Context) - { - long InputPosition = Context.Request.GetBufferType0x21().Position; - long OutputPosition = Context.Request.GetBufferType0x22().Position; - - Context.Ns.Log.PrintStub(LogClass.ServiceNv, "Stubbed."); - - return NvResult.Success; - } - - private static int Remap(ServiceCtx Context, int Cmd) - { - int Count = ((Cmd >> 16) & 0xff) / 0x14; - - long InputPosition = Context.Request.GetBufferType0x21().Position; - - for (int Index = 0; Index < Count; Index++, InputPosition += 0x14) - { - NvGpuASRemap Args = AMemoryHelper.Read(Context.Memory, InputPosition); - - NvGpuVmm Vmm = GetASCtx(Context).Vmm; - - NvMapHandle Map = NvMapIoctl.GetNvMapWithFb(Context, Args.NvMapHandle); - - if (Map == null) - { - Context.Ns.Log.PrintWarning(LogClass.ServiceNv, $"Invalid NvMap handle 0x{Args.NvMapHandle:x8}!"); - - return NvResult.InvalidInput; - } - - long Result = Vmm.Map(Map.Address, (long)(uint)Args.Offset << 16, - (long)(uint)Args.Pages << 16); - - if (Result < 0) - { - Context.Ns.Log.PrintWarning(LogClass.ServiceNv, - $"Page 0x{Args.Offset:x16} size 0x{Args.Pages:x16} not allocated!"); - - return NvResult.InvalidInput; - } - } - - return NvResult.Success; - } - - public static NvGpuASCtx GetASCtx(ServiceCtx Context) - { - return ASCtxs.GetOrAdd(Context.Process, (Key) => new NvGpuASCtx(Context)); - } - - public static void UnloadProcess(Process Process) - { - ASCtxs.TryRemove(Process, out _); - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Nv/NvGpuAS/NvGpuASMapBufferEx.cs b/Ryujinx.HLE/OsHle/Services/Nv/NvGpuAS/NvGpuASMapBufferEx.cs deleted file mode 100644 index f3ee40b6..00000000 --- a/Ryujinx.HLE/OsHle/Services/Nv/NvGpuAS/NvGpuASMapBufferEx.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace Ryujinx.HLE.OsHle.Services.Nv.NvGpuAS -{ - struct NvGpuASMapBufferEx - { - public int Flags; - public int Kind; - public int NvMapHandle; - public int PageSize; - public long BufferOffset; - public long MappingSize; - public long Offset; - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Nv/NvGpuAS/NvGpuASRemap.cs b/Ryujinx.HLE/OsHle/Services/Nv/NvGpuAS/NvGpuASRemap.cs deleted file mode 100644 index e0ccb113..00000000 --- a/Ryujinx.HLE/OsHle/Services/Nv/NvGpuAS/NvGpuASRemap.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace Ryujinx.HLE.OsHle.Services.Nv.NvGpuAS -{ - struct NvGpuASRemap - { - public short Flags; - public short Kind; - public int NvMapHandle; - public int Padding; - public int Offset; - public int Pages; - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Nv/NvGpuAS/NvGpuASUnmapBuffer.cs b/Ryujinx.HLE/OsHle/Services/Nv/NvGpuAS/NvGpuASUnmapBuffer.cs deleted file mode 100644 index 790da3c2..00000000 --- a/Ryujinx.HLE/OsHle/Services/Nv/NvGpuAS/NvGpuASUnmapBuffer.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Ryujinx.HLE.OsHle.Services.Nv.NvGpuAS -{ - struct NvGpuASUnmapBuffer - { - public long Offset; - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Nv/NvGpuGpu/NvGpuGpuGetActiveSlotMask.cs b/Ryujinx.HLE/OsHle/Services/Nv/NvGpuGpu/NvGpuGpuGetActiveSlotMask.cs deleted file mode 100644 index 71edebbb..00000000 --- a/Ryujinx.HLE/OsHle/Services/Nv/NvGpuGpu/NvGpuGpuGetActiveSlotMask.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Ryujinx.HLE.OsHle.Services.Nv.NvGpuGpu -{ - struct NvGpuGpuGetActiveSlotMask - { - public int Slot; - public int Mask; - } -} diff --git a/Ryujinx.HLE/OsHle/Services/Nv/NvGpuGpu/NvGpuGpuGetCharacteristics.cs b/Ryujinx.HLE/OsHle/Services/Nv/NvGpuGpu/NvGpuGpuGetCharacteristics.cs deleted file mode 100644 index a519fed1..00000000 --- a/Ryujinx.HLE/OsHle/Services/Nv/NvGpuGpu/NvGpuGpuGetCharacteristics.cs +++ /dev/null @@ -1,43 +0,0 @@ -namespace Ryujinx.HLE.OsHle.Services.Nv.NvGpuGpu -{ - struct NvGpuGpuGetCharacteristics - { - public long BufferSize; - public long BufferAddress; - public int Arch; - public int Impl; - public int Rev; - public int NumGpc; - public long L2CacheSize; - public long OnBoardVideoMemorySize; - public int NumTpcPerGpc; - public int BusType; - public int BigPageSize; - public int CompressionPageSize; - public int PdeCoverageBitCount; - public int AvailableBigPageSizes; - public int GpcMask; - public int SmArchSmVersion; - public int SmArchSpaVersion; - public int SmArchWarpCount; - public int GpuVaBitCount; - public int Reserved; - public long Flags; - public int TwodClass; - public int ThreedClass; - public int ComputeClass; - public int GpfifoClass; - public int InlineToMemoryClass; - public int DmaCopyClass; - public int MaxFbpsCount; - public int FbpEnMask; - public int MaxLtcPerFbp; - public int MaxLtsPerLtc; - public int MaxTexPerTpc; - public int MaxGpcCount; - public int RopL2EnMask0; - public int RopL2EnMask1; - public long ChipName; - public long GrCompbitStoreBaseHw; - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Nv/NvGpuGpu/NvGpuGpuGetTpcMasks.cs b/Ryujinx.HLE/OsHle/Services/Nv/NvGpuGpu/NvGpuGpuGetTpcMasks.cs deleted file mode 100644 index 17a7da62..00000000 --- a/Ryujinx.HLE/OsHle/Services/Nv/NvGpuGpu/NvGpuGpuGetTpcMasks.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace Ryujinx.HLE.OsHle.Services.Nv.NvGpuGpu -{ - struct NvGpuGpuGetTpcMasks - { - public int MaskBufferSize; - public int Reserved; - public long MaskBufferAddress; - public int TpcMask; - public int Padding; - } -} diff --git a/Ryujinx.HLE/OsHle/Services/Nv/NvGpuGpu/NvGpuGpuIoctl.cs b/Ryujinx.HLE/OsHle/Services/Nv/NvGpuGpu/NvGpuGpuIoctl.cs deleted file mode 100644 index c034994c..00000000 --- a/Ryujinx.HLE/OsHle/Services/Nv/NvGpuGpu/NvGpuGpuIoctl.cs +++ /dev/null @@ -1,187 +0,0 @@ -using ChocolArm64.Memory; -using Ryujinx.HLE.Logging; -using System; -using System.Diagnostics; - -namespace Ryujinx.HLE.OsHle.Services.Nv.NvGpuGpu -{ - class NvGpuGpuIoctl - { - private static Stopwatch PTimer; - - private static double TicksToNs; - - static NvGpuGpuIoctl() - { - PTimer = new Stopwatch(); - - PTimer.Start(); - - TicksToNs = (1.0 / Stopwatch.Frequency) * 1_000_000_000; - } - - public static int ProcessIoctl(ServiceCtx Context, int Cmd) - { - switch (Cmd & 0xffff) - { - case 0x4701: return ZcullGetCtxSize (Context); - case 0x4702: return ZcullGetInfo (Context); - case 0x4703: return ZbcSetTable (Context); - case 0x4705: return GetCharacteristics(Context); - case 0x4706: return GetTpcMasks (Context); - case 0x4714: return GetActiveSlotMask (Context); - case 0x471c: return GetGpuTime (Context); - } - - throw new NotImplementedException(Cmd.ToString("x8")); - } - - private static int ZcullGetCtxSize(ServiceCtx Context) - { - long OutputPosition = Context.Request.GetBufferType0x22().Position; - - NvGpuGpuZcullGetCtxSize Args = new NvGpuGpuZcullGetCtxSize(); - - Args.Size = 1; - - AMemoryHelper.Write(Context.Memory, OutputPosition, Args); - - Context.Ns.Log.PrintStub(LogClass.ServiceNv, "Stubbed."); - - return NvResult.Success; - } - - private static int ZcullGetInfo(ServiceCtx Context) - { - long OutputPosition = Context.Request.GetBufferType0x22().Position; - - NvGpuGpuZcullGetInfo Args = new NvGpuGpuZcullGetInfo(); - - Args.WidthAlignPixels = 0x20; - Args.HeightAlignPixels = 0x20; - Args.PixelSquaresByAliquots = 0x400; - Args.AliquotTotal = 0x800; - Args.RegionByteMultiplier = 0x20; - Args.RegionHeaderSize = 0x20; - Args.SubregionHeaderSize = 0xc0; - Args.SubregionWidthAlignPixels = 0x20; - Args.SubregionHeightAlignPixels = 0x40; - Args.SubregionCount = 0x10; - - AMemoryHelper.Write(Context.Memory, OutputPosition, Args); - - Context.Ns.Log.PrintStub(LogClass.ServiceNv, "Stubbed."); - - return NvResult.Success; - } - - private static int ZbcSetTable(ServiceCtx Context) - { - long InputPosition = Context.Request.GetBufferType0x21().Position; - long OutputPosition = Context.Request.GetBufferType0x22().Position; - - Context.Ns.Log.PrintStub(LogClass.ServiceNv, "Stubbed."); - - return NvResult.Success; - } - - private static int GetCharacteristics(ServiceCtx Context) - { - long InputPosition = Context.Request.GetBufferType0x21().Position; - long OutputPosition = Context.Request.GetBufferType0x22().Position; - - NvGpuGpuGetCharacteristics Args = AMemoryHelper.Read(Context.Memory, InputPosition); - - Args.BufferSize = 0xa0; - - Args.Arch = 0x120; - Args.Impl = 0xb; - Args.Rev = 0xa1; - Args.NumGpc = 0x1; - Args.L2CacheSize = 0x40000; - Args.OnBoardVideoMemorySize = 0x0; - Args.NumTpcPerGpc = 0x2; - Args.BusType = 0x20; - Args.BigPageSize = 0x20000; - Args.CompressionPageSize = 0x20000; - Args.PdeCoverageBitCount = 0x1b; - Args.AvailableBigPageSizes = 0x30000; - Args.GpcMask = 0x1; - Args.SmArchSmVersion = 0x503; - Args.SmArchSpaVersion = 0x503; - Args.SmArchWarpCount = 0x80; - Args.GpuVaBitCount = 0x28; - Args.Reserved = 0x0; - Args.Flags = 0x55; - Args.TwodClass = 0x902d; - Args.ThreedClass = 0xb197; - Args.ComputeClass = 0xb1c0; - Args.GpfifoClass = 0xb06f; - Args.InlineToMemoryClass = 0xa140; - Args.DmaCopyClass = 0xb0b5; - Args.MaxFbpsCount = 0x1; - Args.FbpEnMask = 0x0; - Args.MaxLtcPerFbp = 0x2; - Args.MaxLtsPerLtc = 0x1; - Args.MaxTexPerTpc = 0x0; - Args.MaxGpcCount = 0x1; - Args.RopL2EnMask0 = 0x21d70; - Args.RopL2EnMask1 = 0x0; - Args.ChipName = 0x6230326d67; - Args.GrCompbitStoreBaseHw = 0x0; - - AMemoryHelper.Write(Context.Memory, OutputPosition, Args); - - return NvResult.Success; - } - - private static int GetTpcMasks(ServiceCtx Context) - { - long InputPosition = Context.Request.GetBufferType0x21().Position; - long OutputPosition = Context.Request.GetBufferType0x22().Position; - - NvGpuGpuGetTpcMasks Args = AMemoryHelper.Read(Context.Memory, InputPosition); - - if (Args.MaskBufferSize != 0) - { - Args.TpcMask = 3; - } - - AMemoryHelper.Write(Context.Memory, OutputPosition, Args); - - return NvResult.Success; - } - - private static int GetActiveSlotMask(ServiceCtx Context) - { - long OutputPosition = Context.Request.GetBufferType0x22().Position; - - NvGpuGpuGetActiveSlotMask Args = new NvGpuGpuGetActiveSlotMask(); - - Args.Slot = 0x07; - Args.Mask = 0x01; - - AMemoryHelper.Write(Context.Memory, OutputPosition, Args); - - Context.Ns.Log.PrintStub(LogClass.ServiceNv, "Stubbed."); - - return NvResult.Success; - } - - private static int GetGpuTime(ServiceCtx Context) - { - long OutputPosition = Context.Request.GetBufferType0x22().Position; - - Context.Memory.WriteInt64(OutputPosition, GetPTimerNanoSeconds()); - - return NvResult.Success; - } - - private static long GetPTimerNanoSeconds() - { - double Ticks = PTimer.ElapsedTicks; - - return (long)(Ticks * TicksToNs) & 0xff_ffff_ffff_ffff; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Nv/NvGpuGpu/NvGpuGpuZcullGetCtxSize.cs b/Ryujinx.HLE/OsHle/Services/Nv/NvGpuGpu/NvGpuGpuZcullGetCtxSize.cs deleted file mode 100644 index 21bcaceb..00000000 --- a/Ryujinx.HLE/OsHle/Services/Nv/NvGpuGpu/NvGpuGpuZcullGetCtxSize.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Ryujinx.HLE.OsHle.Services.Nv.NvGpuGpu -{ - struct NvGpuGpuZcullGetCtxSize - { - public int Size; - } -} diff --git a/Ryujinx.HLE/OsHle/Services/Nv/NvGpuGpu/NvGpuGpuZcullGetInfo.cs b/Ryujinx.HLE/OsHle/Services/Nv/NvGpuGpu/NvGpuGpuZcullGetInfo.cs deleted file mode 100644 index 168051ed..00000000 --- a/Ryujinx.HLE/OsHle/Services/Nv/NvGpuGpu/NvGpuGpuZcullGetInfo.cs +++ /dev/null @@ -1,16 +0,0 @@ -namespace Ryujinx.HLE.OsHle.Services.Nv.NvGpuGpu -{ - struct NvGpuGpuZcullGetInfo - { - public int WidthAlignPixels; - public int HeightAlignPixels; - public int PixelSquaresByAliquots; - public int AliquotTotal; - public int RegionByteMultiplier; - public int RegionHeaderSize; - public int SubregionHeaderSize; - public int SubregionWidthAlignPixels; - public int SubregionHeightAlignPixels; - public int SubregionCount; - } -} diff --git a/Ryujinx.HLE/OsHle/Services/Nv/NvHelper.cs b/Ryujinx.HLE/OsHle/Services/Nv/NvHelper.cs deleted file mode 100644 index 22f1fecc..00000000 --- a/Ryujinx.HLE/OsHle/Services/Nv/NvHelper.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Ryujinx.HLE.OsHle.Services.Nv -{ - static class NvHelper - { - public static void Crash() - { - - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Nv/NvHostChannel/NvChannel.cs b/Ryujinx.HLE/OsHle/Services/Nv/NvHostChannel/NvChannel.cs deleted file mode 100644 index 486c3806..00000000 --- a/Ryujinx.HLE/OsHle/Services/Nv/NvHostChannel/NvChannel.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Ryujinx.HLE.OsHle.Services.Nv.NvHostChannel -{ - class NvChannel - { - public int Timeout; - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Nv/NvHostChannel/NvChannelName.cs b/Ryujinx.HLE/OsHle/Services/Nv/NvHostChannel/NvChannelName.cs deleted file mode 100644 index a46a6d98..00000000 --- a/Ryujinx.HLE/OsHle/Services/Nv/NvHostChannel/NvChannelName.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Ryujinx.HLE.OsHle.Services.Nv.NvHostChannel -{ - enum NvChannelName - { - Gpu - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Nv/NvHostChannel/NvHostChannelIoctl.cs b/Ryujinx.HLE/OsHle/Services/Nv/NvHostChannel/NvHostChannelIoctl.cs deleted file mode 100644 index 3e030643..00000000 --- a/Ryujinx.HLE/OsHle/Services/Nv/NvHostChannel/NvHostChannelIoctl.cs +++ /dev/null @@ -1,210 +0,0 @@ -using ChocolArm64.Memory; -using Ryujinx.HLE.Gpu.Memory; -using Ryujinx.HLE.Logging; -using Ryujinx.HLE.OsHle.Services.Nv.NvGpuAS; -using System; -using System.Collections.Concurrent; - -namespace Ryujinx.HLE.OsHle.Services.Nv.NvHostChannel -{ - class NvHostChannelIoctl - { - private class ChannelsPerProcess - { - public ConcurrentDictionary Channels { get; private set; } - - public ChannelsPerProcess() - { - Channels = new ConcurrentDictionary(); - - Channels.TryAdd(NvChannelName.Gpu, new NvChannel()); - } - } - - private static ConcurrentDictionary Channels; - - static NvHostChannelIoctl() - { - Channels = new ConcurrentDictionary(); - } - - public static int ProcessIoctlGpu(ServiceCtx Context, int Cmd) - { - return ProcessIoctl(Context, NvChannelName.Gpu, Cmd); - } - - public static int ProcessIoctl(ServiceCtx Context, NvChannelName Channel, int Cmd) - { - switch (Cmd & 0xffff) - { - case 0x4714: return SetUserData (Context); - case 0x4801: return SetNvMap (Context); - case 0x4803: return SetTimeout (Context, Channel); - case 0x4808: return SubmitGpfifo (Context); - case 0x4809: return AllocObjCtx (Context); - case 0x480b: return ZcullBind (Context); - case 0x480c: return SetErrorNotifier (Context); - case 0x480d: return SetPriority (Context); - case 0x481a: return AllocGpfifoEx2 (Context); - case 0x481b: return KickoffPbWithAttr(Context); - } - - throw new NotImplementedException(Cmd.ToString("x8")); - } - - private static int SetUserData(ServiceCtx Context) - { - long InputPosition = Context.Request.GetBufferType0x21().Position; - long OutputPosition = Context.Request.GetBufferType0x22().Position; - - Context.Ns.Log.PrintStub(LogClass.ServiceNv, "Stubbed."); - - return NvResult.Success; - } - - private static int SetNvMap(ServiceCtx Context) - { - long InputPosition = Context.Request.GetBufferType0x21().Position; - long OutputPosition = Context.Request.GetBufferType0x22().Position; - - Context.Ns.Log.PrintStub(LogClass.ServiceNv, "Stubbed."); - - return NvResult.Success; - } - - private static int SetTimeout(ServiceCtx Context, NvChannelName Channel) - { - long InputPosition = Context.Request.GetBufferType0x21().Position; - - GetChannel(Context, Channel).Timeout = Context.Memory.ReadInt32(InputPosition); - - return NvResult.Success; - } - - private static int SubmitGpfifo(ServiceCtx Context) - { - long InputPosition = Context.Request.GetBufferType0x21().Position; - long OutputPosition = Context.Request.GetBufferType0x22().Position; - - NvHostChannelSubmitGpfifo Args = AMemoryHelper.Read(Context.Memory, InputPosition); - - NvGpuVmm Vmm = NvGpuASIoctl.GetASCtx(Context).Vmm;; - - for (int Index = 0; Index < Args.NumEntries; Index++) - { - long Gpfifo = Context.Memory.ReadInt64(InputPosition + 0x18 + Index * 8); - - PushGpfifo(Context, Vmm, Gpfifo); - } - - Args.SyncptId = 0; - Args.SyncptValue = 0; - - AMemoryHelper.Write(Context.Memory, OutputPosition, Args); - - return NvResult.Success; - } - - private static int AllocObjCtx(ServiceCtx Context) - { - long InputPosition = Context.Request.GetBufferType0x21().Position; - long OutputPosition = Context.Request.GetBufferType0x22().Position; - - Context.Ns.Log.PrintStub(LogClass.ServiceNv, "Stubbed."); - - return NvResult.Success; - } - - private static int ZcullBind(ServiceCtx Context) - { - long InputPosition = Context.Request.GetBufferType0x21().Position; - long OutputPosition = Context.Request.GetBufferType0x22().Position; - - Context.Ns.Log.PrintStub(LogClass.ServiceNv, "Stubbed."); - - return NvResult.Success; - } - - private static int SetErrorNotifier(ServiceCtx Context) - { - long InputPosition = Context.Request.GetBufferType0x21().Position; - long OutputPosition = Context.Request.GetBufferType0x22().Position; - - Context.Ns.Log.PrintStub(LogClass.ServiceNv, "Stubbed."); - - return NvResult.Success; - } - - private static int SetPriority(ServiceCtx Context) - { - long InputPosition = Context.Request.GetBufferType0x21().Position; - long OutputPosition = Context.Request.GetBufferType0x22().Position; - - Context.Ns.Log.PrintStub(LogClass.ServiceNv, "Stubbed."); - - return NvResult.Success; - } - - private static int AllocGpfifoEx2(ServiceCtx Context) - { - long InputPosition = Context.Request.GetBufferType0x21().Position; - long OutputPosition = Context.Request.GetBufferType0x22().Position; - - Context.Ns.Log.PrintStub(LogClass.ServiceNv, "Stubbed."); - - return NvResult.Success; - } - - private static int KickoffPbWithAttr(ServiceCtx Context) - { - long InputPosition = Context.Request.GetBufferType0x21().Position; - long OutputPosition = Context.Request.GetBufferType0x22().Position; - - NvHostChannelSubmitGpfifo Args = AMemoryHelper.Read(Context.Memory, InputPosition); - - NvGpuVmm Vmm = NvGpuASIoctl.GetASCtx(Context).Vmm;; - - for (int Index = 0; Index < Args.NumEntries; Index++) - { - long Gpfifo = Context.Memory.ReadInt64(Args.Address + Index * 8); - - PushGpfifo(Context, Vmm, Gpfifo); - } - - Args.SyncptId = 0; - Args.SyncptValue = 0; - - AMemoryHelper.Write(Context.Memory, OutputPosition, Args); - - return NvResult.Success; - } - - private static void PushGpfifo(ServiceCtx Context, NvGpuVmm Vmm, long Gpfifo) - { - long VA = Gpfifo & 0xff_ffff_ffff; - - int Size = (int)(Gpfifo >> 40) & 0x7ffffc; - - byte[] Data = Vmm.ReadBytes(VA, Size); - - NvGpuPBEntry[] PushBuffer = NvGpuPushBuffer.Decode(Data); - - Context.Ns.Gpu.Fifo.PushBuffer(Vmm, PushBuffer); - } - - public static NvChannel GetChannel(ServiceCtx Context, NvChannelName Channel) - { - ChannelsPerProcess Cpp = Channels.GetOrAdd(Context.Process, (Key) => - { - return new ChannelsPerProcess(); - }); - - return Cpp.Channels[Channel]; - } - - public static void UnloadProcess(Process Process) - { - Channels.TryRemove(Process, out _); - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Nv/NvHostChannel/NvHostChannelSubmitGpfifo.cs b/Ryujinx.HLE/OsHle/Services/Nv/NvHostChannel/NvHostChannelSubmitGpfifo.cs deleted file mode 100644 index ee945839..00000000 --- a/Ryujinx.HLE/OsHle/Services/Nv/NvHostChannel/NvHostChannelSubmitGpfifo.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace Ryujinx.HLE.OsHle.Services.Nv.NvHostChannel -{ - struct NvHostChannelSubmitGpfifo - { - public long Address; - public int NumEntries; - public int Flags; - public int SyncptId; - public int SyncptValue; - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Nv/NvHostCtrl/NvHostCtrlIoctl.cs b/Ryujinx.HLE/OsHle/Services/Nv/NvHostCtrl/NvHostCtrlIoctl.cs deleted file mode 100644 index 7f203453..00000000 --- a/Ryujinx.HLE/OsHle/Services/Nv/NvHostCtrl/NvHostCtrlIoctl.cs +++ /dev/null @@ -1,398 +0,0 @@ -using ChocolArm64.Memory; -using Ryujinx.HLE.Logging; -using System; -using System.Collections.Concurrent; -using System.Text; -using System.Threading; - -namespace Ryujinx.HLE.OsHle.Services.Nv.NvHostCtrl -{ - class NvHostCtrlIoctl - { - private static ConcurrentDictionary UserCtxs; - - private static bool IsProductionMode = true; - - static NvHostCtrlIoctl() - { - UserCtxs = new ConcurrentDictionary(); - - if (Set.NxSettings.Settings.TryGetValue("nv!rmos_set_production_mode", out object ProductionModeSetting)) - { - IsProductionMode = ((string)ProductionModeSetting) != "0"; // Default value is "" - } - } - - public static int ProcessIoctl(ServiceCtx Context, int Cmd) - { - switch (Cmd & 0xffff) - { - case 0x0014: return SyncptRead (Context); - case 0x0015: return SyncptIncr (Context); - case 0x0016: return SyncptWait (Context); - case 0x0019: return SyncptWaitEx (Context); - case 0x001a: return SyncptReadMax (Context); - case 0x001b: return GetConfig (Context); - case 0x001d: return EventWait (Context); - case 0x001e: return EventWaitAsync(Context); - case 0x001f: return EventRegister (Context); - } - - throw new NotImplementedException(Cmd.ToString("x8")); - } - - private static int SyncptRead(ServiceCtx Context) - { - return SyncptReadMinOrMax(Context, Max: false); - } - - private static int SyncptIncr(ServiceCtx Context) - { - long InputPosition = Context.Request.GetBufferType0x21().Position; - - int Id = Context.Memory.ReadInt32(InputPosition); - - if ((uint)Id >= NvHostSyncpt.SyncptsCount) - { - return NvResult.InvalidInput; - } - - GetUserCtx(Context).Syncpt.Increment(Id); - - return NvResult.Success; - } - - private static int SyncptWait(ServiceCtx Context) - { - return SyncptWait(Context, Extended: false); - } - - private static int SyncptWaitEx(ServiceCtx Context) - { - return SyncptWait(Context, Extended: true); - } - - private static int SyncptReadMax(ServiceCtx Context) - { - return SyncptReadMinOrMax(Context, Max: true); - } - - private static int GetConfig(ServiceCtx Context) - { - if (!IsProductionMode) - { - long InputPosition = Context.Request.GetBufferType0x21().Position; - long OutputPosition = Context.Request.GetBufferType0x22().Position; - - string Domain = AMemoryHelper.ReadAsciiString(Context.Memory, InputPosition + 0, 0x41); - string Name = AMemoryHelper.ReadAsciiString(Context.Memory, InputPosition + 0x41, 0x41); - - if (Set.NxSettings.Settings.TryGetValue($"{Domain}!{Name}", out object NvSetting)) - { - byte[] SettingBuffer = new byte[0x101]; - - if (NvSetting is string StringValue) - { - if (StringValue.Length > 0x100) - { - Context.Ns.Log.PrintError(Logging.LogClass.ServiceNv, $"{Domain}!{Name} String value size is too big!"); - } - else - { - SettingBuffer = Encoding.ASCII.GetBytes(StringValue + "\0"); - } - } - - if (NvSetting is int IntValue) - { - SettingBuffer = BitConverter.GetBytes(IntValue); - } - else if (NvSetting is bool BoolValue) - { - SettingBuffer[0] = BoolValue ? (byte)1 : (byte)0; - } - else - { - throw new NotImplementedException(NvSetting.GetType().Name); - } - - Context.Memory.WriteBytes(OutputPosition + 0x82, SettingBuffer); - - Context.Ns.Log.PrintDebug(Logging.LogClass.ServiceNv, $"Got setting {Domain}!{Name}"); - } - - return NvResult.Success; - } - - return NvResult.NotAvailableInProduction; - } - - private static int EventWait(ServiceCtx Context) - { - return EventWait(Context, Async: false); - } - - private static int EventWaitAsync(ServiceCtx Context) - { - return EventWait(Context, Async: true); - } - - private static int EventRegister(ServiceCtx Context) - { - long InputPosition = Context.Request.GetBufferType0x21().Position; - long OutputPosition = Context.Request.GetBufferType0x22().Position; - - int EventId = Context.Memory.ReadInt32(InputPosition); - - Context.Ns.Log.PrintStub(LogClass.ServiceNv, "Stubbed."); - - return NvResult.Success; - } - - private static int SyncptReadMinOrMax(ServiceCtx Context, bool Max) - { - long InputPosition = Context.Request.GetBufferType0x21().Position; - long OutputPosition = Context.Request.GetBufferType0x22().Position; - - NvHostCtrlSyncptRead Args = AMemoryHelper.Read(Context.Memory, InputPosition); - - if ((uint)Args.Id >= NvHostSyncpt.SyncptsCount) - { - return NvResult.InvalidInput; - } - - if (Max) - { - Args.Value = GetUserCtx(Context).Syncpt.GetMax(Args.Id); - } - else - { - Args.Value = GetUserCtx(Context).Syncpt.GetMin(Args.Id); - } - - AMemoryHelper.Write(Context.Memory, OutputPosition, Args); - - return NvResult.Success; - } - - private static int SyncptWait(ServiceCtx Context, bool Extended) - { - long InputPosition = Context.Request.GetBufferType0x21().Position; - long OutputPosition = Context.Request.GetBufferType0x22().Position; - - NvHostCtrlSyncptWait Args = AMemoryHelper.Read(Context.Memory, InputPosition); - - NvHostSyncpt Syncpt = GetUserCtx(Context).Syncpt; - - if ((uint)Args.Id >= NvHostSyncpt.SyncptsCount) - { - return NvResult.InvalidInput; - } - - int Result; - - if (Syncpt.MinCompare(Args.Id, Args.Thresh)) - { - Result = NvResult.Success; - } - else if (Args.Timeout == 0) - { - Result = NvResult.TryAgain; - } - else - { - Context.Ns.Log.PrintDebug(LogClass.ServiceNv, "Waiting syncpt with timeout of " + Args.Timeout + "ms..."); - - using (ManualResetEvent WaitEvent = new ManualResetEvent(false)) - { - Syncpt.AddWaiter(Args.Thresh, WaitEvent); - - //Note: Negative (> INT_MAX) timeouts aren't valid on .NET, - //in this case we just use the maximum timeout possible. - int Timeout = Args.Timeout; - - if (Timeout < -1) - { - Timeout = int.MaxValue; - } - - if (Timeout == -1) - { - WaitEvent.WaitOne(); - - Result = NvResult.Success; - } - else if (WaitEvent.WaitOne(Timeout)) - { - Result = NvResult.Success; - } - else - { - Result = NvResult.TimedOut; - } - } - - Context.Ns.Log.PrintDebug(LogClass.ServiceNv, "Resuming..."); - } - - if (Extended) - { - Context.Memory.WriteInt32(OutputPosition + 0xc, Syncpt.GetMin(Args.Id)); - } - - return Result; - } - - private static int EventWait(ServiceCtx Context, bool Async) - { - long InputPosition = Context.Request.GetBufferType0x21().Position; - long OutputPosition = Context.Request.GetBufferType0x22().Position; - - NvHostCtrlSyncptWaitEx Args = AMemoryHelper.Read(Context.Memory, InputPosition); - - if ((uint)Args.Id >= NvHostSyncpt.SyncptsCount) - { - return NvResult.InvalidInput; - } - - void WriteArgs() - { - AMemoryHelper.Write(Context.Memory, OutputPosition, Args); - } - - NvHostSyncpt Syncpt = GetUserCtx(Context).Syncpt; - - if (Syncpt.MinCompare(Args.Id, Args.Thresh)) - { - Args.Value = Syncpt.GetMin(Args.Id); - - WriteArgs(); - - return NvResult.Success; - } - - if (!Async) - { - Args.Value = 0; - } - - if (Args.Timeout == 0) - { - WriteArgs(); - - return NvResult.TryAgain; - } - - NvHostEvent Event; - - int Result, EventIndex; - - if (Async) - { - EventIndex = Args.Value; - - if ((uint)EventIndex >= NvHostCtrlUserCtx.EventsCount) - { - return NvResult.InvalidInput; - } - - Event = GetUserCtx(Context).Events[EventIndex]; - } - else - { - Event = GetFreeEvent(Context, Syncpt, Args.Id, out EventIndex); - } - - if (Event != null && - (Event.State == NvHostEventState.Registered || - Event.State == NvHostEventState.Free)) - { - Event.Id = Args.Id; - Event.Thresh = Args.Thresh; - - Event.State = NvHostEventState.Waiting; - - if (!Async) - { - Args.Value = ((Args.Id & 0xfff) << 16) | 0x10000000; - } - else - { - Args.Value = Args.Id << 4; - } - - Args.Value |= EventIndex; - - Result = NvResult.TryAgain; - } - else - { - Result = NvResult.InvalidInput; - } - - WriteArgs(); - - return Result; - } - - private static NvHostEvent GetFreeEvent( - ServiceCtx Context, - NvHostSyncpt Syncpt, - int Id, - out int EventIndex) - { - NvHostEvent[] Events = GetUserCtx(Context).Events; - - EventIndex = NvHostCtrlUserCtx.EventsCount; - - int NullIndex = NvHostCtrlUserCtx.EventsCount; - - for (int Index = 0; Index < NvHostCtrlUserCtx.EventsCount; Index++) - { - NvHostEvent Event = Events[Index]; - - if (Event != null) - { - if (Event.State == NvHostEventState.Registered || - Event.State == NvHostEventState.Free) - { - EventIndex = Index; - - if (Event.Id == Id) - { - return Event; - } - } - } - else if (NullIndex == NvHostCtrlUserCtx.EventsCount) - { - NullIndex = Index; - } - } - - if (NullIndex < NvHostCtrlUserCtx.EventsCount) - { - EventIndex = NullIndex; - - return Events[NullIndex] = new NvHostEvent(); - } - - if (EventIndex < NvHostCtrlUserCtx.EventsCount) - { - return Events[EventIndex]; - } - - return null; - } - - public static NvHostCtrlUserCtx GetUserCtx(ServiceCtx Context) - { - return UserCtxs.GetOrAdd(Context.Process, (Key) => new NvHostCtrlUserCtx()); - } - - public static void UnloadProcess(Process Process) - { - UserCtxs.TryRemove(Process, out _); - } - } -} diff --git a/Ryujinx.HLE/OsHle/Services/Nv/NvHostCtrl/NvHostCtrlSyncPtRead.cs b/Ryujinx.HLE/OsHle/Services/Nv/NvHostCtrl/NvHostCtrlSyncPtRead.cs deleted file mode 100644 index 7801f467..00000000 --- a/Ryujinx.HLE/OsHle/Services/Nv/NvHostCtrl/NvHostCtrlSyncPtRead.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Ryujinx.HLE.OsHle.Services.Nv.NvHostCtrl -{ - struct NvHostCtrlSyncptRead - { - public int Id; - public int Value; - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Nv/NvHostCtrl/NvHostCtrlSyncPtWait.cs b/Ryujinx.HLE/OsHle/Services/Nv/NvHostCtrl/NvHostCtrlSyncPtWait.cs deleted file mode 100644 index 29a75dd7..00000000 --- a/Ryujinx.HLE/OsHle/Services/Nv/NvHostCtrl/NvHostCtrlSyncPtWait.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Ryujinx.HLE.OsHle.Services.Nv.NvHostCtrl -{ - struct NvHostCtrlSyncptWait - { - public int Id; - public int Thresh; - public int Timeout; - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Nv/NvHostCtrl/NvHostCtrlSyncPtWaitEx.cs b/Ryujinx.HLE/OsHle/Services/Nv/NvHostCtrl/NvHostCtrlSyncPtWaitEx.cs deleted file mode 100644 index 79f84214..00000000 --- a/Ryujinx.HLE/OsHle/Services/Nv/NvHostCtrl/NvHostCtrlSyncPtWaitEx.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Ryujinx.HLE.OsHle.Services.Nv.NvHostCtrl -{ - struct NvHostCtrlSyncptWaitEx - { - public int Id; - public int Thresh; - public int Timeout; - public int Value; - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Nv/NvHostCtrl/NvHostCtrlUserCtx.cs b/Ryujinx.HLE/OsHle/Services/Nv/NvHostCtrl/NvHostCtrlUserCtx.cs deleted file mode 100644 index 5d414a2e..00000000 --- a/Ryujinx.HLE/OsHle/Services/Nv/NvHostCtrl/NvHostCtrlUserCtx.cs +++ /dev/null @@ -1,19 +0,0 @@ -namespace Ryujinx.HLE.OsHle.Services.Nv.NvHostCtrl -{ - class NvHostCtrlUserCtx - { - public const int LocksCount = 16; - public const int EventsCount = 64; - - public NvHostSyncpt Syncpt { get; private set; } - - public NvHostEvent[] Events { get; private set; } - - public NvHostCtrlUserCtx() - { - Syncpt = new NvHostSyncpt(); - - Events = new NvHostEvent[EventsCount]; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Nv/NvHostCtrl/NvHostEvent.cs b/Ryujinx.HLE/OsHle/Services/Nv/NvHostCtrl/NvHostEvent.cs deleted file mode 100644 index bb294d72..00000000 --- a/Ryujinx.HLE/OsHle/Services/Nv/NvHostCtrl/NvHostEvent.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Ryujinx.HLE.OsHle.Services.Nv.NvHostCtrl -{ - class NvHostEvent - { - public int Id; - public int Thresh; - - public NvHostEventState State; - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Nv/NvHostCtrl/NvHostEventState.cs b/Ryujinx.HLE/OsHle/Services/Nv/NvHostCtrl/NvHostEventState.cs deleted file mode 100644 index fa4583b8..00000000 --- a/Ryujinx.HLE/OsHle/Services/Nv/NvHostCtrl/NvHostEventState.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Ryujinx.HLE.OsHle.Services.Nv.NvHostCtrl -{ - enum NvHostEventState - { - Registered = 0, - Waiting = 1, - Busy = 2, - Free = 5 - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Nv/NvHostCtrl/NvHostSyncPt.cs b/Ryujinx.HLE/OsHle/Services/Nv/NvHostCtrl/NvHostSyncPt.cs deleted file mode 100644 index 47d63f79..00000000 --- a/Ryujinx.HLE/OsHle/Services/Nv/NvHostCtrl/NvHostSyncPt.cs +++ /dev/null @@ -1,107 +0,0 @@ -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Threading; - -namespace Ryujinx.HLE.OsHle.Services.Nv.NvHostCtrl -{ - class NvHostSyncpt - { - public const int SyncptsCount = 192; - - private int[] CounterMin; - private int[] CounterMax; - - private long EventMask; - - private ConcurrentDictionary Waiters; - - public NvHostSyncpt() - { - CounterMin = new int[SyncptsCount]; - CounterMax = new int[SyncptsCount]; - - Waiters = new ConcurrentDictionary(); - } - - public int GetMin(int Id) - { - return CounterMin[Id]; - } - - public int GetMax(int Id) - { - return CounterMax[Id]; - } - - public int Increment(int Id) - { - if (((EventMask >> Id) & 1) != 0) - { - Interlocked.Increment(ref CounterMax[Id]); - } - - return IncrementMin(Id); - } - - public int IncrementMin(int Id) - { - int Value = Interlocked.Increment(ref CounterMin[Id]); - - WakeUpWaiters(Id, Value); - - return Value; - } - - public int IncrementMax(int Id) - { - return Interlocked.Increment(ref CounterMax[Id]); - } - - public void AddWaiter(int Threshold, EventWaitHandle WaitEvent) - { - if (!Waiters.TryAdd(WaitEvent, Threshold)) - { - throw new InvalidOperationException(); - } - } - - public bool RemoveWaiter(EventWaitHandle WaitEvent) - { - return Waiters.TryRemove(WaitEvent, out _); - } - - private void WakeUpWaiters(int Id, int NewValue) - { - foreach (KeyValuePair KV in Waiters) - { - if (MinCompare(Id, NewValue, CounterMax[Id], KV.Value)) - { - KV.Key.Set(); - - Waiters.TryRemove(KV.Key, out _); - } - } - } - - public bool MinCompare(int Id, int Threshold) - { - return MinCompare(Id, CounterMin[Id], CounterMax[Id], Threshold); - } - - private bool MinCompare(int Id, int Min, int Max, int Threshold) - { - int MinDiff = Min - Threshold; - int MaxDiff = Max - Threshold; - - if (((EventMask >> Id) & 1) != 0) - { - return MinDiff >= 0; - } - else - { - return (uint)MaxDiff >= (uint)MinDiff; - } - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Nv/NvMap/NvMapAlloc.cs b/Ryujinx.HLE/OsHle/Services/Nv/NvMap/NvMapAlloc.cs deleted file mode 100644 index 10634b86..00000000 --- a/Ryujinx.HLE/OsHle/Services/Nv/NvMap/NvMapAlloc.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace Ryujinx.HLE.OsHle.Services.Nv.NvMap -{ - struct NvMapAlloc - { - public int Handle; - public int HeapMask; - public int Flags; - public int Align; - public long Kind; - public long Address; - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Nv/NvMap/NvMapCreate.cs b/Ryujinx.HLE/OsHle/Services/Nv/NvMap/NvMapCreate.cs deleted file mode 100644 index 8f3be79d..00000000 --- a/Ryujinx.HLE/OsHle/Services/Nv/NvMap/NvMapCreate.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Ryujinx.HLE.OsHle.Services.Nv.NvMap -{ - struct NvMapCreate - { - public int Size; - public int Handle; - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Nv/NvMap/NvMapFree.cs b/Ryujinx.HLE/OsHle/Services/Nv/NvMap/NvMapFree.cs deleted file mode 100644 index bc66fc71..00000000 --- a/Ryujinx.HLE/OsHle/Services/Nv/NvMap/NvMapFree.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace Ryujinx.HLE.OsHle.Services.Nv.NvMap -{ - struct NvMapFree - { - public int Handle; - public int Padding; - public long Address; - public int Size; - public int Flags; - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Nv/NvMap/NvMapFromId.cs b/Ryujinx.HLE/OsHle/Services/Nv/NvMap/NvMapFromId.cs deleted file mode 100644 index 31c75131..00000000 --- a/Ryujinx.HLE/OsHle/Services/Nv/NvMap/NvMapFromId.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Ryujinx.HLE.OsHle.Services.Nv.NvMap -{ - struct NvMapFromId - { - public int Id; - public int Handle; - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Nv/NvMap/NvMapGetId.cs b/Ryujinx.HLE/OsHle/Services/Nv/NvMap/NvMapGetId.cs deleted file mode 100644 index 780815d2..00000000 --- a/Ryujinx.HLE/OsHle/Services/Nv/NvMap/NvMapGetId.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Ryujinx.HLE.OsHle.Services.Nv.NvMap -{ - struct NvMapGetId - { - public int Id; - public int Handle; - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Nv/NvMap/NvMapHandle.cs b/Ryujinx.HLE/OsHle/Services/Nv/NvMap/NvMapHandle.cs deleted file mode 100644 index f349a03e..00000000 --- a/Ryujinx.HLE/OsHle/Services/Nv/NvMap/NvMapHandle.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System.Threading; - -namespace Ryujinx.HLE.OsHle.Services.Nv.NvMap -{ - class NvMapHandle - { - public int Handle; - public int Id; - public int Size; - public int Align; - public int Kind; - public long Address; - public bool Allocated; - - private long Dupes; - - public NvMapHandle() - { - Dupes = 1; - } - - public NvMapHandle(int Size) : this() - { - this.Size = Size; - } - - public void IncrementRefCount() - { - Interlocked.Increment(ref Dupes); - } - - public long DecrementRefCount() - { - return Interlocked.Decrement(ref Dupes); - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Nv/NvMap/NvMapHandleParam.cs b/Ryujinx.HLE/OsHle/Services/Nv/NvMap/NvMapHandleParam.cs deleted file mode 100644 index ab1b0577..00000000 --- a/Ryujinx.HLE/OsHle/Services/Nv/NvMap/NvMapHandleParam.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace Ryujinx.HLE.OsHle.Services.Nv.NvMap -{ - enum NvMapHandleParam - { - Size = 1, - Align = 2, - Base = 3, - Heap = 4, - Kind = 5, - Compr = 6 - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Nv/NvMap/NvMapIoctl.cs b/Ryujinx.HLE/OsHle/Services/Nv/NvMap/NvMapIoctl.cs deleted file mode 100644 index e5b29825..00000000 --- a/Ryujinx.HLE/OsHle/Services/Nv/NvMap/NvMapIoctl.cs +++ /dev/null @@ -1,302 +0,0 @@ -using ChocolArm64.Memory; -using Ryujinx.HLE.Gpu.Memory; -using Ryujinx.HLE.Logging; -using Ryujinx.HLE.OsHle.Utilities; -using System.Collections.Concurrent; - -namespace Ryujinx.HLE.OsHle.Services.Nv.NvMap -{ - class NvMapIoctl - { - private const int FlagNotFreedYet = 1; - - private static ConcurrentDictionary Maps; - - static NvMapIoctl() - { - Maps = new ConcurrentDictionary(); - } - - public static int ProcessIoctl(ServiceCtx Context, int Cmd) - { - switch (Cmd & 0xffff) - { - case 0x0101: return Create(Context); - case 0x0103: return FromId(Context); - case 0x0104: return Alloc (Context); - case 0x0105: return Free (Context); - case 0x0109: return Param (Context); - case 0x010e: return GetId (Context); - } - - Context.Ns.Log.PrintWarning(LogClass.ServiceNv, $"Unsupported Ioctl command 0x{Cmd:x8}!"); - - return NvResult.NotSupported; - } - - private static int Create(ServiceCtx Context) - { - long InputPosition = Context.Request.GetBufferType0x21().Position; - long OutputPosition = Context.Request.GetBufferType0x22().Position; - - NvMapCreate Args = AMemoryHelper.Read(Context.Memory, InputPosition); - - if (Args.Size == 0) - { - Context.Ns.Log.PrintWarning(LogClass.ServiceNv, $"Invalid size 0x{Args.Size:x8}!"); - - return NvResult.InvalidInput; - } - - int Size = IntUtils.AlignUp(Args.Size, NvGpuVmm.PageSize); - - Args.Handle = AddNvMap(Context, new NvMapHandle(Size)); - - Context.Ns.Log.PrintInfo(LogClass.ServiceNv, $"Created map {Args.Handle} with size 0x{Size:x8}!"); - - AMemoryHelper.Write(Context.Memory, OutputPosition, Args); - - return NvResult.Success; - } - - private static int FromId(ServiceCtx Context) - { - long InputPosition = Context.Request.GetBufferType0x21().Position; - long OutputPosition = Context.Request.GetBufferType0x22().Position; - - NvMapFromId Args = AMemoryHelper.Read(Context.Memory, InputPosition); - - NvMapHandle Map = GetNvMap(Context, Args.Id); - - if (Map == null) - { - Context.Ns.Log.PrintWarning(LogClass.ServiceNv, $"Invalid handle 0x{Args.Handle:x8}!"); - - return NvResult.InvalidInput; - } - - Map.IncrementRefCount(); - - Args.Handle = Args.Id; - - AMemoryHelper.Write(Context.Memory, OutputPosition, Args); - - return NvResult.Success; - } - - private static int Alloc(ServiceCtx Context) - { - long InputPosition = Context.Request.GetBufferType0x21().Position; - long OutputPosition = Context.Request.GetBufferType0x22().Position; - - NvMapAlloc Args = AMemoryHelper.Read(Context.Memory, InputPosition); - - NvMapHandle Map = GetNvMap(Context, Args.Handle); - - if (Map == null) - { - Context.Ns.Log.PrintWarning(LogClass.ServiceNv, $"Invalid handle 0x{Args.Handle:x8}!"); - - return NvResult.InvalidInput; - } - - if ((Args.Align & (Args.Align - 1)) != 0) - { - Context.Ns.Log.PrintWarning(LogClass.ServiceNv, $"Invalid alignment 0x{Args.Align:x8}!"); - - return NvResult.InvalidInput; - } - - if ((uint)Args.Align < NvGpuVmm.PageSize) - { - Args.Align = NvGpuVmm.PageSize; - } - - int Result = NvResult.Success; - - if (!Map.Allocated) - { - Map.Allocated = true; - - Map.Align = Args.Align; - Map.Kind = (byte)Args.Kind; - - int Size = IntUtils.AlignUp(Map.Size, NvGpuVmm.PageSize); - - long Address = Args.Address; - - if (Address == 0) - { - //When the address is zero, we need to allocate - //our own backing memory for the NvMap. - //TODO: Is this allocation inside the transfer memory? - if (!Context.Ns.Memory.Allocator.TryAllocate((uint)Size, out Address)) - { - Result = NvResult.OutOfMemory; - } - } - - if (Result == NvResult.Success) - { - Map.Size = Size; - Map.Address = Address; - } - } - - AMemoryHelper.Write(Context.Memory, OutputPosition, Args); - - return Result; - } - - private static int Free(ServiceCtx Context) - { - long InputPosition = Context.Request.GetBufferType0x21().Position; - long OutputPosition = Context.Request.GetBufferType0x22().Position; - - NvMapFree Args = AMemoryHelper.Read(Context.Memory, InputPosition); - - NvMapHandle Map = GetNvMap(Context, Args.Handle); - - if (Map == null) - { - Context.Ns.Log.PrintWarning(LogClass.ServiceNv, $"Invalid handle 0x{Args.Handle:x8}!"); - - return NvResult.InvalidInput; - } - - if (Map.DecrementRefCount() <= 0) - { - DeleteNvMap(Context, Args.Handle); - - Context.Ns.Log.PrintInfo(LogClass.ServiceNv, $"Deleted map {Args.Handle}!"); - - Args.Address = Map.Address; - Args.Flags = 0; - } - else - { - Args.Address = 0; - Args.Flags = FlagNotFreedYet; - } - - Args.Size = Map.Size; - - AMemoryHelper.Write(Context.Memory, OutputPosition, Args); - - return NvResult.Success; - } - - private static int Param(ServiceCtx Context) - { - long InputPosition = Context.Request.GetBufferType0x21().Position; - long OutputPosition = Context.Request.GetBufferType0x22().Position; - - NvMapParam Args = AMemoryHelper.Read(Context.Memory, InputPosition); - - NvMapHandle Map = GetNvMap(Context, Args.Handle); - - if (Map == null) - { - Context.Ns.Log.PrintWarning(LogClass.ServiceNv, $"Invalid handle 0x{Args.Handle:x8}!"); - - return NvResult.InvalidInput; - } - - switch ((NvMapHandleParam)Args.Param) - { - case NvMapHandleParam.Size: Args.Result = Map.Size; break; - case NvMapHandleParam.Align: Args.Result = Map.Align; break; - case NvMapHandleParam.Heap: Args.Result = 0x40000000; break; - case NvMapHandleParam.Kind: Args.Result = Map.Kind; break; - case NvMapHandleParam.Compr: Args.Result = 0; break; - - //Note: Base is not supported and returns an error. - //Any other value also returns an error. - default: return NvResult.InvalidInput; - } - - AMemoryHelper.Write(Context.Memory, OutputPosition, Args); - - return NvResult.Success; - } - - private static int GetId(ServiceCtx Context) - { - long InputPosition = Context.Request.GetBufferType0x21().Position; - long OutputPosition = Context.Request.GetBufferType0x22().Position; - - NvMapGetId Args = AMemoryHelper.Read(Context.Memory, InputPosition); - - NvMapHandle Map = GetNvMap(Context, Args.Handle); - - if (Map == null) - { - Context.Ns.Log.PrintWarning(LogClass.ServiceNv, $"Invalid handle 0x{Args.Handle:x8}!"); - - return NvResult.InvalidInput; - } - - Args.Id = Args.Handle; - - AMemoryHelper.Write(Context.Memory, OutputPosition, Args); - - return NvResult.Success; - } - - private static int AddNvMap(ServiceCtx Context, NvMapHandle Map) - { - IdDictionary Dict = Maps.GetOrAdd(Context.Process, (Key) => - { - IdDictionary NewDict = new IdDictionary(); - - NewDict.Add(0, new NvMapHandle()); - - return NewDict; - }); - - return Dict.Add(Map); - } - - private static bool DeleteNvMap(ServiceCtx Context, int Handle) - { - if (Maps.TryGetValue(Context.Process, out IdDictionary Dict)) - { - return Dict.Delete(Handle) != null; - } - - return false; - } - - public static void InitializeNvMap(ServiceCtx Context) - { - IdDictionary Dict = Maps.GetOrAdd(Context.Process, (Key) =>new IdDictionary()); - - Dict.Add(0, new NvMapHandle()); - } - - public static NvMapHandle GetNvMapWithFb(ServiceCtx Context, int Handle) - { - if (Maps.TryGetValue(Context.Process, out IdDictionary Dict)) - { - return Dict.GetData(Handle); - } - - return null; - } - - public static NvMapHandle GetNvMap(ServiceCtx Context, int Handle) - { - if (Handle != 0 && Maps.TryGetValue(Context.Process, out IdDictionary Dict)) - { - return Dict.GetData(Handle); - } - - return null; - } - - public static void UnloadProcess(Process Process) - { - Maps.TryRemove(Process, out _); - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Nv/NvMap/NvMapParam.cs b/Ryujinx.HLE/OsHle/Services/Nv/NvMap/NvMapParam.cs deleted file mode 100644 index 218cb700..00000000 --- a/Ryujinx.HLE/OsHle/Services/Nv/NvMap/NvMapParam.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Ryujinx.HLE.OsHle.Services.Nv.NvMap -{ - struct NvMapParam - { - public int Handle; - public int Param; - public int Result; - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Nv/NvResult.cs b/Ryujinx.HLE/OsHle/Services/Nv/NvResult.cs deleted file mode 100644 index 78ae5ae3..00000000 --- a/Ryujinx.HLE/OsHle/Services/Nv/NvResult.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace Ryujinx.HLE.OsHle.Services.Nv -{ - static class NvResult - { - public const int NotAvailableInProduction = 196614; - public const int Success = 0; - public const int TryAgain = -11; - public const int OutOfMemory = -12; - public const int InvalidInput = -22; - public const int NotSupported = -25; - public const int Restart = -85; - public const int TimedOut = -110; - } -} diff --git a/Ryujinx.HLE/OsHle/Services/Pctl/IParentalControlService.cs b/Ryujinx.HLE/OsHle/Services/Pctl/IParentalControlService.cs deleted file mode 100644 index 60a69f58..00000000 --- a/Ryujinx.HLE/OsHle/Services/Pctl/IParentalControlService.cs +++ /dev/null @@ -1,41 +0,0 @@ -using Ryujinx.HLE.Logging; -using Ryujinx.HLE.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.HLE.OsHle.Services.Pctl -{ - class IParentalControlService : IpcService - { - private Dictionary m_Commands; - - public override IReadOnlyDictionary Commands => m_Commands; - - private bool Initialized = false; - - private bool NeedInitialize; - - public IParentalControlService(bool NeedInitialize = true) - { - m_Commands = new Dictionary() - { - { 1, Initialize } - }; - - this.NeedInitialize = NeedInitialize; - } - - public long Initialize(ServiceCtx Context) - { - if (NeedInitialize && !Initialized) - { - Initialized = true; - } - else - { - Context.Ns.Log.PrintWarning(LogClass.ServicePctl, "Service is already initialized!"); - } - - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Pctl/IParentalControlServiceFactory.cs b/Ryujinx.HLE/OsHle/Services/Pctl/IParentalControlServiceFactory.cs deleted file mode 100644 index 7ef91d7f..00000000 --- a/Ryujinx.HLE/OsHle/Services/Pctl/IParentalControlServiceFactory.cs +++ /dev/null @@ -1,35 +0,0 @@ -using Ryujinx.HLE.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.HLE.OsHle.Services.Pctl -{ - class IParentalControlServiceFactory : IpcService - { - private Dictionary m_Commands; - - public override IReadOnlyDictionary Commands => m_Commands; - - public IParentalControlServiceFactory() - { - m_Commands = new Dictionary() - { - { 0, CreateService }, - { 1, CreateServiceWithoutInitialize } - }; - } - - public long CreateService(ServiceCtx Context) - { - MakeObject(Context, new IParentalControlService()); - - return 0; - } - - public long CreateServiceWithoutInitialize(ServiceCtx Context) - { - MakeObject(Context, new IParentalControlService(false)); - - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Pl/ISharedFontManager.cs b/Ryujinx.HLE/OsHle/Services/Pl/ISharedFontManager.cs deleted file mode 100644 index 4788c5af..00000000 --- a/Ryujinx.HLE/OsHle/Services/Pl/ISharedFontManager.cs +++ /dev/null @@ -1,125 +0,0 @@ -using Ryujinx.HLE.OsHle.Font; -using Ryujinx.HLE.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.HLE.OsHle.Services.Pl -{ - class ISharedFontManager : IpcService - { - private Dictionary m_Commands; - - public override IReadOnlyDictionary Commands => m_Commands; - - public ISharedFontManager() - { - m_Commands = new Dictionary() - { - { 0, RequestLoad }, - { 1, GetLoadState }, - { 2, GetFontSize }, - { 3, GetSharedMemoryAddressOffset }, - { 4, GetSharedMemoryNativeHandle }, - { 5, GetSharedFontInOrderOfPriority } - }; - } - - public long RequestLoad(ServiceCtx Context) - { - SharedFontType FontType = (SharedFontType)Context.RequestData.ReadInt32(); - - //We don't need to do anything here because we do lazy initialization - //on SharedFontManager (the font is loaded when necessary). - return 0; - } - - public long GetLoadState(ServiceCtx Context) - { - SharedFontType FontType = (SharedFontType)Context.RequestData.ReadInt32(); - - //1 (true) indicates that the font is already loaded. - //All fonts are already loaded. - Context.ResponseData.Write(1); - - return 0; - } - - public long GetFontSize(ServiceCtx Context) - { - SharedFontType FontType = (SharedFontType)Context.RequestData.ReadInt32(); - - Context.ResponseData.Write(Context.Ns.Os.Font.GetFontSize(FontType)); - - return 0; - } - - public long GetSharedMemoryAddressOffset(ServiceCtx Context) - { - SharedFontType FontType = (SharedFontType)Context.RequestData.ReadInt32(); - - Context.ResponseData.Write(Context.Ns.Os.Font.GetSharedMemoryAddressOffset(FontType)); - - return 0; - } - - public long GetSharedMemoryNativeHandle(ServiceCtx Context) - { - Context.Ns.Os.Font.EnsureInitialized(); - - int Handle = Context.Process.HandleTable.OpenHandle(Context.Ns.Os.FontSharedMem); - - Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle); - - return 0; - } - - public long GetSharedFontInOrderOfPriority(ServiceCtx Context) - { - long LanguageCode = Context.RequestData.ReadInt64(); - int LoadedCount = 0; - - for (SharedFontType Type = 0; Type < SharedFontType.Count; Type++) - { - int Offset = (int)Type * 4; - - if (!AddFontToOrderOfPriorityList(Context, (SharedFontType)Type, Offset)) - { - break; - } - - LoadedCount++; - } - - Context.ResponseData.Write(LoadedCount); - Context.ResponseData.Write((int)SharedFontType.Count); - - return 0; - } - - private bool AddFontToOrderOfPriorityList(ServiceCtx Context, SharedFontType FontType, int Offset) - { - long TypesPosition = Context.Request.ReceiveBuff[0].Position; - long TypesSize = Context.Request.ReceiveBuff[0].Size; - - long OffsetsPosition = Context.Request.ReceiveBuff[1].Position; - long OffsetsSize = Context.Request.ReceiveBuff[1].Size; - - long FontSizeBufferPosition = Context.Request.ReceiveBuff[2].Position; - long FontSizeBufferSize = Context.Request.ReceiveBuff[2].Size; - - if ((uint)Offset + 4 > (uint)TypesSize || - (uint)Offset + 4 > (uint)OffsetsSize || - (uint)Offset + 4 > (uint)FontSizeBufferSize) - { - return false; - } - - Context.Memory.WriteInt32(TypesPosition + Offset, (int)FontType); - - Context.Memory.WriteInt32(OffsetsPosition + Offset, Context.Ns.Os.Font.GetSharedMemoryAddressOffset(FontType)); - - Context.Memory.WriteInt32(FontSizeBufferPosition + Offset, Context.Ns.Os.Font.GetFontSize(FontType)); - - return true; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Prepo/IPrepoService.cs b/Ryujinx.HLE/OsHle/Services/Prepo/IPrepoService.cs deleted file mode 100644 index f313921a..00000000 --- a/Ryujinx.HLE/OsHle/Services/Prepo/IPrepoService.cs +++ /dev/null @@ -1,28 +0,0 @@ -using Ryujinx.HLE.Logging; -using Ryujinx.HLE.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.HLE.OsHle.Services.Prepo -{ - class IPrepoService : IpcService - { - private Dictionary m_Commands; - - public override IReadOnlyDictionary Commands => m_Commands; - - public IPrepoService() - { - m_Commands = new Dictionary() - { - { 10101, SaveReportWithUser } - }; - } - - public static long SaveReportWithUser(ServiceCtx Context) - { - Context.Ns.Log.PrintStub(LogClass.ServicePrepo, "Stubbed."); - - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/ServiceFactory.cs b/Ryujinx.HLE/OsHle/Services/ServiceFactory.cs deleted file mode 100644 index 712698b9..00000000 --- a/Ryujinx.HLE/OsHle/Services/ServiceFactory.cs +++ /dev/null @@ -1,183 +0,0 @@ -using Ryujinx.HLE.OsHle.Services.Acc; -using Ryujinx.HLE.OsHle.Services.Am; -using Ryujinx.HLE.OsHle.Services.Apm; -using Ryujinx.HLE.OsHle.Services.Aud; -using Ryujinx.HLE.OsHle.Services.Bcat; -using Ryujinx.HLE.OsHle.Services.Bsd; -using Ryujinx.HLE.OsHle.Services.Caps; -using Ryujinx.HLE.OsHle.Services.Friend; -using Ryujinx.HLE.OsHle.Services.FspSrv; -using Ryujinx.HLE.OsHle.Services.Hid; -using Ryujinx.HLE.OsHle.Services.Lm; -using Ryujinx.HLE.OsHle.Services.Mm; -using Ryujinx.HLE.OsHle.Services.Nfp; -using Ryujinx.HLE.OsHle.Services.Ns; -using Ryujinx.HLE.OsHle.Services.Nv; -using Ryujinx.HLE.OsHle.Services.Pctl; -using Ryujinx.HLE.OsHle.Services.Pl; -using Ryujinx.HLE.OsHle.Services.Prepo; -using Ryujinx.HLE.OsHle.Services.Set; -using Ryujinx.HLE.OsHle.Services.Sfdnsres; -using Ryujinx.HLE.OsHle.Services.Sm; -using Ryujinx.HLE.OsHle.Services.Spl; -using Ryujinx.HLE.OsHle.Services.Ssl; -using Ryujinx.HLE.OsHle.Services.Vi; -using System; - -namespace Ryujinx.HLE.OsHle.Services -{ - static class ServiceFactory - { - public static IpcService MakeService(string Name) - { - switch (Name) - { - case "acc:u0": - return new IAccountServiceForApplication(); - - case "aoc:u": - return new IAddOnContentManager(); - - case "apm": - return new IManager(); - - case "apm:p": - return new IManager(); - - case "appletAE": - return new IAllSystemAppletProxiesService(); - - case "appletOE": - return new IApplicationProxyService(); - - case "audout:u": - return new IAudioOutManager(); - - case "audren:u": - return new IAudioRendererManager(); - - case "bcat:a": - return new Bcat.IServiceCreator(); - - case "bcat:m": - return new Bcat.IServiceCreator(); - - case "bcat:u": - return new Bcat.IServiceCreator(); - - case "bcat:s": - return new Bcat.IServiceCreator(); - - case "bsd:s": - return new IClient(); - - case "bsd:u": - return new IClient(); - - case "caps:a": - return new IAlbumAccessorService(); - - case "caps:ss": - return new IScreenshotService(); - - case "csrng": - return new IRandomInterface(); - - case "friend:a": - return new Friend.IServiceCreator(); - - case "friend:u": - return new Friend.IServiceCreator(); - - case "fsp-srv": - return new IFileSystemProxy(); - - case "hid": - return new IHidServer(); - - case "lm": - return new ILogService(); - - case "mm:u": - return new IRequest(); - - case "nfp:user": - return new IUserManager(); - - case "nifm:u": - return new Nifm.IStaticService(); - - case "ns:ec": - return new IServiceGetterInterface(); - - case "ns:su": - return new ISystemUpdateInterface(); - - case "ns:vm": - return new IVulnerabilityManagerInterface(); - - case "nvdrv": - return new INvDrvServices(); - - case "nvdrv:a": - return new INvDrvServices(); - - case "pctl:s": - return new IParentalControlServiceFactory(); - - case "pctl:r": - return new IParentalControlServiceFactory(); - - case "pctl:a": - return new IParentalControlServiceFactory(); - - case "pctl": - return new IParentalControlServiceFactory(); - - case "pl:u": - return new ISharedFontManager(); - - case "prepo:a": - return new IPrepoService(); - - case "prepo:u": - return new IPrepoService(); - - case "set": - return new ISettingsServer(); - - case "set:sys": - return new ISystemSettingsServer(); - - case "sfdnsres": - return new IResolver(); - - case "sm:": - return new IUserInterface(); - - case "ssl": - return new ISslService(); - - case "time:a": - return new Time.IStaticService(); - - case "time:s": - return new Time.IStaticService(); - - case "time:u": - return new Time.IStaticService(); - - case "vi:m": - return new IManagerRootService(); - - case "vi:s": - return new ISystemRootService(); - - case "vi:u": - return new IApplicationRootService(); - } - - throw new NotImplementedException(Name); - } - } -} diff --git a/Ryujinx.HLE/OsHle/Services/Set/ISettingsServer.cs b/Ryujinx.HLE/OsHle/Services/Set/ISettingsServer.cs deleted file mode 100644 index 0feccfa2..00000000 --- a/Ryujinx.HLE/OsHle/Services/Set/ISettingsServer.cs +++ /dev/null @@ -1,79 +0,0 @@ -using Ryujinx.HLE.OsHle.Ipc; -using Ryujinx.HLE.OsHle.SystemState; -using System.Collections.Generic; - -namespace Ryujinx.HLE.OsHle.Services.Set -{ - class ISettingsServer : IpcService - { - private Dictionary m_Commands; - - public override IReadOnlyDictionary Commands => m_Commands; - - public ISettingsServer() - { - m_Commands = new Dictionary() - { - { 0, GetLanguageCode }, - { 1, GetAvailableLanguageCodes }, - { 3, GetAvailableLanguageCodeCount }, - { 5, GetAvailableLanguageCodes2 } - }; - } - - public static long GetLanguageCode(ServiceCtx Context) - { - Context.ResponseData.Write(Context.Ns.Os.SystemState.DesiredLanguageCode); - - return 0; - } - - public static long GetAvailableLanguageCodes(ServiceCtx Context) - { - GetAvailableLanguagesCodesImpl( - Context, - Context.Request.RecvListBuff[0].Position, - Context.Request.RecvListBuff[0].Size); - - return 0; - } - - public static long GetAvailableLanguageCodeCount(ServiceCtx Context) - { - Context.ResponseData.Write(SystemStateMgr.LanguageCodes.Length); - - return 0; - } - - public static long GetAvailableLanguageCodes2(ServiceCtx Context) - { - GetAvailableLanguagesCodesImpl( - Context, - Context.Request.ReceiveBuff[0].Position, - Context.Request.ReceiveBuff[0].Size); - - return 0; - } - - public static long GetAvailableLanguagesCodesImpl(ServiceCtx Context, long Position, long Size) - { - int Count = (int)(Size / 8); - - if (Count > SystemStateMgr.LanguageCodes.Length) - { - Count = SystemStateMgr.LanguageCodes.Length; - } - - for (int Index = 0; Index < Count; Index++) - { - Context.Memory.WriteInt64(Position, SystemStateMgr.GetLanguageCode(Index)); - - Position += 8; - } - - Context.ResponseData.Write(Count); - - return 0; - } - } -} diff --git a/Ryujinx.HLE/OsHle/Services/Set/ISystemSettingsServer.cs b/Ryujinx.HLE/OsHle/Services/Set/ISystemSettingsServer.cs deleted file mode 100644 index ef083e4c..00000000 --- a/Ryujinx.HLE/OsHle/Services/Set/ISystemSettingsServer.cs +++ /dev/null @@ -1,151 +0,0 @@ -using Ryujinx.HLE.OsHle.Ipc; -using Ryujinx.HLE.OsHle.SystemState; -using System; -using System.Collections.Generic; -using System.IO; -using System.Text; - -namespace Ryujinx.HLE.OsHle.Services.Set -{ - class ISystemSettingsServer : IpcService - { - private Dictionary m_Commands; - - public override IReadOnlyDictionary Commands => m_Commands; - - public ISystemSettingsServer() - { - m_Commands = new Dictionary() - { - { 4, GetFirmwareVersion2 }, - { 23, GetColorSetId }, - { 24, SetColorSetId }, - { 38, GetSettingsItemValue } - }; - } - - public static long GetFirmwareVersion2(ServiceCtx Context) - { - long ReplyPos = Context.Request.RecvListBuff[0].Position; - long ReplySize = Context.Request.RecvListBuff[0].Size; - - const byte MajorFWVersion = 0x03; - const byte MinorFWVersion = 0x00; - const byte MicroFWVersion = 0x00; - const byte Unknown = 0x00; //Build? - - const int RevisionNumber = 0x0A; - - const string Platform = "NX"; - const string UnknownHex = "7fbde2b0bba4d14107bf836e4643043d9f6c8e47"; - const string Version = "3.0.0"; - const string Build = "NintendoSDK Firmware for NX 3.0.0-10.0"; - - //http://switchbrew.org/index.php?title=System_Version_Title - using (MemoryStream MS = new MemoryStream(0x100)) - { - BinaryWriter Writer = new BinaryWriter(MS); - - Writer.Write(MajorFWVersion); - Writer.Write(MinorFWVersion); - Writer.Write(MicroFWVersion); - Writer.Write(Unknown); - - Writer.Write(RevisionNumber); - - Writer.Write(Encoding.ASCII.GetBytes(Platform)); - - MS.Seek(0x28, SeekOrigin.Begin); - - Writer.Write(Encoding.ASCII.GetBytes(UnknownHex)); - - MS.Seek(0x68, SeekOrigin.Begin); - - Writer.Write(Encoding.ASCII.GetBytes(Version)); - - MS.Seek(0x80, SeekOrigin.Begin); - - Writer.Write(Encoding.ASCII.GetBytes(Build)); - - Context.Memory.WriteBytes(ReplyPos, MS.ToArray()); - } - - return 0; - } - - public static long GetColorSetId(ServiceCtx Context) - { - Context.ResponseData.Write((int)Context.Ns.Os.SystemState.ThemeColor); - - return 0; - } - - public static long SetColorSetId(ServiceCtx Context) - { - int ColorSetId = Context.RequestData.ReadInt32(); - - Context.Ns.Os.SystemState.ThemeColor = (ColorSet)ColorSetId; - - return 0; - } - - public static long GetSettingsItemValue(ServiceCtx Context) - { - long ClassPos = Context.Request.PtrBuff[0].Position; - long ClassSize = Context.Request.PtrBuff[0].Size; - - long NamePos = Context.Request.PtrBuff[1].Position; - long NameSize = Context.Request.PtrBuff[1].Size; - - long ReplyPos = Context.Request.ReceiveBuff[0].Position; - long ReplySize = Context.Request.ReceiveBuff[0].Size; - - byte[] Class = Context.Memory.ReadBytes(ClassPos, ClassSize); - byte[] Name = Context.Memory.ReadBytes(NamePos, NameSize); - - string AskedSetting = Encoding.ASCII.GetString(Class).Trim('\0') + "!" + Encoding.ASCII.GetString(Name).Trim('\0'); - - NxSettings.Settings.TryGetValue(AskedSetting, out object NxSetting); - - if (NxSetting != null) - { - byte[] SettingBuffer = new byte[ReplySize]; - - if (NxSetting is string StringValue) - { - if (StringValue.Length + 1 > ReplySize) - { - Context.Ns.Log.PrintError(Logging.LogClass.ServiceSet, $"{AskedSetting} String value size is too big!"); - } - else - { - SettingBuffer = Encoding.ASCII.GetBytes(StringValue + "\0"); - } - } - - if (NxSetting is int IntValue) - { - SettingBuffer = BitConverter.GetBytes(IntValue); - } - else if (NxSetting is bool BoolValue) - { - SettingBuffer[0] = BoolValue ? (byte)1 : (byte)0; - } - else - { - throw new NotImplementedException(NxSetting.GetType().Name); - } - - Context.Memory.WriteBytes(ReplyPos, SettingBuffer); - - Context.Ns.Log.PrintDebug(Logging.LogClass.ServiceSet, $"{AskedSetting} set value: {NxSetting} as {NxSetting.GetType()}"); - } - else - { - Context.Ns.Log.PrintError(Logging.LogClass.ServiceSet, $"{AskedSetting} not found!"); - } - - return 0; - } - } -} diff --git a/Ryujinx.HLE/OsHle/Services/Set/NxSettings.cs b/Ryujinx.HLE/OsHle/Services/Set/NxSettings.cs deleted file mode 100644 index dc4a0b96..00000000 --- a/Ryujinx.HLE/OsHle/Services/Set/NxSettings.cs +++ /dev/null @@ -1,1711 +0,0 @@ -using System.Collections.Generic; - -namespace Ryujinx.HLE.OsHle.Services.Set -{ - static class NxSettings - { - //Generated automatically from a Switch 3.0 config file (Tid: 0100000000000818). - public static Dictionary Settings = new Dictionary() - { - { "account!na_required_for_network_service", true }, - { "account.daemon!background_awaking_periodicity", 10800 }, - { "account.daemon!schedule_periodicity", 3600 }, - { "account.daemon!profile_sync_interval", 18000 }, - { "account.daemon!na_info_refresh_interval", 46800 }, - { "am.display!transition_layer_enabled", true }, - { "am.gpu!gpu_scheduling_enabled", true }, - { "am.gpu!gpu_scheduling_frame_time_us", 116666 }, - { "am.gpu!gpu_scheduling_fg_app_us", 116166 }, - { "am.gpu!gpu_scheduling_bg_app_us", 104500 }, - { "am.gpu!gpu_scheduling_oa_us", 500 }, - { "am.gpu!gpu_scheduling_fg_sa_us", 11666 }, - { "am.gpu!gpu_scheduling_bg_sa_us", 0 }, - { "am.gpu!gpu_scheduling_fg_la_us", 11666 }, - { "am.gpu!gpu_scheduling_partial_fg_la_us", 2000 }, - { "am.gpu!gpu_scheduling_bg_la_us", 0 }, - { "audio!audren_log_enabled", false }, - { "audio!audout_log_enabled", false }, - { "audio!audin_log_enabled", false }, - { "audio!hwopus_log_enabled", false }, - { "audio!adsp_log_enabled", false }, - { "audio!suspend_for_debugger_enabled", false }, - { "audio!uac_speaker_enabled", false }, - { "bgtc!enable_halfawake", 1 }, - { "bgtc!enable_battery_saver", 1 }, - { "bgtc!leaving_halfawake_margin", 3 }, - { "bgtc!battery_threshold_save", 20 }, - { "bgtc!battery_threshold_stop", 20 }, - { "bgtc!minimum_interval_normal", 1800 }, - { "bgtc!minimum_interval_save", 86400 }, - { "boot!force_maintenance", false }, - { "capsrv!screenshot_layerstack", "screenshot" }, - { "capsrv!enable_album_screenshot_filedata_verification", true }, - { "devmenu!enable_application_update", true }, - { "devmenu!enable_exhibition_mode", false }, - { "eclct!analytics_override", false }, - { "eclct!analytics_pollperiod", 86400 }, - { "err!applet_auto_close", false }, - { "friends!background_processing", true }, - { "htc!disconnection_emulation", false }, - { "idle!dim_level_percent_lcd", 10 }, - { "idle!dim_level_percent_tv", 70 }, - { "lbl!force_disable_als", false }, - { "lm!enable_sd_card_logging", false }, - { "lm!sd_card_log_output_directory", "NxBinLogs" }, - { "mii!is_db_test_mode_enabled", false }, - { "news!system_version", 2 }, - { "nfp!not_locked_tag", true }, - { "nfp!play_report", false }, - { "nifm!is_communication_control_enabled_for_test", false }, - { "nifm!connection_test_timeout", 45000 }, - { "nifm!apply_config_timeout", 30000 }, - { "nifm!ethernet_adapter_standby_time", 10000 }, - { "nim.install!prefer_delta_evenif_inefficient", false }, - { "nim.install!apply_delta_stress_storage", 0 }, - { "ns.notification!retry_interval", 60 }, - { "ns.notification!enable_network_update", true }, - { "ns.notification!enable_download_task_list", true }, - { "ns.notification!enable_version_list", true }, - { "ns.notification!enable_random_wait", true }, - { "ns.notification!debug_waiting_limit", 0 }, - { "ns.notification!enable_request_on_cold_boot", true }, - { "ns.sdcard!mount_sdcard", true }, - { "ns.sdcard!compare_sdcard", 0 }, - { "ns.gamecard!mount_gamecard_result_value", 0 }, - { "ns.gamecard!try_gamecard_access_result_value", 0 }, - { "nv!00008600", "" }, - { "nv!0007b25e", "" }, - { "nv!0083e1", "" }, - { "nv!01621887", "" }, - { "nv!03134743", "" }, - { "nv!0356afd0", "" }, - { "nv!0356afd1", "" }, - { "nv!0356afd2", "" }, - { "nv!0356afd3", "" }, - { "nv!094313", "" }, - { "nv!0x04dc09", "" }, - { "nv!0x111133", "" }, - { "nv!0x1aa483", "" }, - { "nv!0x1cb1cf", "" }, - { "nv!0x1cb1d0", "" }, - { "nv!0x1e3221", "" }, - { "nv!0x300fc8", "" }, - { "nv!0x301fc8", "" }, - { "nv!0x302fc8", "" }, - { "nv!0x3eec59", "" }, - { "nv!0x46b3ed", "" }, - { "nv!0x523dc0", "" }, - { "nv!0x523dc1", "" }, - { "nv!0x523dc2", "" }, - { "nv!0x523dc3", "" }, - { "nv!0x523dc4", "" }, - { "nv!0x523dc5", "" }, - { "nv!0x523dc6", "" }, - { "nv!0x523dd0", "" }, - { "nv!0x523dd1", "" }, - { "nv!0x523dd3", "" }, - { "nv!0x5344bb", "" }, - { "nv!0x555237", "" }, - { "nv!0x58a234", "" }, - { "nv!0x7b4428", "" }, - { "nv!0x923dc0", "" }, - { "nv!0x923dc1", "" }, - { "nv!0x923dc2", "" }, - { "nv!0x923dc3", "" }, - { "nv!0x923dc4", "" }, - { "nv!0x923dd3", "" }, - { "nv!0x9abdc5", "" }, - { "nv!0x9abdc6", "" }, - { "nv!0xaaa36c", "" }, - { "nv!0xb09da0", "" }, - { "nv!0xb09da1", "" }, - { "nv!0xb09da2", "" }, - { "nv!0xb09da3", "" }, - { "nv!0xb09da4", "" }, - { "nv!0xb09da5", "" }, - { "nv!0xb0b348", "" }, - { "nv!0xb0b349", "" }, - { "nv!0xbb558f", "" }, - { "nv!0xbd10fb", "" }, - { "nv!0xc32ad3", "" }, - { "nv!0xce2348", "" }, - { "nv!0xcfd81f", "" }, - { "nv!0xe0036b", "" }, - { "nv!0xe01f2d", "" }, - { "nv!0xe17212", "" }, - { "nv!0xeae966", "" }, - { "nv!0xed4f82", "" }, - { "nv!0xf12335", "" }, - { "nv!0xf12336", "" }, - { "nv!10261989", "" }, - { "nv!1042d483", "" }, - { "nv!10572898", "" }, - { "nv!115631", "" }, - { "nv!12950094", "" }, - { "nv!1314f311", "" }, - { "nv!1314f312", "" }, - { "nv!13279512", "" }, - { "nv!13813496", "" }, - { "nv!14507179", "" }, - { "nv!15694569", "" }, - { "nv!16936964", "" }, - { "nv!17aa230c", "" }, - { "nv!182054", "" }, - { "nv!18273275", "" }, - { "nv!18273276", "" }, - { "nv!1854d03b", "" }, - { "nv!18add00d", "" }, - { "nv!19156670", "" }, - { "nv!19286545", "" }, - { "nv!1a298e9f", "" }, - { "nv!1acf43fe", "" }, - { "nv!1bda43fe", "" }, - { "nv!1c3b92", "" }, - { "nv!21509920", "" }, - { "nv!215323457", "" }, - { "nv!2165ad", "" }, - { "nv!2165ae", "" }, - { "nv!21be9c", "" }, - { "nv!233264316", "" }, - { "nv!234557580", "" }, - { "nv!23cd0e", "" }, - { "nv!24189123", "" }, - { "nv!2443266", "" }, - { "nv!25025519", "" }, - { "nv!255e39", "" }, - { "nv!2583364", "" }, - { "nv!2888c1", "" }, - { "nv!28ca3e", "" }, - { "nv!29871243", "" }, - { "nv!2a1f64", "" }, - { "nv!2dc432", "" }, - { "nv!2de437", "" }, - { "nv!2f3bb89c", "" }, - { "nv!2fd652", "" }, - { "nv!3001ac", "" }, - { "nv!31298772", "" }, - { "nv!313233", "" }, - { "nv!31f7d603", "" }, - { "nv!320ce4", "" }, - { "nv!32153248", "" }, - { "nv!32153249", "" }, - { "nv!335bca", "" }, - { "nv!342abb", "" }, - { "nv!34dfe6", "" }, - { "nv!34dfe7", "" }, - { "nv!34dfe8", "" }, - { "nv!34dfe9", "" }, - { "nv!35201578", "" }, - { "nv!359278", "" }, - { "nv!37f53a", "" }, - { "nv!38144972", "" }, - { "nv!38542646", "" }, - { "nv!3b74c9", "" }, - { "nv!3c136f", "" }, - { "nv!3cf72823", "" }, - { "nv!3d7af029", "" }, - { "nv!3ff34782", "" }, - { "nv!4129618", "" }, - { "nv!4189fac3", "" }, - { "nv!420bd4", "" }, - { "nv!42a699", "" }, - { "nv!441369", "" }, - { "nv!4458713e", "" }, - { "nv!4554b6", "" }, - { "nv!457425", "" }, - { "nv!4603b207", "" }, - { "nv!46574957", "" }, - { "nv!46574958", "" }, - { "nv!46813529", "" }, - { "nv!46f1e13d", "" }, - { "nv!47534c43", "" }, - { "nv!48550336", "" }, - { "nv!48576893", "" }, - { "nv!48576894", "" }, - { "nv!4889ac02", "" }, - { "nv!49005740", "" }, - { "nv!49867584", "" }, - { "nv!49960973", "" }, - { "nv!4a5341", "" }, - { "nv!4f4e48", "" }, - { "nv!4f8a0a", "" }, - { "nv!50299698", "" }, - { "nv!50299699", "" }, - { "nv!50361291", "" }, - { "nv!5242ae", "" }, - { "nv!53d30c", "" }, - { "nv!56347a", "" }, - { "nv!563a95f1", "" }, - { "nv!573823", "" }, - { "nv!58027529", "" }, - { "nv!5d2d63", "" }, - { "nv!5f7e3b", "" }, - { "nv!60461793", "" }, - { "nv!60d355", "" }, - { "nv!616627aa", "" }, - { "nv!62317182", "" }, - { "nv!6253fa2e", "" }, - { "nv!64100768", "" }, - { "nv!64100769", "" }, - { "nv!64100770", "" }, - { "nv!647395", "" }, - { "nv!66543234", "" }, - { "nv!67674763", "" }, - { "nv!67739784", "" }, - { "nv!68fb9c", "" }, - { "nv!69801276", "" }, - { "nv!6af9fa2f", "" }, - { "nv!6af9fa3f", "" }, - { "nv!6af9fa4f", "" }, - { "nv!6bd8c7", "" }, - { "nv!6c7691", "" }, - { "nv!6d4296ce", "" }, - { "nv!6dd7e7", "" }, - { "nv!6dd7e8", "" }, - { "nv!6fe11ec1", "" }, - { "nv!716511763", "" }, - { "nv!72504593", "" }, - { "nv!73304097", "" }, - { "nv!73314098", "" }, - { "nv!74095213", "" }, - { "nv!74095213a", "" }, - { "nv!74095213b", "" }, - { "nv!74095214", "" }, - { "nv!748f9649", "" }, - { "nv!75494732", "" }, - { "nv!78452832", "" }, - { "nv!784561", "" }, - { "nv!78e16b9c", "" }, - { "nv!79251225", "" }, - { "nv!7c128b", "" }, - { "nv!7ccd93", "" }, - { "nv!7df8d1", "" }, - { "nv!800c2310", "" }, - { "nv!80546710", "" }, - { "nv!80772310", "" }, - { "nv!808ee280", "" }, - { "nv!81131154", "" }, - { "nv!81274457", "" }, - { "nv!8292291f", "" }, - { "nv!83498426", "" }, - { "nv!84993794", "" }, - { "nv!84995585", "" }, - { "nv!84a0a0", "" }, - { "nv!852142", "" }, - { "nv!85612309", "" }, - { "nv!85612310", "" }, - { "nv!85612311", "" }, - { "nv!85612312", "" }, - { "nv!8623ff27", "" }, - { "nv!87364952", "" }, - { "nv!87f6275666", "" }, - { "nv!886748", "" }, - { "nv!89894423", "" }, - { "nv!8ad8a75", "" }, - { "nv!8ad8ad00", "" }, - { "nv!8bb815", "" }, - { "nv!8bb817", "" }, - { "nv!8bb818", "" }, - { "nv!8bb819", "" }, - { "nv!8e640cd1", "" }, - { "nv!8f34971a", "" }, - { "nv!8f773984", "" }, - { "nv!8f7a7d", "" }, - { "nv!902486209", "" }, - { "nv!90482571", "" }, - { "nv!91214835", "" }, - { "nv!912848290", "" }, - { "nv!915e56", "" }, - { "nv!92179063", "" }, - { "nv!92179064", "" }, - { "nv!92179065", "" }, - { "nv!92179066", "" }, - { "nv!92350358", "" }, - { "nv!92809063", "" }, - { "nv!92809064", "" }, - { "nv!92809065", "" }, - { "nv!92809066", "" }, - { "nv!92920143", "" }, - { "nv!93a89b12", "" }, - { "nv!93a89c0b", "" }, - { "nv!94812574", "" }, - { "nv!95282304", "" }, - { "nv!95394027", "" }, - { "nv!959b1f", "" }, - { "nv!9638af", "" }, - { "nv!96fd59", "" }, - { "nv!97f6275666", "" }, - { "nv!97f6275667", "" }, - { "nv!97f6275668", "" }, - { "nv!97f6275669", "" }, - { "nv!97f627566a", "" }, - { "nv!97f627566b", "" }, - { "nv!97f627566d", "" }, - { "nv!97f627566e", "" }, - { "nv!97f627566f", "" }, - { "nv!97f6275670", "" }, - { "nv!97f6275671", "" }, - { "nv!97f727566e", "" }, - { "nv!98480775", "" }, - { "nv!98480776", "" }, - { "nv!98480777", "" }, - { "nv!992431", "" }, - { "nv!9aa29065", "" }, - { "nv!9af32c", "" }, - { "nv!9af32d", "" }, - { "nv!9af32e", "" }, - { "nv!9c108b71", "" }, - { "nv!9f279065", "" }, - { "nv!a01bc728", "" }, - { "nv!a13b46c80", "" }, - { "nv!a22eb0", "" }, - { "nv!a2fb451e", "" }, - { "nv!a3456abe", "" }, - { "nv!a7044887", "" }, - { "nv!a7149200", "" }, - { "nv!a766215670", "" }, - { "nv!aac_drc_boost", "" }, - { "nv!aac_drc_cut", "" }, - { "nv!aac_drc_enc_target_level", "" }, - { "nv!aac_drc_heavy", "" }, - { "nv!aac_drc_reference_level", "" }, - { "nv!aalinegamma", "" }, - { "nv!aalinetweaks", "" }, - { "nv!ab34ee01", "" }, - { "nv!ab34ee02", "" }, - { "nv!ab34ee03", "" }, - { "nv!ac0274", "" }, - { "nv!af73c63e", "" }, - { "nv!af73c63f", "" }, - { "nv!af9927", "" }, - { "nv!afoverride", "" }, - { "nv!allocdeviceevents", "" }, - { "nv!applicationkey", "" }, - { "nv!appreturnonlybasicglsltype", "" }, - { "nv!app_softimage", "" }, - { "nv!app_supportbits2", "" }, - { "nv!assumetextureismipmappedatcreation", "" }, - { "nv!b1fb0f01", "" }, - { "nv!b3edd5", "" }, - { "nv!b40d9e03d", "" }, - { "nv!b7f6275666", "" }, - { "nv!b812c1", "" }, - { "nv!ba14ba1a", "" }, - { "nv!ba14ba1b", "" }, - { "nv!bd7559", "" }, - { "nv!bd755a", "" }, - { "nv!bd755c", "" }, - { "nv!bd755d", "" }, - { "nv!be58bb", "" }, - { "nv!be92cb", "" }, - { "nv!beefcba3", "" }, - { "nv!beefcba4", "" }, - { "nv!c023777f", "" }, - { "nv!c09dc8", "" }, - { "nv!c0d340", "" }, - { "nv!c2ff374c", "" }, - { "nv!c5e9d7a3", "" }, - { "nv!c5e9d7a4", "" }, - { "nv!c5e9d7b4", "" }, - { "nv!c618f9", "" }, - { "nv!ca345840", "" }, - { "nv!cachedisable", "" }, - { "nv!cast.on", "" }, - { "nv!cde", "" }, - { "nv!channelpriorityoverride", "" }, - { "nv!cleardatastorevidmem", "" }, - { "nv!cmdbufmemoryspaceenables", "" }, - { "nv!cmdbufminwords", "" }, - { "nv!cmdbufsizewords", "" }, - { "nv!conformantblitframebufferscissor", "" }, - { "nv!conformantincompletetextures", "" }, - { "nv!copybuffermethod", "" }, - { "nv!cubemapaniso", "" }, - { "nv!cubemapfiltering", "" }, - { "nv!d0e9a4d7", "" }, - { "nv!d13733f12", "" }, - { "nv!d1b399", "" }, - { "nv!d2983c32", "" }, - { "nv!d2983c33", "" }, - { "nv!d2e71b", "" }, - { "nv!d377dc", "" }, - { "nv!d377dd", "" }, - { "nv!d489f4", "" }, - { "nv!d4bce1", "" }, - { "nv!d518cb", "" }, - { "nv!d518cd", "" }, - { "nv!d518ce", "" }, - { "nv!d518d0", "" }, - { "nv!d518d1", "" }, - { "nv!d518d2", "" }, - { "nv!d518d3", "" }, - { "nv!d518d4", "" }, - { "nv!d518d5", "" }, - { "nv!d59eda", "" }, - { "nv!d83cbd", "" }, - { "nv!d8e777", "" }, - { "nv!debug_level", "" }, - { "nv!debug_mask", "" }, - { "nv!debug_options", "" }, - { "nv!devshmpageableallocations", "" }, - { "nv!df1f9812", "" }, - { "nv!df783c", "" }, - { "nv!diagenable", "" }, - { "nv!disallowcemask", "" }, - { "nv!disallowz16", "" }, - { "nv!dlmemoryspaceenables", "" }, - { "nv!e0bfec", "" }, - { "nv!e433456d", "" }, - { "nv!e435563f", "" }, - { "nv!e4cd9c", "" }, - { "nv!e5c972", "" }, - { "nv!e639ef", "" }, - { "nv!e802af", "" }, - { "nv!eae964", "" }, - { "nv!earlytexturehwallocation", "" }, - { "nv!eb92a3", "" }, - { "nv!ebca56", "" }, - { "nv!enable-noaud", "" }, - { "nv!enable-noavs", "" }, - { "nv!enable-prof", "" }, - { "nv!enable-sxesmode", "" }, - { "nv!enable-ulld", "" }, - { "nv!expert_detail_level", "" }, - { "nv!expert_output_mask", "" }, - { "nv!expert_report_mask", "" }, - { "nv!extensionstringnvarch", "" }, - { "nv!extensionstringversion", "" }, - { "nv!f00f1938", "" }, - { "nv!f10736", "" }, - { "nv!f1846870", "" }, - { "nv!f33bc370", "" }, - { "nv!f392a874", "" }, - { "nv!f49ae8", "" }, - { "nv!fa345cce", "" }, - { "nv!fa35cc4", "" }, - { "nv!faa14a", "" }, - { "nv!faf8a723", "" }, - { "nv!fastgs", "" }, - { "nv!fbf4ac45", "" }, - { "nv!fbo_blit_ignore_srgb", "" }, - { "nv!fc64c7", "" }, - { "nv!ff54ec97", "" }, - { "nv!ff54ec98", "" }, - { "nv!forceexitprocessdetach", "" }, - { "nv!forcerequestedesversion", "" }, - { "nv!__gl_", "" }, - { "nv!__gl_00008600", "" }, - { "nv!__gl_0007b25e", "" }, - { "nv!__gl_0083e1", "" }, - { "nv!__gl_01621887", "" }, - { "nv!__gl_03134743", "" }, - { "nv!__gl_0356afd0", "" }, - { "nv!__gl_0356afd1", "" }, - { "nv!__gl_0356afd2", "" }, - { "nv!__gl_0356afd3", "" }, - { "nv!__gl_094313", "" }, - { "nv!__gl_0x04dc09", "" }, - { "nv!__gl_0x111133", "" }, - { "nv!__gl_0x1aa483", "" }, - { "nv!__gl_0x1cb1cf", "" }, - { "nv!__gl_0x1cb1d0", "" }, - { "nv!__gl_0x1e3221", "" }, - { "nv!__gl_0x300fc8", "" }, - { "nv!__gl_0x301fc8", "" }, - { "nv!__gl_0x302fc8", "" }, - { "nv!__gl_0x3eec59", "" }, - { "nv!__gl_0x46b3ed", "" }, - { "nv!__gl_0x523dc0", "" }, - { "nv!__gl_0x523dc1", "" }, - { "nv!__gl_0x523dc2", "" }, - { "nv!__gl_0x523dc3", "" }, - { "nv!__gl_0x523dc4", "" }, - { "nv!__gl_0x523dc5", "" }, - { "nv!__gl_0x523dc6", "" }, - { "nv!__gl_0x523dd0", "" }, - { "nv!__gl_0x523dd1", "" }, - { "nv!__gl_0x523dd3", "" }, - { "nv!__gl_0x5344bb", "" }, - { "nv!__gl_0x555237", "" }, - { "nv!__gl_0x58a234", "" }, - { "nv!__gl_0x7b4428", "" }, - { "nv!__gl_0x923dc0", "" }, - { "nv!__gl_0x923dc1", "" }, - { "nv!__gl_0x923dc2", "" }, - { "nv!__gl_0x923dc3", "" }, - { "nv!__gl_0x923dc4", "" }, - { "nv!__gl_0x923dd3", "" }, - { "nv!__gl_0x9abdc5", "" }, - { "nv!__gl_0x9abdc6", "" }, - { "nv!__gl_0xaaa36c", "" }, - { "nv!__gl_0xb09da0", "" }, - { "nv!__gl_0xb09da1", "" }, - { "nv!__gl_0xb09da2", "" }, - { "nv!__gl_0xb09da3", "" }, - { "nv!__gl_0xb09da4", "" }, - { "nv!__gl_0xb09da5", "" }, - { "nv!__gl_0xb0b348", "" }, - { "nv!__gl_0xb0b349", "" }, - { "nv!__gl_0xbb558f", "" }, - { "nv!__gl_0xbd10fb", "" }, - { "nv!__gl_0xc32ad3", "" }, - { "nv!__gl_0xce2348", "" }, - { "nv!__gl_0xcfd81f", "" }, - { "nv!__gl_0xe0036b", "" }, - { "nv!__gl_0xe01f2d", "" }, - { "nv!__gl_0xe17212", "" }, - { "nv!__gl_0xeae966", "" }, - { "nv!__gl_0xed4f82", "" }, - { "nv!__gl_0xf12335", "" }, - { "nv!__gl_0xf12336", "" }, - { "nv!__gl_10261989", "" }, - { "nv!__gl_1042d483", "" }, - { "nv!__gl_10572898", "" }, - { "nv!__gl_115631", "" }, - { "nv!__gl_12950094", "" }, - { "nv!__gl_1314f311", "" }, - { "nv!__gl_1314f312", "" }, - { "nv!__gl_13279512", "" }, - { "nv!__gl_13813496", "" }, - { "nv!__gl_14507179", "" }, - { "nv!__gl_15694569", "" }, - { "nv!__gl_16936964", "" }, - { "nv!__gl_17aa230c", "" }, - { "nv!__gl_182054", "" }, - { "nv!__gl_18273275", "" }, - { "nv!__gl_18273276", "" }, - { "nv!__gl_1854d03b", "" }, - { "nv!__gl_18add00d", "" }, - { "nv!__gl_19156670", "" }, - { "nv!__gl_19286545", "" }, - { "nv!__gl_1a298e9f", "" }, - { "nv!__gl_1acf43fe", "" }, - { "nv!__gl_1bda43fe", "" }, - { "nv!__gl_1c3b92", "" }, - { "nv!__gl_21509920", "" }, - { "nv!__gl_215323457", "" }, - { "nv!__gl_2165ad", "" }, - { "nv!__gl_2165ae", "" }, - { "nv!__gl_21be9c", "" }, - { "nv!__gl_233264316", "" }, - { "nv!__gl_234557580", "" }, - { "nv!__gl_23cd0e", "" }, - { "nv!__gl_24189123", "" }, - { "nv!__gl_2443266", "" }, - { "nv!__gl_25025519", "" }, - { "nv!__gl_255e39", "" }, - { "nv!__gl_2583364", "" }, - { "nv!__gl_2888c1", "" }, - { "nv!__gl_28ca3e", "" }, - { "nv!__gl_29871243", "" }, - { "nv!__gl_2a1f64", "" }, - { "nv!__gl_2dc432", "" }, - { "nv!__gl_2de437", "" }, - { "nv!__gl_2f3bb89c", "" }, - { "nv!__gl_2fd652", "" }, - { "nv!__gl_3001ac", "" }, - { "nv!__gl_31298772", "" }, - { "nv!__gl_313233", "" }, - { "nv!__gl_31f7d603", "" }, - { "nv!__gl_320ce4", "" }, - { "nv!__gl_32153248", "" }, - { "nv!__gl_32153249", "" }, - { "nv!__gl_335bca", "" }, - { "nv!__gl_342abb", "" }, - { "nv!__gl_34dfe6", "" }, - { "nv!__gl_34dfe7", "" }, - { "nv!__gl_34dfe8", "" }, - { "nv!__gl_34dfe9", "" }, - { "nv!__gl_35201578", "" }, - { "nv!__gl_359278", "" }, - { "nv!__gl_37f53a", "" }, - { "nv!__gl_38144972", "" }, - { "nv!__gl_38542646", "" }, - { "nv!__gl_3b74c9", "" }, - { "nv!__gl_3c136f", "" }, - { "nv!__gl_3cf72823", "" }, - { "nv!__gl_3d7af029", "" }, - { "nv!__gl_3ff34782", "" }, - { "nv!__gl_4129618", "" }, - { "nv!__gl_4189fac3", "" }, - { "nv!__gl_420bd4", "" }, - { "nv!__gl_42a699", "" }, - { "nv!__gl_441369", "" }, - { "nv!__gl_4458713e", "" }, - { "nv!__gl_4554b6", "" }, - { "nv!__gl_457425", "" }, - { "nv!__gl_4603b207", "" }, - { "nv!__gl_46574957", "" }, - { "nv!__gl_46574958", "" }, - { "nv!__gl_46813529", "" }, - { "nv!__gl_46f1e13d", "" }, - { "nv!__gl_47534c43", "" }, - { "nv!__gl_48550336", "" }, - { "nv!__gl_48576893", "" }, - { "nv!__gl_48576894", "" }, - { "nv!__gl_4889ac02", "" }, - { "nv!__gl_49005740", "" }, - { "nv!__gl_49867584", "" }, - { "nv!__gl_49960973", "" }, - { "nv!__gl_4a5341", "" }, - { "nv!__gl_4f4e48", "" }, - { "nv!__gl_4f8a0a", "" }, - { "nv!__gl_50299698", "" }, - { "nv!__gl_50299699", "" }, - { "nv!__gl_50361291", "" }, - { "nv!__gl_5242ae", "" }, - { "nv!__gl_53d30c", "" }, - { "nv!__gl_56347a", "" }, - { "nv!__gl_563a95f1", "" }, - { "nv!__gl_573823", "" }, - { "nv!__gl_58027529", "" }, - { "nv!__gl_5d2d63", "" }, - { "nv!__gl_5f7e3b", "" }, - { "nv!__gl_60461793", "" }, - { "nv!__gl_60d355", "" }, - { "nv!__gl_616627aa", "" }, - { "nv!__gl_62317182", "" }, - { "nv!__gl_6253fa2e", "" }, - { "nv!__gl_64100768", "" }, - { "nv!__gl_64100769", "" }, - { "nv!__gl_64100770", "" }, - { "nv!__gl_647395", "" }, - { "nv!__gl_66543234", "" }, - { "nv!__gl_67674763", "" }, - { "nv!__gl_67739784", "" }, - { "nv!__gl_68fb9c", "" }, - { "nv!__gl_69801276", "" }, - { "nv!__gl_6af9fa2f", "" }, - { "nv!__gl_6af9fa3f", "" }, - { "nv!__gl_6af9fa4f", "" }, - { "nv!__gl_6bd8c7", "" }, - { "nv!__gl_6c7691", "" }, - { "nv!__gl_6d4296ce", "" }, - { "nv!__gl_6dd7e7", "" }, - { "nv!__gl_6dd7e8", "" }, - { "nv!__gl_6fe11ec1", "" }, - { "nv!__gl_716511763", "" }, - { "nv!__gl_72504593", "" }, - { "nv!__gl_73304097", "" }, - { "nv!__gl_73314098", "" }, - { "nv!__gl_74095213", "" }, - { "nv!__gl_74095213a", "" }, - { "nv!__gl_74095213b", "" }, - { "nv!__gl_74095214", "" }, - { "nv!__gl_748f9649", "" }, - { "nv!__gl_75494732", "" }, - { "nv!__gl_78452832", "" }, - { "nv!__gl_784561", "" }, - { "nv!__gl_78e16b9c", "" }, - { "nv!__gl_79251225", "" }, - { "nv!__gl_7c128b", "" }, - { "nv!__gl_7ccd93", "" }, - { "nv!__gl_7df8d1", "" }, - { "nv!__gl_800c2310", "" }, - { "nv!__gl_80546710", "" }, - { "nv!__gl_80772310", "" }, - { "nv!__gl_808ee280", "" }, - { "nv!__gl_81131154", "" }, - { "nv!__gl_81274457", "" }, - { "nv!__gl_8292291f", "" }, - { "nv!__gl_83498426", "" }, - { "nv!__gl_84993794", "" }, - { "nv!__gl_84995585", "" }, - { "nv!__gl_84a0a0", "" }, - { "nv!__gl_852142", "" }, - { "nv!__gl_85612309", "" }, - { "nv!__gl_85612310", "" }, - { "nv!__gl_85612311", "" }, - { "nv!__gl_85612312", "" }, - { "nv!__gl_8623ff27", "" }, - { "nv!__gl_87364952", "" }, - { "nv!__gl_87f6275666", "" }, - { "nv!__gl_886748", "" }, - { "nv!__gl_89894423", "" }, - { "nv!__gl_8ad8a75", "" }, - { "nv!__gl_8ad8ad00", "" }, - { "nv!__gl_8bb815", "" }, - { "nv!__gl_8bb817", "" }, - { "nv!__gl_8bb818", "" }, - { "nv!__gl_8bb819", "" }, - { "nv!__gl_8e640cd1", "" }, - { "nv!__gl_8f34971a", "" }, - { "nv!__gl_8f773984", "" }, - { "nv!__gl_8f7a7d", "" }, - { "nv!__gl_902486209", "" }, - { "nv!__gl_90482571", "" }, - { "nv!__gl_91214835", "" }, - { "nv!__gl_912848290", "" }, - { "nv!__gl_915e56", "" }, - { "nv!__gl_92179063", "" }, - { "nv!__gl_92179064", "" }, - { "nv!__gl_92179065", "" }, - { "nv!__gl_92179066", "" }, - { "nv!__gl_92350358", "" }, - { "nv!__gl_92809063", "" }, - { "nv!__gl_92809064", "" }, - { "nv!__gl_92809065", "" }, - { "nv!__gl_92809066", "" }, - { "nv!__gl_92920143", "" }, - { "nv!__gl_93a89b12", "" }, - { "nv!__gl_93a89c0b", "" }, - { "nv!__gl_94812574", "" }, - { "nv!__gl_95282304", "" }, - { "nv!__gl_95394027", "" }, - { "nv!__gl_959b1f", "" }, - { "nv!__gl_9638af", "" }, - { "nv!__gl_96fd59", "" }, - { "nv!__gl_97f6275666", "" }, - { "nv!__gl_97f6275667", "" }, - { "nv!__gl_97f6275668", "" }, - { "nv!__gl_97f6275669", "" }, - { "nv!__gl_97f627566a", "" }, - { "nv!__gl_97f627566b", "" }, - { "nv!__gl_97f627566d", "" }, - { "nv!__gl_97f627566e", "" }, - { "nv!__gl_97f627566f", "" }, - { "nv!__gl_97f6275670", "" }, - { "nv!__gl_97f6275671", "" }, - { "nv!__gl_97f727566e", "" }, - { "nv!__gl_98480775", "" }, - { "nv!__gl_98480776", "" }, - { "nv!__gl_98480777", "" }, - { "nv!__gl_992431", "" }, - { "nv!__gl_9aa29065", "" }, - { "nv!__gl_9af32c", "" }, - { "nv!__gl_9af32d", "" }, - { "nv!__gl_9af32e", "" }, - { "nv!__gl_9c108b71", "" }, - { "nv!__gl_9f279065", "" }, - { "nv!__gl_a01bc728", "" }, - { "nv!__gl_a13b46c80", "" }, - { "nv!__gl_a22eb0", "" }, - { "nv!__gl_a2fb451e", "" }, - { "nv!__gl_a3456abe", "" }, - { "nv!__gl_a7044887", "" }, - { "nv!__gl_a7149200", "" }, - { "nv!__gl_a766215670", "" }, - { "nv!__gl_aalinegamma", "" }, - { "nv!__gl_aalinetweaks", "" }, - { "nv!__gl_ab34ee01", "" }, - { "nv!__gl_ab34ee02", "" }, - { "nv!__gl_ab34ee03", "" }, - { "nv!__gl_ac0274", "" }, - { "nv!__gl_af73c63e", "" }, - { "nv!__gl_af73c63f", "" }, - { "nv!__gl_af9927", "" }, - { "nv!__gl_afoverride", "" }, - { "nv!__gl_allocdeviceevents", "" }, - { "nv!__gl_applicationkey", "" }, - { "nv!__gl_appreturnonlybasicglsltype", "" }, - { "nv!__gl_app_softimage", "" }, - { "nv!__gl_app_supportbits2", "" }, - { "nv!__gl_assumetextureismipmappedatcreation", "" }, - { "nv!__gl_b1fb0f01", "" }, - { "nv!__gl_b3edd5", "" }, - { "nv!__gl_b40d9e03d", "" }, - { "nv!__gl_b7f6275666", "" }, - { "nv!__gl_b812c1", "" }, - { "nv!__gl_ba14ba1a", "" }, - { "nv!__gl_ba14ba1b", "" }, - { "nv!__gl_bd7559", "" }, - { "nv!__gl_bd755a", "" }, - { "nv!__gl_bd755c", "" }, - { "nv!__gl_bd755d", "" }, - { "nv!__gl_be58bb", "" }, - { "nv!__gl_be92cb", "" }, - { "nv!__gl_beefcba3", "" }, - { "nv!__gl_beefcba4", "" }, - { "nv!__gl_c023777f", "" }, - { "nv!__gl_c09dc8", "" }, - { "nv!__gl_c0d340", "" }, - { "nv!__gl_c2ff374c", "" }, - { "nv!__gl_c5e9d7a3", "" }, - { "nv!__gl_c5e9d7a4", "" }, - { "nv!__gl_c5e9d7b4", "" }, - { "nv!__gl_c618f9", "" }, - { "nv!__gl_ca345840", "" }, - { "nv!__gl_cachedisable", "" }, - { "nv!__gl_channelpriorityoverride", "" }, - { "nv!__gl_cleardatastorevidmem", "" }, - { "nv!__gl_cmdbufmemoryspaceenables", "" }, - { "nv!__gl_cmdbufminwords", "" }, - { "nv!__gl_cmdbufsizewords", "" }, - { "nv!__gl_conformantblitframebufferscissor", "" }, - { "nv!__gl_conformantincompletetextures", "" }, - { "nv!__gl_copybuffermethod", "" }, - { "nv!__gl_cubemapaniso", "" }, - { "nv!__gl_cubemapfiltering", "" }, - { "nv!__gl_d0e9a4d7", "" }, - { "nv!__gl_d13733f12", "" }, - { "nv!__gl_d1b399", "" }, - { "nv!__gl_d2983c32", "" }, - { "nv!__gl_d2983c33", "" }, - { "nv!__gl_d2e71b", "" }, - { "nv!__gl_d377dc", "" }, - { "nv!__gl_d377dd", "" }, - { "nv!__gl_d489f4", "" }, - { "nv!__gl_d4bce1", "" }, - { "nv!__gl_d518cb", "" }, - { "nv!__gl_d518cd", "" }, - { "nv!__gl_d518ce", "" }, - { "nv!__gl_d518d0", "" }, - { "nv!__gl_d518d1", "" }, - { "nv!__gl_d518d2", "" }, - { "nv!__gl_d518d3", "" }, - { "nv!__gl_d518d4", "" }, - { "nv!__gl_d518d5", "" }, - { "nv!__gl_d59eda", "" }, - { "nv!__gl_d83cbd", "" }, - { "nv!__gl_d8e777", "" }, - { "nv!__gl_debug_level", "" }, - { "nv!__gl_debug_mask", "" }, - { "nv!__gl_debug_options", "" }, - { "nv!__gl_devshmpageableallocations", "" }, - { "nv!__gl_df1f9812", "" }, - { "nv!__gl_df783c", "" }, - { "nv!__gl_diagenable", "" }, - { "nv!__gl_disallowcemask", "" }, - { "nv!__gl_disallowz16", "" }, - { "nv!__gl_dlmemoryspaceenables", "" }, - { "nv!__gl_e0bfec", "" }, - { "nv!__gl_e433456d", "" }, - { "nv!__gl_e435563f", "" }, - { "nv!__gl_e4cd9c", "" }, - { "nv!__gl_e5c972", "" }, - { "nv!__gl_e639ef", "" }, - { "nv!__gl_e802af", "" }, - { "nv!__gl_eae964", "" }, - { "nv!__gl_earlytexturehwallocation", "" }, - { "nv!__gl_eb92a3", "" }, - { "nv!__gl_ebca56", "" }, - { "nv!__gl_expert_detail_level", "" }, - { "nv!__gl_expert_output_mask", "" }, - { "nv!__gl_expert_report_mask", "" }, - { "nv!__gl_extensionstringnvarch", "" }, - { "nv!__gl_extensionstringversion", "" }, - { "nv!__gl_f00f1938", "" }, - { "nv!__gl_f10736", "" }, - { "nv!__gl_f1846870", "" }, - { "nv!__gl_f33bc370", "" }, - { "nv!__gl_f392a874", "" }, - { "nv!__gl_f49ae8", "" }, - { "nv!__gl_fa345cce", "" }, - { "nv!__gl_fa35cc4", "" }, - { "nv!__gl_faa14a", "" }, - { "nv!__gl_faf8a723", "" }, - { "nv!__gl_fastgs", "" }, - { "nv!__gl_fbf4ac45", "" }, - { "nv!__gl_fbo_blit_ignore_srgb", "" }, - { "nv!__gl_fc64c7", "" }, - { "nv!__gl_ff54ec97", "" }, - { "nv!__gl_ff54ec98", "" }, - { "nv!__gl_forceexitprocessdetach", "" }, - { "nv!__gl_forcerequestedesversion", "" }, - { "nv!__gl_glsynctovblank", "" }, - { "nv!__gl_gvitimeoutcontrol", "" }, - { "nv!__gl_hcctrl", "" }, - { "nv!__gl_hwstate_per_ctx", "" }, - { "nv!__gl_machinecachelimit", "" }, - { "nv!__gl_maxframesallowed", "" }, - { "nv!__gl_memmgrcachedalloclimit", "" }, - { "nv!__gl_memmgrcachedalloclimitratio", "" }, - { "nv!__gl_memmgrsysheapalloclimit", "" }, - { "nv!__gl_memmgrsysheapalloclimitratio", "" }, - { "nv!__gl_memmgrvidheapalloclimit", "" }, - { "nv!__gl_mosaic_clip_to_subdev", "" }, - { "nv!__gl_mosaic_clip_to_subdev_h_overlap", "" }, - { "nv!__gl_mosaic_clip_to_subdev_v_overlap", "" }, - { "nv!__gl_overlaymergeblittimerms", "" }, - { "nv!__gl_perfmon_mode", "" }, - { "nv!__gl_pixbar_mode", "" }, - { "nv!__gl_qualityenhancements", "" }, - { "nv!__gl_r27s18q28", "" }, - { "nv!__gl_r2d7c1d8", "" }, - { "nv!__gl_renderer", "" }, - { "nv!__gl_renderqualityflags", "" }, - { "nv!__gl_s3tcquality", "" }, - { "nv!__gl_shaderatomics", "" }, - { "nv!__gl_shadercacheinitsize", "" }, - { "nv!__gl_shader_disk_cache_path", "" }, - { "nv!__gl_shader_disk_cache_read_only", "" }, - { "nv!__gl_shaderobjects", "" }, - { "nv!__gl_shaderportabilitywarnings", "" }, - { "nv!__gl_shaderwarningsaserrors", "" }, - { "nv!__gl_skiptexturehostcopies", "" }, - { "nv!__glslc_debug_level", "" }, - { "nv!__glslc_debug_mask", "" }, - { "nv!__glslc_debug_options", "" }, - { "nv!__glslc_debug_filename", "" }, - { "nv!__gl_sli_dli_control", "" }, - { "nv!__gl_sparsetexture", "" }, - { "nv!__gl_spinlooptimeout", "" }, - { "nv!__gl_sync_to_vblank", "" }, - { "nv!glsynctovblank", "" }, - { "nv!__gl_sysheapreuseratio", "" }, - { "nv!__gl_sysmemtexturepromotion", "" }, - { "nv!__gl_targetflushcount", "" }, - { "nv!__gl_tearingfreeswappresent", "" }, - { "nv!__gl_texclampbehavior", "" }, - { "nv!__gl_texlodbias", "" }, - { "nv!__gl_texmemoryspaceenables", "" }, - { "nv!__gl_textureprecache", "" }, - { "nv!__gl_threadcontrol", "" }, - { "nv!__gl_threadcontrol2", "" }, - { "nv!__gl_usegvievents", "" }, - { "nv!__gl_vbomemoryspaceenables", "" }, - { "nv!__gl_vertexlimit", "" }, - { "nv!__gl_vidheapreuseratio", "" }, - { "nv!__gl_vpipe", "" }, - { "nv!__gl_vpipeformatbloatlimit", "" }, - { "nv!__gl_wglmessageboxonabort", "" }, - { "nv!__gl_writeinfolog", "" }, - { "nv!__gl_writeprogramobjectassembly", "" }, - { "nv!__gl_writeprogramobjectsource", "" }, - { "nv!__gl_xnvadapterpresent", "" }, - { "nv!__gl_yield", "" }, - { "nv!__gl_yieldfunction", "" }, - { "nv!__gl_yieldfunctionfast", "" }, - { "nv!__gl_yieldfunctionslow", "" }, - { "nv!__gl_yieldfunctionwaitfordcqueue", "" }, - { "nv!__gl_yieldfunctionwaitforframe", "" }, - { "nv!__gl_yieldfunctionwaitforgpu", "" }, - { "nv!__gl_zbctableaddhysteresis", "" }, - { "nv!gpu_debug_mode", "" }, - { "nv!gpu_stay_on", "" }, - { "nv!gpu_timeout_ms_max", "" }, - { "nv!gvitimeoutcontrol", "" }, - { "nv!hcctrl", "" }, - { "nv!hwstate_per_ctx", "" }, - { "nv!libandroid_enable_log", "" }, - { "nv!machinecachelimit", "" }, - { "nv!maxframesallowed", "" }, - { "nv!media.aac_51_output_enabled", "" }, - { "nv!memmgrcachedalloclimit", "" }, - { "nv!memmgrcachedalloclimitratio", "" }, - { "nv!memmgrsysheapalloclimit", "" }, - { "nv!memmgrsysheapalloclimitratio", "" }, - { "nv!memmgrvidheapalloclimit", "" }, - { "nv!mosaic_clip_to_subdev", "" }, - { "nv!mosaic_clip_to_subdev_h_overlap", "" }, - { "nv!mosaic_clip_to_subdev_v_overlap", "" }, - { "nv!nvblit.dump", "" }, - { "nv!nvblit.profile", "" }, - { "nv!nvblit.twod", "" }, - { "nv!nvblit.vic", "" }, - { "nv!nvddk_vic_prevent_use", "" }, - { "nv!nv_decompression", "" }, - { "nv!nvdisp_bl_ctrl", "0" }, - { "nv!nvdisp_debug_mask", "" }, - { "nv!nvdisp_enable_ts", "0" }, - { "nv!nvhdcp_timeout_ms", "12000" }, - { "nv!nvhdcp_max_retries", "5" }, - { "nv!nv_emc_dvfs_test", "" }, - { "nv!nv_emc_init_rate_hz", "" }, - { "nv!nv_gmmu_va_page_split", "" }, - { "nv!nv_gmmu_va_range", "" }, - { "nv!nvhost_debug_mask", "" }, - { "nv!nvidia.hwc.dump_config", "" }, - { "nv!nvidia.hwc.dump_layerlist", "" }, - { "nv!nvidia.hwc.dump_windows", "" }, - { "nv!nvidia.hwc.enable_disp_trans", "" }, - { "nv!nvidia.hwc.ftrace_enable", "" }, - { "nv!nvidia.hwc.hdcp_enable", "" }, - { "nv!nvidia.hwc.hidden_window_mask0", "" }, - { "nv!nvidia.hwc.hidden_window_mask1", "" }, - { "nv!nvidia.hwc.immediate_modeset", "" }, - { "nv!nvidia.hwc.imp_enable", "" }, - { "nv!nvidia.hwc.no_egl", "" }, - { "nv!nvidia.hwc.no_scratchblit", "" }, - { "nv!nvidia.hwc.no_vic", "" }, - { "nv!nvidia.hwc.null_display", "" }, - { "nv!nvidia.hwc.scan_props", "" }, - { "nv!nvidia.hwc.swap_interval", "" }, - { "nv!nvidia.hwc.war_1515812", "0" }, - { "nv!nvmap_debug_mask", "" }, - { "nv!nv_memory_profiler", "" }, - { "nv!nvnflinger_enable_log", "" }, - { "nv!nvnflinger_flip_policy", "" }, - { "nv!nvnflinger_hotplug_autoswitch", "0" }, - { "nv!nvnflinger_prefer_primary_layer", "0" }, - { "nv!nvnflinger_service_priority", "" }, - { "nv!nvnflinger_service_threads", "" }, - { "nv!nvnflinger_swap_interval", "" }, - { "nv!nvnflinger_track_perf", "" }, - { "nv!nvnflinger_virtualdisplay_policy", "60hz" }, - { "nv!nvn_no_vsync_capability", false }, - { "nv!nvn_through_opengl", "" }, - { "nv!nv_pllcx_always_on", "" }, - { "nv!nv_pllcx_safe_div", "" }, - { "nv!nvrm_gpu_channel_interleave", "" }, - { "nv!nvrm_gpu_channel_priority", "" }, - { "nv!nvrm_gpu_channel_timeslice", "" }, - { "nv!nvrm_gpu_default_device_index", "" }, - { "nv!nvrm_gpu_dummy", "" }, - { "nv!nvrm_gpu_help", "" }, - { "nv!nvrm_gpu_nvgpu_disable", "" }, - { "nv!nvrm_gpu_nvgpu_do_nfa_partial_map", "" }, - { "nv!nvrm_gpu_nvgpu_ecc_overrides", "" }, - { "nv!nvrm_gpu_nvgpu_no_as_get_va_regions", "" }, - { "nv!nvrm_gpu_nvgpu_no_channel_abort", "" }, - { "nv!nvrm_gpu_nvgpu_no_cyclestats", "" }, - { "nv!nvrm_gpu_nvgpu_no_fixed", "" }, - { "nv!nvrm_gpu_nvgpu_no_gpu_characteristics", "" }, - { "nv!nvrm_gpu_nvgpu_no_ioctl_mutex", "" }, - { "nv!nvrm_gpu_nvgpu_no_map_buffer_ex", "" }, - { "nv!nvrm_gpu_nvgpu_no_robustness", "" }, - { "nv!nvrm_gpu_nvgpu_no_sparse", "" }, - { "nv!nvrm_gpu_nvgpu_no_syncpoints", "" }, - { "nv!nvrm_gpu_nvgpu_no_tsg", "" }, - { "nv!nvrm_gpu_nvgpu_no_zbc", "" }, - { "nv!nvrm_gpu_nvgpu_no_zcull", "" }, - { "nv!nvrm_gpu_nvgpu_wrap_channels_in_tsgs", "" }, - { "nv!nvrm_gpu_prevent_use", "" }, - { "nv!nvrm_gpu_trace", "" }, - { "nv!nvsched_debug_mask", "" }, - { "nv!nvsched_force_enable", "" }, - { "nv!nvsched_force_log", "" }, - { "nv!nv_usb_plls_hw_ctrl", "" }, - { "nv!nv_winsys", "" }, - { "nv!nvwsi_dump", "" }, - { "nv!nvwsi_fill", "" }, - { "nv!ogl_", "" }, - { "nv!ogl_0356afd0", "" }, - { "nv!ogl_0356afd1", "" }, - { "nv!ogl_0356afd2", "" }, - { "nv!ogl_0356afd3", "" }, - { "nv!ogl_0x923dc0", "" }, - { "nv!ogl_0x923dc1", "" }, - { "nv!ogl_0x923dc2", "" }, - { "nv!ogl_0x923dc3", "" }, - { "nv!ogl_0x923dc4", "" }, - { "nv!ogl_0x923dd3", "" }, - { "nv!ogl_0x9abdc5", "" }, - { "nv!ogl_0x9abdc6", "" }, - { "nv!ogl_0xbd10fb", "" }, - { "nv!ogl_0xce2348", "" }, - { "nv!ogl_10261989", "" }, - { "nv!ogl_1042d483", "" }, - { "nv!ogl_10572898", "" }, - { "nv!ogl_115631", "" }, - { "nv!ogl_12950094", "" }, - { "nv!ogl_1314f311", "" }, - { "nv!ogl_1314f312", "" }, - { "nv!ogl_13279512", "" }, - { "nv!ogl_13813496", "" }, - { "nv!ogl_14507179", "" }, - { "nv!ogl_15694569", "" }, - { "nv!ogl_16936964", "" }, - { "nv!ogl_17aa230c", "" }, - { "nv!ogl_182054", "" }, - { "nv!ogl_18273275", "" }, - { "nv!ogl_18273276", "" }, - { "nv!ogl_1854d03b", "" }, - { "nv!ogl_18add00d", "" }, - { "nv!ogl_19156670", "" }, - { "nv!ogl_19286545", "" }, - { "nv!ogl_1a298e9f", "" }, - { "nv!ogl_1acf43fe", "" }, - { "nv!ogl_1bda43fe", "" }, - { "nv!ogl_1c3b92", "" }, - { "nv!ogl_21509920", "" }, - { "nv!ogl_215323457", "" }, - { "nv!ogl_2165ad", "" }, - { "nv!ogl_2165ae", "" }, - { "nv!ogl_21be9c", "" }, - { "nv!ogl_233264316", "" }, - { "nv!ogl_234557580", "" }, - { "nv!ogl_23cd0e", "" }, - { "nv!ogl_24189123", "" }, - { "nv!ogl_2443266", "" }, - { "nv!ogl_25025519", "" }, - { "nv!ogl_255e39", "" }, - { "nv!ogl_2583364", "" }, - { "nv!ogl_2888c1", "" }, - { "nv!ogl_28ca3e", "" }, - { "nv!ogl_29871243", "" }, - { "nv!ogl_2a1f64", "" }, - { "nv!ogl_2dc432", "" }, - { "nv!ogl_2de437", "" }, - { "nv!ogl_2f3bb89c", "" }, - { "nv!ogl_2fd652", "" }, - { "nv!ogl_3001ac", "" }, - { "nv!ogl_31298772", "" }, - { "nv!ogl_313233", "" }, - { "nv!ogl_31f7d603", "" }, - { "nv!ogl_320ce4", "" }, - { "nv!ogl_32153248", "" }, - { "nv!ogl_32153249", "" }, - { "nv!ogl_335bca", "" }, - { "nv!ogl_342abb", "" }, - { "nv!ogl_34dfe6", "" }, - { "nv!ogl_34dfe7", "" }, - { "nv!ogl_34dfe8", "" }, - { "nv!ogl_34dfe9", "" }, - { "nv!ogl_35201578", "" }, - { "nv!ogl_359278", "" }, - { "nv!ogl_37f53a", "" }, - { "nv!ogl_38144972", "" }, - { "nv!ogl_38542646", "" }, - { "nv!ogl_3b74c9", "" }, - { "nv!ogl_3c136f", "" }, - { "nv!ogl_3cf72823", "" }, - { "nv!ogl_3d7af029", "" }, - { "nv!ogl_3ff34782", "" }, - { "nv!ogl_4129618", "" }, - { "nv!ogl_4189fac3", "" }, - { "nv!ogl_420bd4", "" }, - { "nv!ogl_42a699", "" }, - { "nv!ogl_441369", "" }, - { "nv!ogl_4458713e", "" }, - { "nv!ogl_4554b6", "" }, - { "nv!ogl_457425", "" }, - { "nv!ogl_4603b207", "" }, - { "nv!ogl_46574957", "" }, - { "nv!ogl_46574958", "" }, - { "nv!ogl_46813529", "" }, - { "nv!ogl_46f1e13d", "" }, - { "nv!ogl_47534c43", "" }, - { "nv!ogl_48550336", "" }, - { "nv!ogl_48576893", "" }, - { "nv!ogl_48576894", "" }, - { "nv!ogl_4889ac02", "" }, - { "nv!ogl_49005740", "" }, - { "nv!ogl_49867584", "" }, - { "nv!ogl_49960973", "" }, - { "nv!ogl_4a5341", "" }, - { "nv!ogl_4f4e48", "" }, - { "nv!ogl_4f8a0a", "" }, - { "nv!ogl_50299698", "" }, - { "nv!ogl_50299699", "" }, - { "nv!ogl_50361291", "" }, - { "nv!ogl_5242ae", "" }, - { "nv!ogl_53d30c", "" }, - { "nv!ogl_56347a", "" }, - { "nv!ogl_563a95f1", "" }, - { "nv!ogl_573823", "" }, - { "nv!ogl_58027529", "" }, - { "nv!ogl_5d2d63", "" }, - { "nv!ogl_5f7e3b", "" }, - { "nv!ogl_60461793", "" }, - { "nv!ogl_60d355", "" }, - { "nv!ogl_616627aa", "" }, - { "nv!ogl_62317182", "" }, - { "nv!ogl_6253fa2e", "" }, - { "nv!ogl_64100768", "" }, - { "nv!ogl_64100769", "" }, - { "nv!ogl_64100770", "" }, - { "nv!ogl_647395", "" }, - { "nv!ogl_66543234", "" }, - { "nv!ogl_67674763", "" }, - { "nv!ogl_67739784", "" }, - { "nv!ogl_68fb9c", "" }, - { "nv!ogl_69801276", "" }, - { "nv!ogl_6af9fa2f", "" }, - { "nv!ogl_6af9fa3f", "" }, - { "nv!ogl_6af9fa4f", "" }, - { "nv!ogl_6bd8c7", "" }, - { "nv!ogl_6c7691", "" }, - { "nv!ogl_6d4296ce", "" }, - { "nv!ogl_6dd7e7", "" }, - { "nv!ogl_6dd7e8", "" }, - { "nv!ogl_6fe11ec1", "" }, - { "nv!ogl_716511763", "" }, - { "nv!ogl_72504593", "" }, - { "nv!ogl_73304097", "" }, - { "nv!ogl_73314098", "" }, - { "nv!ogl_74095213", "" }, - { "nv!ogl_74095213a", "" }, - { "nv!ogl_74095213b", "" }, - { "nv!ogl_74095214", "" }, - { "nv!ogl_748f9649", "" }, - { "nv!ogl_75494732", "" }, - { "nv!ogl_78452832", "" }, - { "nv!ogl_784561", "" }, - { "nv!ogl_78e16b9c", "" }, - { "nv!ogl_79251225", "" }, - { "nv!ogl_7c128b", "" }, - { "nv!ogl_7ccd93", "" }, - { "nv!ogl_7df8d1", "" }, - { "nv!ogl_800c2310", "" }, - { "nv!ogl_80546710", "" }, - { "nv!ogl_80772310", "" }, - { "nv!ogl_808ee280", "" }, - { "nv!ogl_81131154", "" }, - { "nv!ogl_81274457", "" }, - { "nv!ogl_8292291f", "" }, - { "nv!ogl_83498426", "" }, - { "nv!ogl_84993794", "" }, - { "nv!ogl_84995585", "" }, - { "nv!ogl_84a0a0", "" }, - { "nv!ogl_852142", "" }, - { "nv!ogl_85612309", "" }, - { "nv!ogl_85612310", "" }, - { "nv!ogl_85612311", "" }, - { "nv!ogl_85612312", "" }, - { "nv!ogl_8623ff27", "" }, - { "nv!ogl_87364952", "" }, - { "nv!ogl_87f6275666", "" }, - { "nv!ogl_886748", "" }, - { "nv!ogl_89894423", "" }, - { "nv!ogl_8ad8a75", "" }, - { "nv!ogl_8ad8ad00", "" }, - { "nv!ogl_8bb815", "" }, - { "nv!ogl_8bb817", "" }, - { "nv!ogl_8bb818", "" }, - { "nv!ogl_8bb819", "" }, - { "nv!ogl_8e640cd1", "" }, - { "nv!ogl_8f34971a", "" }, - { "nv!ogl_8f773984", "" }, - { "nv!ogl_8f7a7d", "" }, - { "nv!ogl_902486209", "" }, - { "nv!ogl_90482571", "" }, - { "nv!ogl_91214835", "" }, - { "nv!ogl_912848290", "" }, - { "nv!ogl_915e56", "" }, - { "nv!ogl_92179063", "" }, - { "nv!ogl_92179064", "" }, - { "nv!ogl_92179065", "" }, - { "nv!ogl_92179066", "" }, - { "nv!ogl_92350358", "" }, - { "nv!ogl_92809063", "" }, - { "nv!ogl_92809064", "" }, - { "nv!ogl_92809065", "" }, - { "nv!ogl_92809066", "" }, - { "nv!ogl_92920143", "" }, - { "nv!ogl_93a89b12", "" }, - { "nv!ogl_93a89c0b", "" }, - { "nv!ogl_94812574", "" }, - { "nv!ogl_95282304", "" }, - { "nv!ogl_95394027", "" }, - { "nv!ogl_959b1f", "" }, - { "nv!ogl_9638af", "" }, - { "nv!ogl_96fd59", "" }, - { "nv!ogl_97f6275666", "" }, - { "nv!ogl_97f6275667", "" }, - { "nv!ogl_97f6275668", "" }, - { "nv!ogl_97f6275669", "" }, - { "nv!ogl_97f627566a", "" }, - { "nv!ogl_97f627566b", "" }, - { "nv!ogl_97f627566d", "" }, - { "nv!ogl_97f627566e", "" }, - { "nv!ogl_97f627566f", "" }, - { "nv!ogl_97f6275670", "" }, - { "nv!ogl_97f6275671", "" }, - { "nv!ogl_97f727566e", "" }, - { "nv!ogl_98480775", "" }, - { "nv!ogl_98480776", "" }, - { "nv!ogl_98480777", "" }, - { "nv!ogl_992431", "" }, - { "nv!ogl_9aa29065", "" }, - { "nv!ogl_9af32c", "" }, - { "nv!ogl_9af32d", "" }, - { "nv!ogl_9af32e", "" }, - { "nv!ogl_9c108b71", "" }, - { "nv!ogl_9f279065", "" }, - { "nv!ogl_a01bc728", "" }, - { "nv!ogl_a13b46c80", "" }, - { "nv!ogl_a22eb0", "" }, - { "nv!ogl_a2fb451e", "" }, - { "nv!ogl_a3456abe", "" }, - { "nv!ogl_a7044887", "" }, - { "nv!ogl_a7149200", "" }, - { "nv!ogl_a766215670", "" }, - { "nv!ogl_aalinegamma", "" }, - { "nv!ogl_aalinetweaks", "" }, - { "nv!ogl_ab34ee01", "" }, - { "nv!ogl_ab34ee02", "" }, - { "nv!ogl_ab34ee03", "" }, - { "nv!ogl_ac0274", "" }, - { "nv!ogl_af73c63e", "" }, - { "nv!ogl_af73c63f", "" }, - { "nv!ogl_af9927", "" }, - { "nv!ogl_afoverride", "" }, - { "nv!ogl_allocdeviceevents", "" }, - { "nv!ogl_applicationkey", "" }, - { "nv!ogl_appreturnonlybasicglsltype", "" }, - { "nv!ogl_app_softimage", "" }, - { "nv!ogl_app_supportbits2", "" }, - { "nv!ogl_assumetextureismipmappedatcreation", "" }, - { "nv!ogl_b1fb0f01", "" }, - { "nv!ogl_b3edd5", "" }, - { "nv!ogl_b40d9e03d", "" }, - { "nv!ogl_b7f6275666", "" }, - { "nv!ogl_b812c1", "" }, - { "nv!ogl_ba14ba1a", "" }, - { "nv!ogl_ba14ba1b", "" }, - { "nv!ogl_bd7559", "" }, - { "nv!ogl_bd755a", "" }, - { "nv!ogl_bd755c", "" }, - { "nv!ogl_bd755d", "" }, - { "nv!ogl_be58bb", "" }, - { "nv!ogl_be92cb", "" }, - { "nv!ogl_beefcba3", "" }, - { "nv!ogl_beefcba4", "" }, - { "nv!ogl_c023777f", "" }, - { "nv!ogl_c09dc8", "" }, - { "nv!ogl_c0d340", "" }, - { "nv!ogl_c2ff374c", "" }, - { "nv!ogl_c5e9d7a3", "" }, - { "nv!ogl_c5e9d7a4", "" }, - { "nv!ogl_c5e9d7b4", "" }, - { "nv!ogl_c618f9", "" }, - { "nv!ogl_ca345840", "" }, - { "nv!ogl_cachedisable", "" }, - { "nv!ogl_channelpriorityoverride", "" }, - { "nv!ogl_cleardatastorevidmem", "" }, - { "nv!ogl_cmdbufmemoryspaceenables", "" }, - { "nv!ogl_cmdbufminwords", "" }, - { "nv!ogl_cmdbufsizewords", "" }, - { "nv!ogl_conformantblitframebufferscissor", "" }, - { "nv!ogl_conformantincompletetextures", "" }, - { "nv!ogl_copybuffermethod", "" }, - { "nv!ogl_cubemapaniso", "" }, - { "nv!ogl_cubemapfiltering", "" }, - { "nv!ogl_d0e9a4d7", "" }, - { "nv!ogl_d13733f12", "" }, - { "nv!ogl_d1b399", "" }, - { "nv!ogl_d2983c32", "" }, - { "nv!ogl_d2983c33", "" }, - { "nv!ogl_d2e71b", "" }, - { "nv!ogl_d377dc", "" }, - { "nv!ogl_d377dd", "" }, - { "nv!ogl_d489f4", "" }, - { "nv!ogl_d4bce1", "" }, - { "nv!ogl_d518cb", "" }, - { "nv!ogl_d518cd", "" }, - { "nv!ogl_d518ce", "" }, - { "nv!ogl_d518d0", "" }, - { "nv!ogl_d518d1", "" }, - { "nv!ogl_d518d2", "" }, - { "nv!ogl_d518d3", "" }, - { "nv!ogl_d518d4", "" }, - { "nv!ogl_d518d5", "" }, - { "nv!ogl_d59eda", "" }, - { "nv!ogl_d83cbd", "" }, - { "nv!ogl_d8e777", "" }, - { "nv!ogl_debug_level", "" }, - { "nv!ogl_debug_mask", "" }, - { "nv!ogl_debug_options", "" }, - { "nv!ogl_devshmpageableallocations", "" }, - { "nv!ogl_df1f9812", "" }, - { "nv!ogl_df783c", "" }, - { "nv!ogl_diagenable", "" }, - { "nv!ogl_disallowcemask", "" }, - { "nv!ogl_disallowz16", "" }, - { "nv!ogl_dlmemoryspaceenables", "" }, - { "nv!ogl_e0bfec", "" }, - { "nv!ogl_e433456d", "" }, - { "nv!ogl_e435563f", "" }, - { "nv!ogl_e4cd9c", "" }, - { "nv!ogl_e5c972", "" }, - { "nv!ogl_e639ef", "" }, - { "nv!ogl_e802af", "" }, - { "nv!ogl_eae964", "" }, - { "nv!ogl_earlytexturehwallocation", "" }, - { "nv!ogl_eb92a3", "" }, - { "nv!ogl_ebca56", "" }, - { "nv!ogl_expert_detail_level", "" }, - { "nv!ogl_expert_output_mask", "" }, - { "nv!ogl_expert_report_mask", "" }, - { "nv!ogl_extensionstringnvarch", "" }, - { "nv!ogl_extensionstringversion", "" }, - { "nv!ogl_f00f1938", "" }, - { "nv!ogl_f10736", "" }, - { "nv!ogl_f1846870", "" }, - { "nv!ogl_f33bc370", "" }, - { "nv!ogl_f392a874", "" }, - { "nv!ogl_f49ae8", "" }, - { "nv!ogl_fa345cce", "" }, - { "nv!ogl_fa35cc4", "" }, - { "nv!ogl_faa14a", "" }, - { "nv!ogl_faf8a723", "" }, - { "nv!ogl_fastgs", "" }, - { "nv!ogl_fbf4ac45", "" }, - { "nv!ogl_fbo_blit_ignore_srgb", "" }, - { "nv!ogl_fc64c7", "" }, - { "nv!ogl_ff54ec97", "" }, - { "nv!ogl_ff54ec98", "" }, - { "nv!ogl_forceexitprocessdetach", "" }, - { "nv!ogl_forcerequestedesversion", "" }, - { "nv!ogl_glsynctovblank", "" }, - { "nv!ogl_gvitimeoutcontrol", "" }, - { "nv!ogl_hcctrl", "" }, - { "nv!ogl_hwstate_per_ctx", "" }, - { "nv!ogl_machinecachelimit", "" }, - { "nv!ogl_maxframesallowed", "" }, - { "nv!ogl_memmgrcachedalloclimit", "" }, - { "nv!ogl_memmgrcachedalloclimitratio", "" }, - { "nv!ogl_memmgrsysheapalloclimit", "" }, - { "nv!ogl_memmgrsysheapalloclimitratio", "" }, - { "nv!ogl_memmgrvidheapalloclimit", "" }, - { "nv!ogl_mosaic_clip_to_subdev", "" }, - { "nv!ogl_mosaic_clip_to_subdev_h_overlap", "" }, - { "nv!ogl_mosaic_clip_to_subdev_v_overlap", "" }, - { "nv!ogl_overlaymergeblittimerms", "" }, - { "nv!ogl_perfmon_mode", "" }, - { "nv!ogl_pixbar_mode", "" }, - { "nv!ogl_qualityenhancements", "" }, - { "nv!ogl_r27s18q28", "" }, - { "nv!ogl_r2d7c1d8", "" }, - { "nv!ogl_renderer", "" }, - { "nv!ogl_renderqualityflags", "" }, - { "nv!ogl_s3tcquality", "" }, - { "nv!ogl_shaderatomics", "" }, - { "nv!ogl_shadercacheinitsize", "" }, - { "nv!ogl_shader_disk_cache_path", "" }, - { "nv!ogl_shader_disk_cache_read_only", "" }, - { "nv!ogl_shaderobjects", "" }, - { "nv!ogl_shaderportabilitywarnings", "" }, - { "nv!ogl_shaderwarningsaserrors", "" }, - { "nv!ogl_skiptexturehostcopies", "" }, - { "nv!ogl_sli_dli_control", "" }, - { "nv!ogl_sparsetexture", "" }, - { "nv!ogl_spinlooptimeout", "" }, - { "nv!ogl_sync_to_vblank", "" }, - { "nv!ogl_sysheapreuseratio", "" }, - { "nv!ogl_sysmemtexturepromotion", "" }, - { "nv!ogl_targetflushcount", "" }, - { "nv!ogl_tearingfreeswappresent", "" }, - { "nv!ogl_texclampbehavior", "" }, - { "nv!ogl_texlodbias", "" }, - { "nv!ogl_texmemoryspaceenables", "" }, - { "nv!ogl_textureprecache", "" }, - { "nv!ogl_threadcontrol", "" }, - { "nv!ogl_threadcontrol2", "" }, - { "nv!ogl_usegvievents", "" }, - { "nv!ogl_vbomemoryspaceenables", "" }, - { "nv!ogl_vertexlimit", "" }, - { "nv!ogl_vidheapreuseratio", "" }, - { "nv!ogl_vpipe", "" }, - { "nv!ogl_vpipeformatbloatlimit", "" }, - { "nv!ogl_wglmessageboxonabort", "" }, - { "nv!ogl_writeinfolog", "" }, - { "nv!ogl_writeprogramobjectassembly", "" }, - { "nv!ogl_writeprogramobjectsource", "" }, - { "nv!ogl_xnvadapterpresent", "" }, - { "nv!ogl_yield", "" }, - { "nv!ogl_yieldfunction", "" }, - { "nv!ogl_yieldfunctionfast", "" }, - { "nv!ogl_yieldfunctionslow", "" }, - { "nv!ogl_yieldfunctionwaitfordcqueue", "" }, - { "nv!ogl_yieldfunctionwaitforframe", "" }, - { "nv!ogl_yieldfunctionwaitforgpu", "" }, - { "nv!ogl_zbctableaddhysteresis", "" }, - { "nv!overlaymergeblittimerms", "" }, - { "nv!perfmon_mode", "" }, - { "nv!persist.sys.display.resolution", "" }, - { "nv!persist.tegra.composite.fallb", "" }, - { "nv!persist.tegra.composite.policy", "" }, - { "nv!persist.tegra.composite.range", "" }, - { "nv!persist.tegra.compositor", "" }, - { "nv!persist.tegra.compositor.virt", "" }, - { "nv!persist.tegra.compression", "" }, - { "nv!persist.tegra.cursor.enable", "" }, - { "nv!persist.tegra.didim.enable", "" }, - { "nv!persist.tegra.didim.normal", "" }, - { "nv!persist.tegra.didim.video", "" }, - { "nv!persist.tegra.disp.heads", "" }, - { "nv!persist.tegra.gamma_correction", "" }, - { "nv!persist.tegra.gpu_mapping_cache", "" }, - { "nv!persist.tegra.grlayout", "" }, - { "nv!persist.tegra.hdmi.2020.10", "" }, - { "nv!persist.tegra.hdmi.2020.fake", "" }, - { "nv!persist.tegra.hdmi.2020.force", "" }, - { "nv!persist.tegra.hdmi.autorotate", "" }, - { "nv!persist.tegra.hdmi.hdr.fake", "" }, - { "nv!persist.tegra.hdmi.ignore_ratio", "" }, - { "nv!persist.tegra.hdmi.limit.clock", "" }, - { "nv!persist.tegra.hdmi.only_16_9", "" }, - { "nv!persist.tegra.hdmi.range", "" }, - { "nv!persist.tegra.hdmi.resolution", "" }, - { "nv!persist.tegra.hdmi.underscan", "" }, - { "nv!persist.tegra.hdmi.yuv.422", "" }, - { "nv!persist.tegra.hdmi.yuv.444", "" }, - { "nv!persist.tegra.hdmi.yuv.enable", "" }, - { "nv!persist.tegra.hdmi.yuv.force", "" }, - { "nv!persist.tegra.hwc.nvdc", "" }, - { "nv!persist.tegra.idle.minimum_fps", "" }, - { "nv!persist.tegra.panel.rotation", "" }, - { "nv!persist.tegra.scan_props", "" }, - { "nv!persist.tegra.stb.mode", "" }, - { "nv!persist.tegra.zbc_override", "" }, - { "nv!pixbar_mode", "" }, - { "nv!qualityenhancements", "" }, - { "nv!r27s18q28", "" }, - { "nv!r2d7c1d8", "" }, - { "nv!renderer", "" }, - { "nv!renderqualityflags", "" }, - { "nv!rmos_debug_mask", "" }, - { "nv!rmos_set_production_mode", "" }, - { "nv!s3tcquality", "" }, - { "nv!shaderatomics", "" }, - { "nv!shadercacheinitsize", "" }, - { "nv!shader_disk_cache_path", "" }, - { "nv!shader_disk_cache_read_only", "" }, - { "nv!shaderobjects", "" }, - { "nv!shaderportabilitywarnings", "" }, - { "nv!shaderwarningsaserrors", "" }, - { "nv!skiptexturehostcopies", "" }, - { "nv!sli_dli_control", "" }, - { "nv!sparsetexture", "" }, - { "nv!spinlooptimeout", "" }, - { "nv!sync_to_vblank", "" }, - { "nv!sysheapreuseratio", "" }, - { "nv!sysmemtexturepromotion", "" }, - { "nv!targetflushcount", "" }, - { "nv!tearingfreeswappresent", "" }, - { "nv!tegra.refresh", "" }, - { "nv!texclampbehavior", "" }, - { "nv!texlodbias", "" }, - { "nv!texmemoryspaceenables", "" }, - { "nv!textureprecache", "" }, - { "nv!threadcontrol", "" }, - { "nv!threadcontrol2", "" }, - { "nv!tvmr.avp.logs", "" }, - { "nv!tvmr.buffer.logs", "" }, - { "nv!tvmr.dec.prof", "" }, - { "nv!tvmr.deint.logs", "" }, - { "nv!tvmr.dfs.logs", "" }, - { "nv!tvmr.ffprof.logs", "" }, - { "nv!tvmr.game.stream", "" }, - { "nv!tvmr.general.logs", "" }, - { "nv!tvmr.input.dump", "" }, - { "nv!tvmr.seeking.logs", "" }, - { "nv!tvmr.ts_pulldown", "" }, - { "nv!usegvievents", "" }, - { "nv!vbomemoryspaceenables", "" }, - { "nv!vcc_debug_ip", "" }, - { "nv!vcc_verbose_level", "" }, - { "nv!vertexlimit", "" }, - { "nv!viccomposer.filter", "" }, - { "nv!videostats-enable", "" }, - { "nv!vidheapreuseratio", "" }, - { "nv!vpipe", "" }, - { "nv!vpipeformatbloatlimit", "" }, - { "nv!wglmessageboxonabort", "" }, - { "nv!writeinfolog", "" }, - { "nv!writeprogramobjectassembly", "" }, - { "nv!writeprogramobjectsource", "" }, - { "nv!xnvadapterpresent", "" }, - { "nv!yield", "" }, - { "nv!yieldfunction", "" }, - { "nv!yieldfunctionfast", "" }, - { "nv!yieldfunctionslow", "" }, - { "nv!yieldfunctionwaitfordcqueue", "" }, - { "nv!yieldfunctionwaitforframe", "" }, - { "nv!yieldfunctionwaitforgpu", "" }, - { "nv!zbctableaddhysteresis", "" }, - { "pcm!enable", true }, - { "pctl!intermittent_task_interval_seconds", 21600 }, - { "prepo!devmenu_prepo_page_view", false }, - { "prepo!background_processing", true }, - { "prepo!transmission_interval_min", 10 }, - { "prepo!transmission_retry_interval", 3600 }, - { "psm!evaluation_log_enabled", false }, - { "snap_shot_dump!auto_dump", false }, - { "snap_shot_dump!output_dir", "%USERPROFILE%/Documents/Nintendo/NXDMP" }, - { "snap_shot_dump!full_dump", false }, - { "systemconfig!field_testing", false }, - { "systemconfig!exhivision", false }, - { "systempowerstate!always_reboot", false }, - { "systempowerstate!power_state_message_emulation_trigger_time", 0 }, - { "systempowerstate!power_state_message_to_emulate", 0 }, - { "target_manager!device_name", "" }, - { "vulnerability!needs_update_vulnerability_policy", 0 }, - { "apm!performance_mode_policy", "auto" }, - { "apm!sdev_throttling_enabled", true }, - { "apm!sdev_throttling_additional_delay_us", 16000 }, - { "apm!battery_draining_enabled", false }, - { "apm!sdev_cpu_overclock_enabled", false }, - { "bcat!production_mode", true }, - { "bpc!enable_quasi_off", true }, - { "bsp0!usb", "UDS" }, - { "bsp0!tm_transport", "USB" }, - { "bluetooth_debug!skip_boot", false }, - { "contents_delivery!enable_debug_api", false }, - { "eupld!upload_enabled", true }, - { "fatal!transition_to_fatal", true }, - { "fatal!show_extra_info", false }, - { "gpu_core_dump!auto_dump", false }, - { "hid_debug!enables_debugpad", false }, - { "hid_debug!manages_devices", true }, - { "hid_debug!emulate_future_device", false }, - { "hid_debug!emulate_firmware_update_failure", false }, - { "hid_debug!emulate_mcu_hardware_error", false }, - { "hid_debug!firmware_update_failure_emulation_mode", 0 }, - { "jit_debug!enable_jit_debug", false }, - { "npns!background_processing", true }, - { "npns!logmanager_redirection", true }, - { "npns!sleep_processing_timeout", 30 }, - { "npns!sleep_periodic_interval", 10800 }, - { "npns!sleep_max_try_count", 5 }, - { "npns!test_mode", false }, - { "ns.applet!overlay_applet_id", "0x010000000000100c" }, - { "ns.applet!system_applet_id", "0x0100000000001000" }, - { "ns.applet!shop_applet_id", "0x010000000000100b" }, - { "ns.autoboot!enabled", true }, - { "ns.pseudodeviceid!reset_pseudo_device_id", false }, - { "nsd!environment_identifier", "lp1" }, - { "nsd!test_mode", false }, - { "ntc!is_autonomic_correction_enabled", true }, - { "ntc!autonomic_correction_interval_seconds", 432000 }, - { "ntc!autonomic_correction_failed_retry_interval_seconds", 1800 }, - { "ntc!autonomic_correction_immediate_try_count_max", 4 }, - { "ntc!autonomic_correction_immediate_try_interval_milliseconds", 5000 }, - { "nv!nv_graphics_firmware_memory_margin", false }, - { "omm!operation_mode_policy", "auto" }, - { "omm!sleep_fade_in_ms", 50 }, - { "omm!sleep_fade_out_ms", 100 }, - { "omm!charging_sign_ms", 3000 }, - { "omm!low_battery_sign_ms", 3000 }, - { "omm!sign_fade_in_ms", 0 }, - { "omm!sign_fade_out_ms", 400 }, - { "omm!sign_wait_layer_visible_ms", 100 }, - { "omm!startup_fade_in_ms", 200 }, - { "omm!startup_fade_out_ms", 400 }, - { "omm!backlight_off_ms_on_handheld_switch", 150 }, - { "omm!sleep_on_ac_ok_boot", true }, - { "pdm!save_playlog", true }, - { "productinfo!product_name", "Nintendo Switch" }, - { "productinfo!cec_osd_name", "NintendoSwitch" }, - { "ro!ease_nro_restriction", false }, - { "settings_debug!is_debug_mode_enabled", false }, - { "systemreport!enabled", true }, - { "systemsleep!enter_sleep", true }, - { "systemsleep!enter_sc7", true }, - { "systemsleep!keep_vdd_core", true }, - { "systemsleep!disable_tma_sleep", false }, - { "systemsleep!disable_auto_sleep", false }, - { "systemsleep!override_auto_sleep_time", 0 }, - { "systemsleep!sleep_pending_time_ms", 15000 }, - { "systemsleep!hush_time_after_brief_power_button_press_ms", 1000 }, - { "systemsleep!transition_timeout_sec", 60 }, - { "systemsleep!dummy_event_auto_wake", false }, - { "systemupdate!debug_id", "0x0000000000000000" }, - { "systemupdate!debug_version", 0 }, - { "systemupdate!bgnup_retry_seconds", 60 }, - { "systemupdate!enable_background_download_stress_testing", false }, - { "systemupdate!debug_id_for_content_delivery", "0x0000000000000000" }, - { "systemupdate!debug_version_for_content_delivery", 0 }, - { "systemupdate!assumed_system_applet_version", 0 }, - { "tc!iir_filter_gain_soc", 100 }, - { "tc!iir_filter_gain_pcb", 100 }, - { "tc!tskin_soc_coefficients_handheld", "[5464, 174190]" }, - { "tc!tskin_soc_coefficients_console", "[6182, 112480]" }, - { "tc!tskin_pcb_coefficients_handheld", "[5464, 174190]" }, - { "tc!tskin_pcb_coefficients_console", "[6182, 112480]" }, - { "tc!tskin_select", "both" }, - { "tc!tskin_rate_table_handheld", "[[-1000000, 40000, 0, 0], [36000, 43000, 51, 51], [43000, 48000, 51, 102], [48000, 53000, 102, 153], [53000, 1000000, 153, 153], [48000, 1000000, 153, 153]]" }, - { "tc!tskin_rate_table_console", "[[-1000000, 43000, 51, 51], [43000, 53000, 51, 153], [53000, 58000, 153, 255], [58000, 1000000, 255, 255]]" }, - { "tc!rate_select", "both" }, - { "tc!log_enabled", false }, - { "tc!sleep_enabled", true }, - { "time!standard_steady_clock_test_offset_minutes", 0 }, - { "time!standard_steady_clock_rtc_update_interval_minutes", 5 }, - { "time!standard_network_clock_sufficient_accuracy_minutes", 43200 }, - { "usb!usb30_force_enabled", false }, - { "wlan_debug!skip_wlan_boot", false }, - }; - } -} diff --git a/Ryujinx.HLE/OsHle/Services/Sfdnsres/IResolver.cs b/Ryujinx.HLE/OsHle/Services/Sfdnsres/IResolver.cs deleted file mode 100644 index 2fa81eb9..00000000 --- a/Ryujinx.HLE/OsHle/Services/Sfdnsres/IResolver.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Ryujinx.HLE.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.HLE.OsHle.Services.Sfdnsres -{ - class IResolver : IpcService - { - private Dictionary m_Commands; - - public override IReadOnlyDictionary Commands => m_Commands; - - public IResolver() - { - m_Commands = new Dictionary() - { - //... - }; - } - } -} diff --git a/Ryujinx.HLE/OsHle/Services/Sm/IUserInterface.cs b/Ryujinx.HLE/OsHle/Services/Sm/IUserInterface.cs deleted file mode 100644 index a0a174f5..00000000 --- a/Ryujinx.HLE/OsHle/Services/Sm/IUserInterface.cs +++ /dev/null @@ -1,69 +0,0 @@ -using Ryujinx.HLE.OsHle.Handles; -using Ryujinx.HLE.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.HLE.OsHle.Services.Sm -{ - class IUserInterface : IpcService - { - private Dictionary m_Commands; - - public override IReadOnlyDictionary Commands => m_Commands; - - private bool IsInitialized; - - public IUserInterface() - { - m_Commands = new Dictionary() - { - { 0, Initialize }, - { 1, GetService } - }; - } - - private const int SmNotInitialized = 0x415; - - public long Initialize(ServiceCtx Context) - { - IsInitialized = true; - - return 0; - } - - public long GetService(ServiceCtx Context) - { - //Only for kernel version > 3.0.0. - if (!IsInitialized) - { - //return SmNotInitialized; - } - - string Name = string.Empty; - - for (int Index = 0; Index < 8 && - Context.RequestData.BaseStream.Position < - Context.RequestData.BaseStream.Length; Index++) - { - byte Chr = Context.RequestData.ReadByte(); - - if (Chr >= 0x20 && Chr < 0x7f) - { - Name += (char)Chr; - } - } - - if (Name == string.Empty) - { - return 0; - } - - KSession Session = new KSession(ServiceFactory.MakeService(Name), Name); - - int Handle = Context.Process.HandleTable.OpenHandle(Session); - - Context.Response.HandleDesc = IpcHandleDesc.MakeMove(Handle); - - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Spl/IRandomInterface.cs b/Ryujinx.HLE/OsHle/Services/Spl/IRandomInterface.cs deleted file mode 100644 index 489ca52c..00000000 --- a/Ryujinx.HLE/OsHle/Services/Spl/IRandomInterface.cs +++ /dev/null @@ -1,50 +0,0 @@ -using Ryujinx.HLE.OsHle.Ipc; -using System; -using System.Collections.Generic; -using System.Security.Cryptography; - -namespace Ryujinx.HLE.OsHle.Services.Spl -{ - class IRandomInterface : IpcService, IDisposable - { - private Dictionary m_Commands; - - public override IReadOnlyDictionary Commands => m_Commands; - - private RNGCryptoServiceProvider Rng; - - public IRandomInterface() - { - m_Commands = new Dictionary() - { - { 0, GetRandomBytes } - }; - - Rng = new RNGCryptoServiceProvider(); - } - - public long GetRandomBytes(ServiceCtx Context) - { - byte[] RandomBytes = new byte[Context.Request.ReceiveBuff[0].Size]; - - Rng.GetBytes(RandomBytes); - - Context.Memory.WriteBytes(Context.Request.ReceiveBuff[0].Position, RandomBytes); - - return 0; - } - - public void Dispose() - { - Dispose(true); - } - - protected virtual void Dispose(bool Disposing) - { - if (Disposing) - { - Rng.Dispose(); - } - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Ssl/ISslService.cs b/Ryujinx.HLE/OsHle/Services/Ssl/ISslService.cs deleted file mode 100644 index 0bf4c144..00000000 --- a/Ryujinx.HLE/OsHle/Services/Ssl/ISslService.cs +++ /dev/null @@ -1,30 +0,0 @@ -using Ryujinx.HLE.Logging; -using Ryujinx.HLE.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.HLE.OsHle.Services.Ssl -{ - class ISslService : IpcService - { - private Dictionary m_Commands; - - public override IReadOnlyDictionary Commands => m_Commands; - - public ISslService() - { - m_Commands = new Dictionary() - { - { 5, SetInterfaceVersion } - }; - } - - public long SetInterfaceVersion(ServiceCtx Context) - { - int Version = Context.RequestData.ReadInt32(); - - Context.Ns.Log.PrintStub(LogClass.ServiceSsl, "Stubbed."); - - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Time/IStaticService.cs b/Ryujinx.HLE/OsHle/Services/Time/IStaticService.cs deleted file mode 100644 index 55601a89..00000000 --- a/Ryujinx.HLE/OsHle/Services/Time/IStaticService.cs +++ /dev/null @@ -1,74 +0,0 @@ -using Ryujinx.HLE.OsHle.Ipc; -using System; -using System.Collections.Generic; - -namespace Ryujinx.HLE.OsHle.Services.Time -{ - class IStaticService : IpcService - { - private Dictionary m_Commands; - - public override IReadOnlyDictionary Commands => m_Commands; - - private static readonly DateTime StartupDate = DateTime.UtcNow; - - public IStaticService() - { - m_Commands = new Dictionary() - { - { 0, GetStandardUserSystemClock }, - { 1, GetStandardNetworkSystemClock }, - { 2, GetStandardSteadyClock }, - { 3, GetTimeZoneService }, - { 4, GetStandardLocalSystemClock }, - { 300, CalculateMonotonicSystemClockBaseTimePoint } - }; - } - - public long GetStandardUserSystemClock(ServiceCtx Context) - { - MakeObject(Context, new ISystemClock(SystemClockType.User)); - - return 0; - } - - public long GetStandardNetworkSystemClock(ServiceCtx Context) - { - MakeObject(Context, new ISystemClock(SystemClockType.Network)); - - return 0; - } - - public long GetStandardSteadyClock(ServiceCtx Context) - { - MakeObject(Context, new ISteadyClock()); - - return 0; - } - - public long GetTimeZoneService(ServiceCtx Context) - { - MakeObject(Context, new ITimeZoneService()); - - return 0; - } - - public long GetStandardLocalSystemClock(ServiceCtx Context) - { - MakeObject(Context, new ISystemClock(SystemClockType.Local)); - - return 0; - } - - public long CalculateMonotonicSystemClockBaseTimePoint(ServiceCtx Context) - { - long TimeOffset = (long)(DateTime.UtcNow - StartupDate).TotalSeconds; - long SystemClockContextEpoch = Context.RequestData.ReadInt64(); - - Context.ResponseData.Write(TimeOffset + SystemClockContextEpoch); - - return 0; - } - - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Time/ISteadyClock.cs b/Ryujinx.HLE/OsHle/Services/Time/ISteadyClock.cs deleted file mode 100644 index e2cb34e3..00000000 --- a/Ryujinx.HLE/OsHle/Services/Time/ISteadyClock.cs +++ /dev/null @@ -1,53 +0,0 @@ -using Ryujinx.HLE.OsHle.Ipc; -using System; -using System.Collections.Generic; - -namespace Ryujinx.HLE.OsHle.Services.Time -{ - class ISteadyClock : IpcService - { - private Dictionary m_Commands; - - public override IReadOnlyDictionary Commands => m_Commands; - - private ulong TestOffset; - - public ISteadyClock() - { - m_Commands = new Dictionary() - { - { 0, GetCurrentTimePoint }, - { 1, GetTestOffset }, - { 2, SetTestOffset } - }; - - TestOffset = 0; - } - - public long GetCurrentTimePoint(ServiceCtx Context) - { - Context.ResponseData.Write((long)(System.Diagnostics.Process.GetCurrentProcess().StartTime - DateTime.Now).TotalSeconds); - - for (int i = 0; i < 0x10; i++) - { - Context.ResponseData.Write((byte)0); - } - - return 0; - } - - public long GetTestOffset(ServiceCtx Context) - { - Context.ResponseData.Write(TestOffset); - - return 0; - } - - public long SetTestOffset(ServiceCtx Context) - { - TestOffset = Context.RequestData.ReadUInt64(); - - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Time/ISystemClock.cs b/Ryujinx.HLE/OsHle/Services/Time/ISystemClock.cs deleted file mode 100644 index 27b65c3c..00000000 --- a/Ryujinx.HLE/OsHle/Services/Time/ISystemClock.cs +++ /dev/null @@ -1,107 +0,0 @@ -using Ryujinx.HLE.OsHle.Ipc; -using System; -using System.Collections.Generic; - -namespace Ryujinx.HLE.OsHle.Services.Time -{ - class ISystemClock : IpcService - { - private Dictionary m_Commands; - - public override IReadOnlyDictionary Commands => m_Commands; - - private static readonly DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); - - private SystemClockType ClockType; - - private DateTime SystemClockContextEpoch; - - private long SystemClockTimePoint; - - private byte[] SystemClockContextEnding; - - private long TimeOffset; - - public ISystemClock(SystemClockType ClockType) - { - m_Commands = new Dictionary() - { - { 0, GetCurrentTime }, - { 1, SetCurrentTime }, - { 2, GetSystemClockContext }, - { 3, SetSystemClockContext } - }; - - this.ClockType = ClockType; - SystemClockContextEpoch = System.Diagnostics.Process.GetCurrentProcess().StartTime; - SystemClockContextEnding = new byte[0x10]; - TimeOffset = 0; - - if (ClockType == SystemClockType.User || - ClockType == SystemClockType.Network) - { - SystemClockContextEpoch = SystemClockContextEpoch.ToUniversalTime(); - } - - SystemClockTimePoint = (long)(SystemClockContextEpoch - Epoch).TotalSeconds; - } - - public long GetCurrentTime(ServiceCtx Context) - { - DateTime CurrentTime = DateTime.Now; - - if (ClockType == SystemClockType.User || - ClockType == SystemClockType.Network) - { - CurrentTime = CurrentTime.ToUniversalTime(); - } - - Context.ResponseData.Write((long)((CurrentTime - Epoch).TotalSeconds) + TimeOffset); - - return 0; - } - - public long SetCurrentTime(ServiceCtx Context) - { - DateTime CurrentTime = DateTime.Now; - - if (ClockType == SystemClockType.User || - ClockType == SystemClockType.Network) - { - CurrentTime = CurrentTime.ToUniversalTime(); - } - - TimeOffset = (Context.RequestData.ReadInt64() - (long)(CurrentTime - Epoch).TotalSeconds); - - return 0; - } - - public long GetSystemClockContext(ServiceCtx Context) - { - Context.ResponseData.Write((long)(SystemClockContextEpoch - Epoch).TotalSeconds); - - // The point in time, TODO: is there a link between epoch and this? - Context.ResponseData.Write(SystemClockTimePoint); - - // This seems to be some kind of identifier? - for (int i = 0; i < 0x10; i++) - { - Context.ResponseData.Write(SystemClockContextEnding[i]); - } - - return 0; - } - - public long SetSystemClockContext(ServiceCtx Context) - { - long NewSystemClockEpoch = Context.RequestData.ReadInt64(); - long NewSystemClockTimePoint = Context.RequestData.ReadInt64(); - - SystemClockContextEpoch = Epoch.Add(TimeSpan.FromSeconds(NewSystemClockEpoch)); - SystemClockTimePoint = NewSystemClockTimePoint; - SystemClockContextEnding = Context.RequestData.ReadBytes(0x10); - - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Time/ITimeZoneService.cs b/Ryujinx.HLE/OsHle/Services/Time/ITimeZoneService.cs deleted file mode 100644 index 87ef02f9..00000000 --- a/Ryujinx.HLE/OsHle/Services/Time/ITimeZoneService.cs +++ /dev/null @@ -1,267 +0,0 @@ -using Ryujinx.HLE.Logging; -using Ryujinx.HLE.OsHle.Ipc; -using System; -using System.Collections.Generic; -using System.Text; - -namespace Ryujinx.HLE.OsHle.Services.Time -{ - class ITimeZoneService : IpcService - { - private Dictionary m_Commands; - - public override IReadOnlyDictionary Commands => m_Commands; - - private static readonly DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); - - private TimeZoneInfo TimeZone = TimeZoneInfo.Local; - - public ITimeZoneService() - { - m_Commands = new Dictionary() - { - { 0, GetDeviceLocationName }, - { 1, SetDeviceLocationName }, - { 2, GetTotalLocationNameCount }, - { 3, LoadLocationNameList }, - { 4, LoadTimeZoneRule }, - { 100, ToCalendarTime }, - { 101, ToCalendarTimeWithMyRule }, - { 201, ToPosixTime }, - { 202, ToPosixTimeWithMyRule } - }; - } - - public long GetDeviceLocationName(ServiceCtx Context) - { - char[] TzName = TimeZone.Id.ToCharArray(); - - Context.ResponseData.Write(TzName); - - int Padding = 0x24 - TzName.Length; - - for (int Index = 0; Index < Padding; Index++) - { - Context.ResponseData.Write((byte)0); - } - - return 0; - } - - public long SetDeviceLocationName(ServiceCtx Context) - { - byte[] LocationName = Context.RequestData.ReadBytes(0x24); - string TzID = Encoding.ASCII.GetString(LocationName).TrimEnd('\0'); - - long ResultCode = 0; - - try - { - TimeZone = TimeZoneInfo.FindSystemTimeZoneById(TzID); - } - catch (TimeZoneNotFoundException e) - { - ResultCode = 0x7BA74; - } - - return ResultCode; - } - - public long GetTotalLocationNameCount(ServiceCtx Context) - { - Context.ResponseData.Write(TimeZoneInfo.GetSystemTimeZones().Count); - - return 0; - } - - public long LoadLocationNameList(ServiceCtx Context) - { - long BufferPosition = Context.Response.SendBuff[0].Position; - long BufferSize = Context.Response.SendBuff[0].Size; - - int i = 0; - foreach (TimeZoneInfo info in TimeZoneInfo.GetSystemTimeZones()) - { - byte[] TzData = Encoding.ASCII.GetBytes(info.Id); - - Context.Memory.WriteBytes(BufferPosition + i, TzData); - - int Padding = 0x24 - TzData.Length; - - for (int Index = 0; Index < Padding; Index++) - { - Context.ResponseData.Write((byte)0); - } - - i += 0x24; - } - return 0; - } - - public long LoadTimeZoneRule(ServiceCtx Context) - { - long BufferPosition = Context.Request.ReceiveBuff[0].Position; - long BufferSize = Context.Request.ReceiveBuff[0].Size; - - if (BufferSize != 0x4000) - { - Context.Ns.Log.PrintWarning(LogClass.ServiceTime, $"TimeZoneRule buffer size is 0x{BufferSize:x} (expected 0x4000)"); - } - - long ResultCode = 0; - - byte[] LocationName = Context.RequestData.ReadBytes(0x24); - string TzID = Encoding.ASCII.GetString(LocationName).TrimEnd('\0'); - - // Check if the Time Zone exists, otherwise error out. - try - { - TimeZoneInfo Info = TimeZoneInfo.FindSystemTimeZoneById(TzID); - byte[] TzData = Encoding.ASCII.GetBytes(Info.Id); - - // FIXME: This is not in ANY cases accurate, but the games don't care about the content of the buffer, they only pass it. - // TODO: Reverse the TZif2 conversion in PCV to make this match with real hardware. - Context.Memory.WriteBytes(BufferPosition, TzData); - } - catch (TimeZoneNotFoundException e) - { - Context.Ns.Log.PrintWarning(LogClass.ServiceTime, $"Timezone not found for string: {TzID} (len: {TzID.Length})"); - ResultCode = 0x7BA74; - } - - return ResultCode; - } - - private long ToCalendarTimeWithTz(ServiceCtx Context, long PosixTime, TimeZoneInfo Info) - { - DateTime CurrentTime = Epoch.AddSeconds(PosixTime); - CurrentTime = TimeZoneInfo.ConvertTimeFromUtc(CurrentTime, Info); - - Context.ResponseData.Write((ushort)CurrentTime.Year); - Context.ResponseData.Write((byte)CurrentTime.Month); - Context.ResponseData.Write((byte)CurrentTime.Day); - Context.ResponseData.Write((byte)CurrentTime.Hour); - Context.ResponseData.Write((byte)CurrentTime.Minute); - Context.ResponseData.Write((byte)CurrentTime.Second); - Context.ResponseData.Write((byte)0); //MilliSecond ? - Context.ResponseData.Write((int)CurrentTime.DayOfWeek); - Context.ResponseData.Write(CurrentTime.DayOfYear - 1); - Context.ResponseData.Write(new byte[8]); //TODO: Find out the names used. - Context.ResponseData.Write((byte)(CurrentTime.IsDaylightSavingTime() ? 1 : 0)); - Context.ResponseData.Write((int)Info.GetUtcOffset(CurrentTime).TotalSeconds); - - return 0; - } - - public long ToCalendarTime(ServiceCtx Context) - { - long PosixTime = Context.RequestData.ReadInt64(); - long BufferPosition = Context.Request.SendBuff[0].Position; - long BufferSize = Context.Request.SendBuff[0].Size; - - if (BufferSize != 0x4000) - { - Context.Ns.Log.PrintWarning(LogClass.ServiceTime, $"TimeZoneRule buffer size is 0x{BufferSize:x} (expected 0x4000)"); - } - - // TODO: Reverse the TZif2 conversion in PCV to make this match with real hardware. - byte[] TzData = Context.Memory.ReadBytes(BufferPosition, 0x24); - string TzID = Encoding.ASCII.GetString(TzData).TrimEnd('\0'); - - long ResultCode = 0; - - // Check if the Time Zone exists, otherwise error out. - try - { - TimeZoneInfo Info = TimeZoneInfo.FindSystemTimeZoneById(TzID); - - ResultCode = ToCalendarTimeWithTz(Context, PosixTime, Info); - } - catch (TimeZoneNotFoundException e) - { - Context.Ns.Log.PrintWarning(LogClass.ServiceTime, $"Timezone not found for string: {TzID} (len: {TzID.Length})"); - ResultCode = 0x7BA74; - } - - return ResultCode; - } - - public long ToCalendarTimeWithMyRule(ServiceCtx Context) - { - long PosixTime = Context.RequestData.ReadInt64(); - - return ToCalendarTimeWithTz(Context, PosixTime, TimeZone); - } - - public long ToPosixTime(ServiceCtx Context) - { - long BufferPosition = Context.Request.SendBuff[0].Position; - long BufferSize = Context.Request.SendBuff[0].Size; - - ushort Year = Context.RequestData.ReadUInt16(); - byte Month = Context.RequestData.ReadByte(); - byte Day = Context.RequestData.ReadByte(); - byte Hour = Context.RequestData.ReadByte(); - byte Minute = Context.RequestData.ReadByte(); - byte Second = Context.RequestData.ReadByte(); - - DateTime CalendarTime = new DateTime(Year, Month, Day, Hour, Minute, Second); - - if (BufferSize != 0x4000) - { - Context.Ns.Log.PrintWarning(LogClass.ServiceTime, $"TimeZoneRule buffer size is 0x{BufferSize:x} (expected 0x4000)"); - } - - // TODO: Reverse the TZif2 conversion in PCV to make this match with real hardware. - byte[] TzData = Context.Memory.ReadBytes(BufferPosition, 0x24); - string TzID = Encoding.ASCII.GetString(TzData).TrimEnd('\0'); - - long ResultCode = 0; - - // Check if the Time Zone exists, otherwise error out. - try - { - TimeZoneInfo Info = TimeZoneInfo.FindSystemTimeZoneById(TzID); - - return ToPosixTimeWithTz(Context, CalendarTime, Info); - } - catch (TimeZoneNotFoundException e) - { - Context.Ns.Log.PrintWarning(LogClass.ServiceTime, $"Timezone not found for string: {TzID} (len: {TzID.Length})"); - ResultCode = 0x7BA74; - } - - return ResultCode; - } - - public long ToPosixTimeWithMyRule(ServiceCtx Context) - { - ushort Year = Context.RequestData.ReadUInt16(); - byte Month = Context.RequestData.ReadByte(); - byte Day = Context.RequestData.ReadByte(); - byte Hour = Context.RequestData.ReadByte(); - byte Minute = Context.RequestData.ReadByte(); - byte Second = Context.RequestData.ReadByte(); - - DateTime CalendarTime = new DateTime(Year, Month, Day, Hour, Minute, Second, DateTimeKind.Local); - - return ToPosixTimeWithTz(Context, CalendarTime, TimeZone); - } - - private long ToPosixTimeWithTz(ServiceCtx Context, DateTime CalendarTime, TimeZoneInfo Info) - { - DateTime CalenderTimeUTC = TimeZoneInfo.ConvertTimeToUtc(CalendarTime, Info); - - long PosixTime = ((DateTimeOffset)CalenderTimeUTC).ToUnixTimeSeconds(); - - long Position = Context.Request.RecvListBuff[0].Position; - long Size = Context.Request.RecvListBuff[0].Size; - - Context.Memory.WriteInt64(Position, PosixTime); - - Context.ResponseData.Write(1); - - return 0; - } - } -} diff --git a/Ryujinx.HLE/OsHle/Services/Time/SystemClockType.cs b/Ryujinx.HLE/OsHle/Services/Time/SystemClockType.cs deleted file mode 100644 index d581d9ca..00000000 --- a/Ryujinx.HLE/OsHle/Services/Time/SystemClockType.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Ryujinx.HLE.OsHle.Services.Time -{ - enum SystemClockType - { - User, - Network, - Local, - EphemeralNetwork - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Vi/Display.cs b/Ryujinx.HLE/OsHle/Services/Vi/Display.cs deleted file mode 100644 index 3da51c47..00000000 --- a/Ryujinx.HLE/OsHle/Services/Vi/Display.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace Ryujinx.HLE.OsHle.Services.Vi -{ - class Display - { - public string Name { get; private set; } - - public Display(string Name) - { - this.Name = Name; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Vi/GbpBuffer.cs b/Ryujinx.HLE/OsHle/Services/Vi/GbpBuffer.cs deleted file mode 100644 index b9e9054b..00000000 --- a/Ryujinx.HLE/OsHle/Services/Vi/GbpBuffer.cs +++ /dev/null @@ -1,60 +0,0 @@ -using System.IO; - -namespace Ryujinx.HLE.OsHle.Services.Android -{ - struct GbpBuffer - { - public int Magic { get; private set; } - public int Width { get; private set; } - public int Height { get; private set; } - public int Stride { get; private set; } - public int Format { get; private set; } - public int Usage { get; private set; } - - public int Pid { get; private set; } - public int RefCount { get; private set; } - - public int FdsCount { get; private set; } - public int IntsCount { get; private set; } - - public byte[] RawData { get; private set; } - - public int Size => RawData.Length + 10 * 4; - - public GbpBuffer(BinaryReader Reader) - { - Magic = Reader.ReadInt32(); - Width = Reader.ReadInt32(); - Height = Reader.ReadInt32(); - Stride = Reader.ReadInt32(); - Format = Reader.ReadInt32(); - Usage = Reader.ReadInt32(); - - Pid = Reader.ReadInt32(); - RefCount = Reader.ReadInt32(); - - FdsCount = Reader.ReadInt32(); - IntsCount = Reader.ReadInt32(); - - RawData = Reader.ReadBytes((FdsCount + IntsCount) * 4); - } - - public void Write(BinaryWriter Writer) - { - Writer.Write(Magic); - Writer.Write(Width); - Writer.Write(Height); - Writer.Write(Stride); - Writer.Write(Format); - Writer.Write(Usage); - - Writer.Write(Pid); - Writer.Write(RefCount); - - Writer.Write(FdsCount); - Writer.Write(IntsCount); - - Writer.Write(RawData); - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Vi/IApplicationDisplayService.cs b/Ryujinx.HLE/OsHle/Services/Vi/IApplicationDisplayService.cs deleted file mode 100644 index 17dc47e1..00000000 --- a/Ryujinx.HLE/OsHle/Services/Vi/IApplicationDisplayService.cs +++ /dev/null @@ -1,233 +0,0 @@ -using ChocolArm64.Memory; -using Ryujinx.HLE.OsHle.Ipc; -using System.Collections.Generic; -using System.IO; -using System.Text; - -using static Ryujinx.HLE.OsHle.Services.Android.Parcel; - -namespace Ryujinx.HLE.OsHle.Services.Vi -{ - class IApplicationDisplayService : IpcService - { - private Dictionary m_Commands; - - public override IReadOnlyDictionary Commands => m_Commands; - - private IdDictionary Displays; - - public IApplicationDisplayService() - { - m_Commands = new Dictionary() - { - { 100, GetRelayService }, - { 101, GetSystemDisplayService }, - { 102, GetManagerDisplayService }, - { 103, GetIndirectDisplayTransactionService }, - { 1000, ListDisplays }, - { 1010, OpenDisplay }, - { 1020, CloseDisplay }, - { 1102, GetDisplayResolution }, - { 2020, OpenLayer }, - { 2021, CloseLayer }, - { 2030, CreateStrayLayer }, - { 2031, DestroyStrayLayer }, - { 2101, SetLayerScalingMode }, - { 5202, GetDisplayVSyncEvent } - }; - - Displays = new IdDictionary(); - } - - public long GetRelayService(ServiceCtx Context) - { - MakeObject(Context, new IHOSBinderDriver(Context.Ns.Gpu.Renderer)); - - return 0; - } - - public long GetSystemDisplayService(ServiceCtx Context) - { - MakeObject(Context, new ISystemDisplayService()); - - return 0; - } - - public long GetManagerDisplayService(ServiceCtx Context) - { - MakeObject(Context, new IManagerDisplayService()); - - return 0; - } - - public long GetIndirectDisplayTransactionService(ServiceCtx Context) - { - MakeObject(Context, new IHOSBinderDriver(Context.Ns.Gpu.Renderer)); - - return 0; - } - - public long ListDisplays(ServiceCtx Context) - { - long RecBuffPtr = Context.Request.ReceiveBuff[0].Position; - - AMemoryHelper.FillWithZeros(Context.Memory, RecBuffPtr, 0x60); - - //Add only the default display to buffer - Context.Memory.WriteBytes(RecBuffPtr, Encoding.ASCII.GetBytes("Default")); - Context.Memory.WriteInt64(RecBuffPtr + 0x40, 0x1L); - Context.Memory.WriteInt64(RecBuffPtr + 0x48, 0x1L); - Context.Memory.WriteInt64(RecBuffPtr + 0x50, 1920L); - Context.Memory.WriteInt64(RecBuffPtr + 0x58, 1080L); - - Context.ResponseData.Write(1L); - - return 0; - } - - public long OpenDisplay(ServiceCtx Context) - { - string Name = GetDisplayName(Context); - - long DisplayId = Displays.Add(new Display(Name)); - - Context.ResponseData.Write(DisplayId); - - return 0; - } - - public long CloseDisplay(ServiceCtx Context) - { - int DisplayId = Context.RequestData.ReadInt32(); - - Displays.Delete(DisplayId); - - return 0; - } - - public long GetDisplayResolution(ServiceCtx Context) - { - long DisplayId = Context.RequestData.ReadInt32(); - - Context.ResponseData.Write(1280); - Context.ResponseData.Write(720); - - return 0; - } - - public long OpenLayer(ServiceCtx Context) - { - long LayerId = Context.RequestData.ReadInt64(); - long UserId = Context.RequestData.ReadInt64(); - - long ParcelPtr = Context.Request.ReceiveBuff[0].Position; - - byte[] Parcel = MakeIGraphicsBufferProducer(ParcelPtr); - - Context.Memory.WriteBytes(ParcelPtr, Parcel); - - Context.ResponseData.Write((long)Parcel.Length); - - return 0; - } - - public long CloseLayer(ServiceCtx Context) - { - long LayerId = Context.RequestData.ReadInt64(); - - return 0; - } - - public long CreateStrayLayer(ServiceCtx Context) - { - long LayerFlags = Context.RequestData.ReadInt64(); - long DisplayId = Context.RequestData.ReadInt64(); - - long ParcelPtr = Context.Request.ReceiveBuff[0].Position; - - Display Disp = Displays.GetData((int)DisplayId); - - byte[] Parcel = MakeIGraphicsBufferProducer(ParcelPtr); - - Context.Memory.WriteBytes(ParcelPtr, Parcel); - - Context.ResponseData.Write(0L); - Context.ResponseData.Write((long)Parcel.Length); - - return 0; - } - - public long DestroyStrayLayer(ServiceCtx Context) - { - return 0; - } - - public long SetLayerScalingMode(ServiceCtx Context) - { - int ScalingMode = Context.RequestData.ReadInt32(); - long Unknown = Context.RequestData.ReadInt64(); - - return 0; - } - - public long GetDisplayVSyncEvent(ServiceCtx Context) - { - string Name = GetDisplayName(Context); - - int Handle = Context.Process.HandleTable.OpenHandle(Context.Ns.Os.VsyncEvent); - - Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle); - - return 0; - } - - private byte[] MakeIGraphicsBufferProducer(long BasePtr) - { - long Id = 0x20; - long CookiePtr = 0L; - - using (MemoryStream MS = new MemoryStream()) - { - BinaryWriter Writer = new BinaryWriter(MS); - - //flat_binder_object (size is 0x28) - Writer.Write(2); //Type (BINDER_TYPE_WEAK_BINDER) - Writer.Write(0); //Flags - Writer.Write((int)(Id >> 0)); - Writer.Write((int)(Id >> 32)); - Writer.Write((int)(CookiePtr >> 0)); - Writer.Write((int)(CookiePtr >> 32)); - Writer.Write((byte)'d'); - Writer.Write((byte)'i'); - Writer.Write((byte)'s'); - Writer.Write((byte)'p'); - Writer.Write((byte)'d'); - Writer.Write((byte)'r'); - Writer.Write((byte)'v'); - Writer.Write((byte)'\0'); - Writer.Write(0L); //Pad - - return MakeParcel(MS.ToArray(), new byte[] { 0, 0, 0, 0 }); - } - } - - private string GetDisplayName(ServiceCtx Context) - { - string Name = string.Empty; - - for (int Index = 0; Index < 8 && - Context.RequestData.BaseStream.Position < - Context.RequestData.BaseStream.Length; Index++) - { - byte Chr = Context.RequestData.ReadByte(); - - if (Chr >= 0x20 && Chr < 0x7f) - { - Name += (char)Chr; - } - } - - return Name; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Vi/IApplicationRootService.cs b/Ryujinx.HLE/OsHle/Services/Vi/IApplicationRootService.cs deleted file mode 100644 index 93b05156..00000000 --- a/Ryujinx.HLE/OsHle/Services/Vi/IApplicationRootService.cs +++ /dev/null @@ -1,29 +0,0 @@ -using Ryujinx.HLE.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.HLE.OsHle.Services.Vi -{ - class IApplicationRootService : IpcService - { - private Dictionary m_Commands; - - public override IReadOnlyDictionary Commands => m_Commands; - - public IApplicationRootService() - { - m_Commands = new Dictionary() - { - { 0, GetDisplayService } - }; - } - - public long GetDisplayService(ServiceCtx Context) - { - int ServiceType = Context.RequestData.ReadInt32(); - - MakeObject(Context, new IApplicationDisplayService()); - - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Vi/IHOSBinderDriver.cs b/Ryujinx.HLE/OsHle/Services/Vi/IHOSBinderDriver.cs deleted file mode 100644 index 85283b75..00000000 --- a/Ryujinx.HLE/OsHle/Services/Vi/IHOSBinderDriver.cs +++ /dev/null @@ -1,100 +0,0 @@ -using Ryujinx.Graphics.Gal; -using Ryujinx.HLE.OsHle.Handles; -using Ryujinx.HLE.OsHle.Ipc; -using Ryujinx.HLE.OsHle.Services.Android; -using System; -using System.Collections.Generic; - -namespace Ryujinx.HLE.OsHle.Services.Vi -{ - class IHOSBinderDriver : IpcService, IDisposable - { - private Dictionary m_Commands; - - public override IReadOnlyDictionary Commands => m_Commands; - - private KEvent ReleaseEvent; - - private NvFlinger Flinger; - - public IHOSBinderDriver(IGalRenderer Renderer) - { - m_Commands = new Dictionary() - { - { 0, TransactParcel }, - { 1, AdjustRefcount }, - { 2, GetNativeHandle }, - { 3, TransactParcelAuto } - }; - - ReleaseEvent = new KEvent(); - - Flinger = new NvFlinger(Renderer, ReleaseEvent); - } - - public long TransactParcel(ServiceCtx Context) - { - int Id = Context.RequestData.ReadInt32(); - int Code = Context.RequestData.ReadInt32(); - - long DataPos = Context.Request.SendBuff[0].Position; - long DataSize = Context.Request.SendBuff[0].Size; - - byte[] Data = Context.Memory.ReadBytes(DataPos, DataSize); - - Data = Parcel.GetParcelData(Data); - - return Flinger.ProcessParcelRequest(Context, Data, Code); - } - - public long TransactParcelAuto(ServiceCtx Context) - { - int Id = Context.RequestData.ReadInt32(); - int Code = Context.RequestData.ReadInt32(); - - (long DataPos, long DataSize) = Context.Request.GetBufferType0x21(); - - byte[] Data = Context.Memory.ReadBytes(DataPos, DataSize); - - Data = Parcel.GetParcelData(Data); - - return Flinger.ProcessParcelRequest(Context, Data, Code); - } - - public long AdjustRefcount(ServiceCtx Context) - { - int Id = Context.RequestData.ReadInt32(); - int AddVal = Context.RequestData.ReadInt32(); - int Type = Context.RequestData.ReadInt32(); - - return 0; - } - - public long GetNativeHandle(ServiceCtx Context) - { - int Id = Context.RequestData.ReadInt32(); - uint Unk = Context.RequestData.ReadUInt32(); - - int Handle = Context.Process.HandleTable.OpenHandle(ReleaseEvent); - - Context.Response.HandleDesc = IpcHandleDesc.MakeMove(Handle); - - return 0; - } - - public void Dispose() - { - Dispose(true); - } - - protected virtual void Dispose(bool Disposing) - { - if (Disposing) - { - ReleaseEvent.Dispose(); - - Flinger.Dispose(); - } - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Vi/IManagerDisplayService.cs b/Ryujinx.HLE/OsHle/Services/Vi/IManagerDisplayService.cs deleted file mode 100644 index d7a51b0e..00000000 --- a/Ryujinx.HLE/OsHle/Services/Vi/IManagerDisplayService.cs +++ /dev/null @@ -1,49 +0,0 @@ -using Ryujinx.HLE.Logging; -using Ryujinx.HLE.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.HLE.OsHle.Services.Vi -{ - class IManagerDisplayService : IpcService - { - private Dictionary m_Commands; - - public override IReadOnlyDictionary Commands => m_Commands; - - public IManagerDisplayService() - { - m_Commands = new Dictionary() - { - { 2010, CreateManagedLayer }, - { 2011, DestroyManagedLayer }, - { 6000, AddToLayerStack }, - { 6002, SetLayerVisibility } - }; - } - - public static long CreateManagedLayer(ServiceCtx Context) - { - Context.Ns.Log.PrintStub(LogClass.ServiceVi, "Stubbed."); - Context.ResponseData.Write(0L); //LayerId - return 0; - } - - public long DestroyManagedLayer(ServiceCtx Context) - { - Context.Ns.Log.PrintStub(LogClass.ServiceVi, "Stubbed."); - return 0; - } - - public static long AddToLayerStack(ServiceCtx Context) - { - Context.Ns.Log.PrintStub(LogClass.ServiceVi, "Stubbed."); - return 0; - } - - public static long SetLayerVisibility(ServiceCtx Context) - { - Context.Ns.Log.PrintStub(LogClass.ServiceVi, "Stubbed."); - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Vi/IManagerRootService.cs b/Ryujinx.HLE/OsHle/Services/Vi/IManagerRootService.cs deleted file mode 100644 index 7c131dac..00000000 --- a/Ryujinx.HLE/OsHle/Services/Vi/IManagerRootService.cs +++ /dev/null @@ -1,29 +0,0 @@ -using Ryujinx.HLE.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.HLE.OsHle.Services.Vi -{ - class IManagerRootService : IpcService - { - private Dictionary m_Commands; - - public override IReadOnlyDictionary Commands => m_Commands; - - public IManagerRootService() - { - m_Commands = new Dictionary() - { - { 2, GetDisplayService } - }; - } - - public long GetDisplayService(ServiceCtx Context) - { - int ServiceType = Context.RequestData.ReadInt32(); - - MakeObject(Context, new IApplicationDisplayService()); - - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Vi/ISystemDisplayService.cs b/Ryujinx.HLE/OsHle/Services/Vi/ISystemDisplayService.cs deleted file mode 100644 index 360268b9..00000000 --- a/Ryujinx.HLE/OsHle/Services/Vi/ISystemDisplayService.cs +++ /dev/null @@ -1,44 +0,0 @@ -using Ryujinx.HLE.Logging; -using Ryujinx.HLE.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.HLE.OsHle.Services.Vi -{ - class ISystemDisplayService : IpcService - { - private Dictionary m_Commands; - - public override IReadOnlyDictionary Commands => m_Commands; - - public ISystemDisplayService() - { - m_Commands = new Dictionary() - { - { 2205, SetLayerZ }, - { 2207, SetLayerVisibility }, - { 3200, GetDisplayMode } - }; - } - - public static long SetLayerZ(ServiceCtx Context) - { - Context.Ns.Log.PrintStub(LogClass.ServiceVi, "Stubbed."); - return 0; - } - - public static long SetLayerVisibility(ServiceCtx Context) - { - Context.Ns.Log.PrintStub(LogClass.ServiceVi, "Stubbed."); - return 0; - } - - public static long GetDisplayMode(ServiceCtx Context) - { - Context.ResponseData.Write(1280); - Context.ResponseData.Write(720); - Context.ResponseData.Write(60.0f); - Context.ResponseData.Write(0); - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Vi/ISystemRootService.cs b/Ryujinx.HLE/OsHle/Services/Vi/ISystemRootService.cs deleted file mode 100644 index 21581baa..00000000 --- a/Ryujinx.HLE/OsHle/Services/Vi/ISystemRootService.cs +++ /dev/null @@ -1,29 +0,0 @@ -using Ryujinx.HLE.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.HLE.OsHle.Services.Vi -{ - class ISystemRootService : IpcService - { - private Dictionary m_Commands; - - public override IReadOnlyDictionary Commands => m_Commands; - - public ISystemRootService() - { - m_Commands = new Dictionary() - { - { 1, GetDisplayService } - }; - } - - public long GetDisplayService(ServiceCtx Context) - { - int ServiceType = Context.RequestData.ReadInt32(); - - MakeObject(Context, new IApplicationDisplayService()); - - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Vi/NvFlinger.cs b/Ryujinx.HLE/OsHle/Services/Vi/NvFlinger.cs deleted file mode 100644 index 04b50bb3..00000000 --- a/Ryujinx.HLE/OsHle/Services/Vi/NvFlinger.cs +++ /dev/null @@ -1,416 +0,0 @@ -using Ryujinx.Graphics.Gal; -using Ryujinx.HLE.Gpu.Texture; -using Ryujinx.HLE.Logging; -using Ryujinx.HLE.OsHle.Handles; -using Ryujinx.HLE.OsHle.Services.Nv.NvMap; -using System; -using System.Collections.Generic; -using System.IO; -using System.Text; -using System.Threading; - -using static Ryujinx.HLE.OsHle.Services.Android.Parcel; - -namespace Ryujinx.HLE.OsHle.Services.Android -{ - class NvFlinger : IDisposable - { - private delegate long ServiceProcessParcel(ServiceCtx Context, BinaryReader ParcelReader); - - private Dictionary<(string, int), ServiceProcessParcel> Commands; - - private KEvent ReleaseEvent; - - private IGalRenderer Renderer; - - private const int BufferQueueCount = 0x40; - private const int BufferQueueMask = BufferQueueCount - 1; - - [Flags] - private enum HalTransform - { - FlipX = 1 << 0, - FlipY = 1 << 1, - Rotate90 = 1 << 2 - } - - private enum BufferState - { - Free, - Dequeued, - Queued, - Acquired - } - - private struct Rect - { - public int Top; - public int Left; - public int Right; - public int Bottom; - } - - private struct BufferEntry - { - public BufferState State; - - public HalTransform Transform; - - public Rect Crop; - - public GbpBuffer Data; - } - - private BufferEntry[] BufferQueue; - - private ManualResetEvent WaitBufferFree; - - private bool Disposed; - - public NvFlinger(IGalRenderer Renderer, KEvent ReleaseEvent) - { - Commands = new Dictionary<(string, int), ServiceProcessParcel>() - { - { ("android.gui.IGraphicBufferProducer", 0x1), GbpRequestBuffer }, - { ("android.gui.IGraphicBufferProducer", 0x3), GbpDequeueBuffer }, - { ("android.gui.IGraphicBufferProducer", 0x4), GbpDetachBuffer }, - { ("android.gui.IGraphicBufferProducer", 0x7), GbpQueueBuffer }, - { ("android.gui.IGraphicBufferProducer", 0x8), GbpCancelBuffer }, - { ("android.gui.IGraphicBufferProducer", 0x9), GbpQuery }, - { ("android.gui.IGraphicBufferProducer", 0xa), GbpConnect }, - { ("android.gui.IGraphicBufferProducer", 0xb), GbpDisconnect }, - { ("android.gui.IGraphicBufferProducer", 0xe), GbpPreallocBuffer } - }; - - this.Renderer = Renderer; - this.ReleaseEvent = ReleaseEvent; - - BufferQueue = new BufferEntry[0x40]; - - WaitBufferFree = new ManualResetEvent(false); - } - - public long ProcessParcelRequest(ServiceCtx Context, byte[] ParcelData, int Code) - { - using (MemoryStream MS = new MemoryStream(ParcelData)) - { - BinaryReader Reader = new BinaryReader(MS); - - MS.Seek(4, SeekOrigin.Current); - - int StrSize = Reader.ReadInt32(); - - string InterfaceName = Encoding.Unicode.GetString(Reader.ReadBytes(StrSize * 2)); - - long Remainder = MS.Position & 0xf; - - if (Remainder != 0) - { - MS.Seek(0x10 - Remainder, SeekOrigin.Current); - } - - MS.Seek(0x50, SeekOrigin.Begin); - - if (Commands.TryGetValue((InterfaceName, Code), out ServiceProcessParcel ProcReq)) - { - Context.Ns.Log.PrintDebug(LogClass.ServiceVi, $"{InterfaceName} {ProcReq.Method.Name}"); - - return ProcReq(Context, Reader); - } - else - { - throw new NotImplementedException($"{InterfaceName} {Code}"); - } - } - } - - private long GbpRequestBuffer(ServiceCtx Context, BinaryReader ParcelReader) - { - int Slot = ParcelReader.ReadInt32(); - - using (MemoryStream MS = new MemoryStream()) - { - BinaryWriter Writer = new BinaryWriter(MS); - - BufferEntry Entry = BufferQueue[Slot]; - - int BufferCount = 1; //? - long BufferSize = Entry.Data.Size; - - Writer.Write(BufferCount); - Writer.Write(BufferSize); - - Entry.Data.Write(Writer); - - Writer.Write(0); - - return MakeReplyParcel(Context, MS.ToArray()); - } - } - - private long GbpDequeueBuffer(ServiceCtx Context, BinaryReader ParcelReader) - { - //TODO: Errors. - int Format = ParcelReader.ReadInt32(); - int Width = ParcelReader.ReadInt32(); - int Height = ParcelReader.ReadInt32(); - int GetTimestamps = ParcelReader.ReadInt32(); - int Usage = ParcelReader.ReadInt32(); - - int Slot = GetFreeSlotBlocking(Width, Height); - - return MakeReplyParcel(Context, Slot, 1, 0x24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); - } - - private long GbpQueueBuffer(ServiceCtx Context, BinaryReader ParcelReader) - { - Context.Ns.Statistics.RecordGameFrameTime(); - - //TODO: Errors. - int Slot = ParcelReader.ReadInt32(); - int Unknown4 = ParcelReader.ReadInt32(); - int Unknown8 = ParcelReader.ReadInt32(); - int Unknownc = ParcelReader.ReadInt32(); - int Timestamp = ParcelReader.ReadInt32(); - int IsAutoTimestamp = ParcelReader.ReadInt32(); - int CropTop = ParcelReader.ReadInt32(); - int CropLeft = ParcelReader.ReadInt32(); - int CropRight = ParcelReader.ReadInt32(); - int CropBottom = ParcelReader.ReadInt32(); - int ScalingMode = ParcelReader.ReadInt32(); - int Transform = ParcelReader.ReadInt32(); - int StickyTransform = ParcelReader.ReadInt32(); - int Unknown34 = ParcelReader.ReadInt32(); - int Unknown38 = ParcelReader.ReadInt32(); - int IsFenceValid = ParcelReader.ReadInt32(); - int Fence0Id = ParcelReader.ReadInt32(); - int Fence0Value = ParcelReader.ReadInt32(); - int Fence1Id = ParcelReader.ReadInt32(); - int Fence1Value = ParcelReader.ReadInt32(); - - BufferQueue[Slot].Transform = (HalTransform)Transform; - - BufferQueue[Slot].Crop.Top = CropTop; - BufferQueue[Slot].Crop.Left = CropLeft; - BufferQueue[Slot].Crop.Right = CropRight; - BufferQueue[Slot].Crop.Bottom = CropBottom; - - BufferQueue[Slot].State = BufferState.Queued; - - SendFrameBuffer(Context, Slot); - - return MakeReplyParcel(Context, 1280, 720, 0, 0, 0); - } - - private long GbpDetachBuffer(ServiceCtx Context, BinaryReader ParcelReader) - { - return MakeReplyParcel(Context, 0); - } - - private long GbpCancelBuffer(ServiceCtx Context, BinaryReader ParcelReader) - { - //TODO: Errors. - int Slot = ParcelReader.ReadInt32(); - - BufferQueue[Slot].State = BufferState.Free; - - return MakeReplyParcel(Context, 0); - } - - private long GbpQuery(ServiceCtx Context, BinaryReader ParcelReader) - { - return MakeReplyParcel(Context, 0, 0); - } - - private long GbpConnect(ServiceCtx Context, BinaryReader ParcelReader) - { - return MakeReplyParcel(Context, 1280, 720, 0, 0, 0); - } - - private long GbpDisconnect(ServiceCtx Context, BinaryReader ParcelReader) - { - return MakeReplyParcel(Context, 0); - } - - private long GbpPreallocBuffer(ServiceCtx Context, BinaryReader ParcelReader) - { - int Slot = ParcelReader.ReadInt32(); - - int BufferCount = ParcelReader.ReadInt32(); - - if (BufferCount > 0) - { - long BufferSize = ParcelReader.ReadInt64(); - - BufferQueue[Slot].State = BufferState.Free; - - BufferQueue[Slot].Data = new GbpBuffer(ParcelReader); - } - - return MakeReplyParcel(Context, 0); - } - - private long MakeReplyParcel(ServiceCtx Context, params int[] Ints) - { - using (MemoryStream MS = new MemoryStream()) - { - BinaryWriter Writer = new BinaryWriter(MS); - - foreach (int Int in Ints) - { - Writer.Write(Int); - } - - return MakeReplyParcel(Context, MS.ToArray()); - } - } - - private long MakeReplyParcel(ServiceCtx Context, byte[] Data) - { - long ReplyPos = Context.Request.ReceiveBuff[0].Position; - long ReplySize = Context.Request.ReceiveBuff[0].Size; - - byte[] Reply = MakeParcel(Data, new byte[0]); - - Context.Memory.WriteBytes(ReplyPos, Reply); - - return 0; - } - - private void SendFrameBuffer(ServiceCtx Context, int Slot) - { - int FbWidth = BufferQueue[Slot].Data.Width; - int FbHeight = BufferQueue[Slot].Data.Height; - - int NvMapHandle = BitConverter.ToInt32(BufferQueue[Slot].Data.RawData, 0x4c); - int BufferOffset = BitConverter.ToInt32(BufferQueue[Slot].Data.RawData, 0x50); - - NvMapHandle Map = NvMapIoctl.GetNvMap(Context, NvMapHandle);; - - long FbAddr = Map.Address + BufferOffset; - - BufferQueue[Slot].State = BufferState.Acquired; - - Rect Crop = BufferQueue[Slot].Crop; - - bool FlipX = BufferQueue[Slot].Transform.HasFlag(HalTransform.FlipX); - bool FlipY = BufferQueue[Slot].Transform.HasFlag(HalTransform.FlipY); - - //Rotation is being ignored - - int Top = Crop.Top; - int Left = Crop.Left; - int Right = Crop.Right; - int Bottom = Crop.Bottom; - - Renderer.QueueAction(() => Renderer.FrameBuffer.SetTransform(FlipX, FlipY, Top, Left, Right, Bottom)); - - //TODO: Support double buffering here aswell, it is broken for GPU - //frame buffers because it seems to be completely out of sync. - if (Context.Ns.Gpu.Engine3d.IsFrameBufferPosition(FbAddr)) - { - //Frame buffer is rendered to by the GPU, we can just - //bind the frame buffer texture, it's not necessary to read anything. - Renderer.QueueAction(() => Renderer.FrameBuffer.Set(FbAddr)); - } - else - { - //Frame buffer is not set on the GPU registers, in this case - //assume that the app is manually writing to it. - TextureInfo Texture = new TextureInfo(FbAddr, FbWidth, FbHeight); - - byte[] Data = TextureReader.Read(Context.Memory, Texture); - - Renderer.QueueAction(() => Renderer.FrameBuffer.Set(Data, FbWidth, FbHeight)); - } - - Context.Ns.Gpu.Renderer.QueueAction(() => ReleaseBuffer(Slot)); - } - - private void ReleaseBuffer(int Slot) - { - BufferQueue[Slot].State = BufferState.Free; - - ReleaseEvent.WaitEvent.Set(); - - lock (WaitBufferFree) - { - WaitBufferFree.Set(); - } - } - - private int GetFreeSlotBlocking(int Width, int Height) - { - int Slot; - - do - { - lock (WaitBufferFree) - { - if ((Slot = GetFreeSlot(Width, Height)) != -1) - { - break; - } - - if (Disposed) - { - break; - } - - WaitBufferFree.Reset(); - } - - WaitBufferFree.WaitOne(); - } - while (!Disposed); - - return Slot; - } - - private int GetFreeSlot(int Width, int Height) - { - lock (BufferQueue) - { - for (int Slot = 0; Slot < BufferQueue.Length; Slot++) - { - if (BufferQueue[Slot].State != BufferState.Free) - { - continue; - } - - GbpBuffer Data = BufferQueue[Slot].Data; - - if (Data.Width == Width && - Data.Height == Height) - { - BufferQueue[Slot].State = BufferState.Dequeued; - - return Slot; - } - } - } - - return -1; - } - - public void Dispose() - { - Dispose(true); - } - - protected virtual void Dispose(bool Disposing) - { - if (Disposing && !Disposed) - { - Disposed = true; - - lock (WaitBufferFree) - { - WaitBufferFree.Set(); - } - - WaitBufferFree.Dispose(); - } - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Vi/Parcel.cs b/Ryujinx.HLE/OsHle/Services/Vi/Parcel.cs deleted file mode 100644 index 009ed8c1..00000000 --- a/Ryujinx.HLE/OsHle/Services/Vi/Parcel.cs +++ /dev/null @@ -1,58 +0,0 @@ -using System; -using System.IO; - -namespace Ryujinx.HLE.OsHle.Services.Android -{ - static class Parcel - { - public static byte[] GetParcelData(byte[] Parcel) - { - if (Parcel == null) - { - throw new ArgumentNullException(nameof(Parcel)); - } - - using (MemoryStream MS = new MemoryStream(Parcel)) - { - BinaryReader Reader = new BinaryReader(MS); - - int DataSize = Reader.ReadInt32(); - int DataOffset = Reader.ReadInt32(); - int ObjsSize = Reader.ReadInt32(); - int ObjsOffset = Reader.ReadInt32(); - - MS.Seek(DataOffset - 0x10, SeekOrigin.Current); - - return Reader.ReadBytes(DataSize); - } - } - - public static byte[] MakeParcel(byte[] Data, byte[] Objs) - { - if (Data == null) - { - throw new ArgumentNullException(nameof(Data)); - } - - if (Objs == null) - { - throw new ArgumentNullException(nameof(Objs)); - } - - using (MemoryStream MS = new MemoryStream()) - { - BinaryWriter Writer = new BinaryWriter(MS); - - Writer.Write(Data.Length); - Writer.Write(0x10); - Writer.Write(Objs.Length); - Writer.Write(Data.Length + 0x10); - - Writer.Write(Data); - Writer.Write(Objs); - - return MS.ToArray(); - } - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/SystemState/AppletStateMgr.cs b/Ryujinx.HLE/OsHle/SystemState/AppletStateMgr.cs deleted file mode 100644 index a656d218..00000000 --- a/Ryujinx.HLE/OsHle/SystemState/AppletStateMgr.cs +++ /dev/null @@ -1,62 +0,0 @@ -using Ryujinx.HLE.OsHle.Handles; -using Ryujinx.HLE.OsHle.Services.Am; -using System; -using System.Collections.Concurrent; - -namespace Ryujinx.HLE.OsHle.SystemState -{ - class AppletStateMgr : IDisposable - { - private ConcurrentQueue Messages; - - public FocusState FocusState { get; private set; } - - public KEvent MessageEvent { get; private set; } - - public AppletStateMgr() - { - Messages = new ConcurrentQueue(); - - MessageEvent = new KEvent(); - } - - public void SetFocus(bool IsFocused) - { - FocusState = IsFocused - ? FocusState.InFocus - : FocusState.OutOfFocus; - - EnqueueMessage(MessageInfo.FocusStateChanged); - } - - public void EnqueueMessage(MessageInfo Message) - { - Messages.Enqueue(Message); - - MessageEvent.WaitEvent.Set(); - } - - public bool TryDequeueMessage(out MessageInfo Message) - { - if (Messages.Count < 2) - { - MessageEvent.WaitEvent.Reset(); - } - - return Messages.TryDequeue(out Message); - } - - public void Dispose() - { - Dispose(true); - } - - protected virtual void Dispose(bool Disposing) - { - if (Disposing) - { - MessageEvent.Dispose(); - } - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/SystemState/ColorSet.cs b/Ryujinx.HLE/OsHle/SystemState/ColorSet.cs deleted file mode 100644 index adcdf00d..00000000 --- a/Ryujinx.HLE/OsHle/SystemState/ColorSet.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Ryujinx.HLE.OsHle.SystemState -{ - public enum ColorSet - { - BasicWhite = 0, - BasicBlack = 1 - } -} diff --git a/Ryujinx.HLE/OsHle/SystemState/OpenCloseState.cs b/Ryujinx.HLE/OsHle/SystemState/OpenCloseState.cs deleted file mode 100644 index c43a260f..00000000 --- a/Ryujinx.HLE/OsHle/SystemState/OpenCloseState.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Ryujinx.HLE.OsHle.SystemState -{ - public enum OpenCloseState - { - Closed, - Open - } -} diff --git a/Ryujinx.HLE/OsHle/SystemState/SystemLanguage.cs b/Ryujinx.HLE/OsHle/SystemState/SystemLanguage.cs deleted file mode 100644 index 946d0a3b..00000000 --- a/Ryujinx.HLE/OsHle/SystemState/SystemLanguage.cs +++ /dev/null @@ -1,23 +0,0 @@ -namespace Ryujinx.HLE.OsHle.SystemState -{ - public enum SystemLanguage - { - Japanese, - AmericanEnglish, - French, - German, - Italian, - Spanish, - Chinese, - Korean, - Dutch, - Portuguese, - Russian, - Taiwanese, - BritishEnglish, - CanadianFrench, - LatinAmericanSpanish, - SimplifiedChinese, - TraditionalChinese - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/SystemState/SystemStateMgr.cs b/Ryujinx.HLE/OsHle/SystemState/SystemStateMgr.cs deleted file mode 100644 index bf0c0efb..00000000 --- a/Ryujinx.HLE/OsHle/SystemState/SystemStateMgr.cs +++ /dev/null @@ -1,145 +0,0 @@ -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Linq; - -namespace Ryujinx.HLE.OsHle.SystemState -{ - public class SystemStateMgr - { - internal static string[] LanguageCodes = new string[] - { - "ja", - "en-US", - "fr", - "de", - "it", - "es", - "zh-CN", - "ko", - "nl", - "pt", - "ru", - "zh-TW", - "en-GB", - "fr-CA", - "es-419", - "zh-Hans", - "zh-Hant" - }; - - internal static string[] AudioOutputs = new string[] - { - "AudioTvOutput", - "AudioStereoJackOutput", - "AudioBuiltInSpeakerOutput" - }; - - internal long DesiredLanguageCode { get; private set; } - - internal string ActiveAudioOutput { get; private set; } - - public bool DockedMode { get; set; } - - public ColorSet ThemeColor { get; set; } - - private ConcurrentDictionary Profiles; - - internal UserProfile LastOpenUser { get; private set; } - - public SystemStateMgr() - { - SetLanguage(SystemLanguage.AmericanEnglish); - - SetAudioOutputAsBuiltInSpeaker(); - - Profiles = new ConcurrentDictionary(); - - UserId DefaultUuid = new UserId("00000000000000000000000000000001"); - - AddUser(DefaultUuid, "Player"); - OpenUser(DefaultUuid); - } - - public void SetLanguage(SystemLanguage Language) - { - DesiredLanguageCode = GetLanguageCode((int)Language); - } - - public void SetAudioOutputAsTv() - { - ActiveAudioOutput = AudioOutputs[0]; - } - - public void SetAudioOutputAsStereoJack() - { - ActiveAudioOutput = AudioOutputs[1]; - } - - public void SetAudioOutputAsBuiltInSpeaker() - { - ActiveAudioOutput = AudioOutputs[2]; - } - - public void AddUser(UserId Uuid, string Name) - { - UserProfile Profile = new UserProfile(Uuid, Name); - - Profiles.AddOrUpdate(Uuid.UserIdHex, Profile, (Key, Old) => Profile); - } - - public void OpenUser(UserId Uuid) - { - if (Profiles.TryGetValue(Uuid.UserIdHex, out UserProfile Profile)) - { - (LastOpenUser = Profile).AccountState = OpenCloseState.Open; - } - } - - public void CloseUser(UserId Uuid) - { - if (Profiles.TryGetValue(Uuid.UserIdHex, out UserProfile Profile)) - { - Profile.AccountState = OpenCloseState.Closed; - } - } - - public int GetUserCount() - { - return Profiles.Count; - } - - internal bool TryGetUser(UserId Uuid, out UserProfile Profile) - { - return Profiles.TryGetValue(Uuid.UserIdHex, out Profile); - } - - internal IEnumerable GetAllUsers() - { - return Profiles.Values; - } - - internal IEnumerable GetOpenUsers() - { - return Profiles.Values.Where(x => x.AccountState == OpenCloseState.Open); - } - - internal static long GetLanguageCode(int Index) - { - if ((uint)Index >= LanguageCodes.Length) - { - throw new ArgumentOutOfRangeException(nameof(Index)); - } - - long Code = 0; - int Shift = 0; - - foreach (char Chr in LanguageCodes[Index]) - { - Code |= (long)(byte)Chr << Shift++ * 8; - } - - return Code; - } - } -} diff --git a/Ryujinx.HLE/OsHle/SystemState/UserId.cs b/Ryujinx.HLE/OsHle/SystemState/UserId.cs deleted file mode 100644 index 278ea9f7..00000000 --- a/Ryujinx.HLE/OsHle/SystemState/UserId.cs +++ /dev/null @@ -1,76 +0,0 @@ -using Ryujinx.HLE.OsHle.Utilities; -using System; -using System.IO; -using System.Linq; - -namespace Ryujinx.HLE.OsHle.SystemState -{ - public struct UserId - { - public string UserIdHex { get; private set; } - - public byte[] Bytes { get; private set; } - - public UserId(long Low, long High) - { - if ((Low | High) == 0) - { - throw new ArgumentException("Zero is not a valid user id!"); - } - - byte[] Bytes = new byte[16]; - - int Index = Bytes.Length; - - void WriteBytes(long Value) - { - for (int Byte = 0; Byte < 8; Byte++) - { - Bytes[--Index] = (byte)(Value >> Byte * 8); - } - } - - WriteBytes(Low); - WriteBytes(High); - - UserIdHex = string.Empty; - - foreach (byte Byte in Bytes) - { - UserIdHex += Byte.ToString("X2"); - } - - this.Bytes = Bytes; - } - - public UserId(string UserIdHex) - { - if (UserIdHex == null || UserIdHex.Length != 32 || !UserIdHex.All("0123456789abcdefABCDEF".Contains)) - { - throw new ArgumentException("Invalid user id!", nameof(UserIdHex)); - } - - if (UserIdHex == "00000000000000000000000000000000") - { - throw new ArgumentException("Zero is not a valid user id!", nameof(UserIdHex)); - } - - this.UserIdHex = UserIdHex.ToUpper(); - - Bytes = StringUtils.HexToBytes(UserIdHex); - } - - internal void Write(BinaryWriter Writer) - { - for (int Index = Bytes.Length - 1; Index >= 0; Index--) - { - Writer.Write(Bytes[Index]); - } - } - - public override string ToString() - { - return UserIdHex; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/SystemState/UserProfile.cs b/Ryujinx.HLE/OsHle/SystemState/UserProfile.cs deleted file mode 100644 index b5b52339..00000000 --- a/Ryujinx.HLE/OsHle/SystemState/UserProfile.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System; - -namespace Ryujinx.HLE.OsHle.SystemState -{ - class UserProfile - { - private static readonly DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); - - public UserId Uuid { get; private set; } - - public string Name { get; private set; } - - public long LastModifiedTimestamp { get; private set; } - - public OpenCloseState AccountState { get; set; } - public OpenCloseState OnlinePlayState { get; set; } - - public UserProfile(UserId Uuid, string Name) - { - this.Uuid = Uuid; - this.Name = Name; - - LastModifiedTimestamp = 0; - - AccountState = OpenCloseState.Closed; - OnlinePlayState = OpenCloseState.Closed; - - UpdateTimestamp(); - } - - private void UpdateTimestamp() - { - LastModifiedTimestamp = (long)(DateTime.Now - Epoch).TotalSeconds; - } - } -} diff --git a/Ryujinx.HLE/OsHle/Utilities/EndianSwap.cs b/Ryujinx.HLE/OsHle/Utilities/EndianSwap.cs deleted file mode 100644 index 46a2edcb..00000000 --- a/Ryujinx.HLE/OsHle/Utilities/EndianSwap.cs +++ /dev/null @@ -1,17 +0,0 @@ -namespace Ryujinx.HLE.OsHle.Utilities -{ - static class EndianSwap - { - public static short Swap16(short Value) => (short)(((Value >> 8) & 0xff) | (Value << 8)); - - public static int Swap32(int Value) - { - uint UintVal = (uint)Value; - - return (int)(((UintVal >> 24) & 0x000000ff) | - ((UintVal >> 8) & 0x0000ff00) | - ((UintVal << 8) & 0x00ff0000) | - ((UintVal << 24) & 0xff000000)); - } - } -} diff --git a/Ryujinx.HLE/OsHle/Utilities/IntUtils.cs b/Ryujinx.HLE/OsHle/Utilities/IntUtils.cs deleted file mode 100644 index 010dbb20..00000000 --- a/Ryujinx.HLE/OsHle/Utilities/IntUtils.cs +++ /dev/null @@ -1,25 +0,0 @@ -namespace Ryujinx.HLE.OsHle.Utilities -{ - static class IntUtils - { - public static int AlignUp(int Value, int Size) - { - return (Value + (Size - 1)) & ~(Size - 1); - } - - public static long AlignUp(long Value, int Size) - { - return (Value + (Size - 1)) & ~((long)Size - 1); - } - - public static int AlignDown(int Value, int Size) - { - return Value & ~(Size - 1); - } - - public static long AlignDown(long Value, int Size) - { - return Value & ~((long)Size - 1); - } - } -} diff --git a/Ryujinx.HLE/OsHle/Utilities/StringUtils.cs b/Ryujinx.HLE/OsHle/Utilities/StringUtils.cs deleted file mode 100644 index 90f34695..00000000 --- a/Ryujinx.HLE/OsHle/Utilities/StringUtils.cs +++ /dev/null @@ -1,51 +0,0 @@ -using System; -using System.Globalization; -using System.Linq; -using System.Text; - -namespace Ryujinx.HLE.OsHle.Utilities -{ - static class StringUtils - { - public static byte[] GetFixedLengthBytes(string InputString, int Size, Encoding Encoding) - { - InputString = InputString + "\0"; - - int BytesCount = Encoding.GetByteCount(InputString); - - byte[] Output = new byte[Size]; - - if (BytesCount < Size) - { - Encoding.GetBytes(InputString, 0, InputString.Length, Output, 0); - } - else - { - int NullSize = Encoding.GetByteCount("\0"); - - Output = Encoding.GetBytes(InputString); - - Array.Resize(ref Output, Size - NullSize); - - Output = Output.Concat(Encoding.GetBytes("\0")).ToArray(); - } - - return Output; - } - - public static byte[] HexToBytes(string HexString) - { - //Ignore last charactor if HexLength % 2 != 0. - int BytesInHex = HexString.Length / 2; - - byte[] Output = new byte[BytesInHex]; - - for (int Index = 0; Index < BytesInHex; Index++) - { - Output[Index] = byte.Parse(HexString.Substring(Index * 2, 2), NumberStyles.HexNumber); - } - - return Output; - } - } -} diff --git a/Ryujinx.HLE/OsHle/Utilities/StructReader.cs b/Ryujinx.HLE/OsHle/Utilities/StructReader.cs deleted file mode 100644 index e218288b..00000000 --- a/Ryujinx.HLE/OsHle/Utilities/StructReader.cs +++ /dev/null @@ -1,45 +0,0 @@ -using ChocolArm64.Memory; -using System.Runtime.InteropServices; - -namespace Ryujinx.HLE.OsHle.Utilities -{ - class StructReader - { - private AMemory Memory; - - public long Position { get; private set; } - - public StructReader(AMemory Memory, long Position) - { - this.Memory = Memory; - this.Position = Position; - } - - public T Read() where T : struct - { - T Value = AMemoryHelper.Read(Memory, Position); - - Position += Marshal.SizeOf(); - - return Value; - } - - public T[] Read(int Size) where T : struct - { - int StructSize = Marshal.SizeOf(); - - int Count = Size / StructSize; - - T[] Output = new T[Count]; - - for (int Index = 0; Index < Count; Index++) - { - Output[Index] = AMemoryHelper.Read(Memory, Position); - - Position += StructSize; - } - - return Output; - } - } -} diff --git a/Ryujinx.HLE/OsHle/Utilities/StructWriter.cs b/Ryujinx.HLE/OsHle/Utilities/StructWriter.cs deleted file mode 100644 index 7daa95fb..00000000 --- a/Ryujinx.HLE/OsHle/Utilities/StructWriter.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ChocolArm64.Memory; -using System.Runtime.InteropServices; - -namespace Ryujinx.HLE.OsHle.Utilities -{ - class StructWriter - { - private AMemory Memory; - - public long Position { get; private set; } - - public StructWriter(AMemory Memory, long Position) - { - this.Memory = Memory; - this.Position = Position; - } - - public void Write(T Value) where T : struct - { - AMemoryHelper.Write(Memory, Position, Value); - - Position += Marshal.SizeOf(); - } - } -} diff --git a/Ryujinx.HLE/Switch.cs b/Ryujinx.HLE/Switch.cs index 165922e9..03dc44e8 100644 --- a/Ryujinx.HLE/Switch.cs +++ b/Ryujinx.HLE/Switch.cs @@ -1,10 +1,10 @@ using Ryujinx.Audio; using Ryujinx.Graphics.Gal; using Ryujinx.HLE.Gpu; +using Ryujinx.HLE.HOS; using Ryujinx.HLE.Input; using Ryujinx.HLE.Logging; using Ryujinx.HLE.Memory; -using Ryujinx.HLE.OsHle; using System; namespace Ryujinx.HLE @@ -19,16 +19,14 @@ namespace Ryujinx.HLE internal NvGpu Gpu { get; private set; } - internal VirtualFileSystem VFs { get; private set; } + internal VirtualFileSystem FileSystem { get; private set; } - public Horizon Os { get; private set; } + public Horizon System { get; private set; } public PerformanceStatistics Statistics { get; private set; } public Hid Hid { get; private set; } - public event EventHandler Finish; - public Switch(IGalRenderer Renderer, IAalOutput AudioOut) { if (Renderer == null) @@ -49,23 +47,23 @@ namespace Ryujinx.HLE Gpu = new NvGpu(Renderer); - VFs = new VirtualFileSystem(); + FileSystem = new VirtualFileSystem(); - Os = new Horizon(this); + System = new Horizon(this); Statistics = new PerformanceStatistics(); - Hid = new Hid(this, Os.HidSharedMem.PA); + Hid = new Hid(this, System.HidSharedMem.PA); } public void LoadCart(string ExeFsDir, string RomFsFile = null) { - Os.LoadCart(ExeFsDir, RomFsFile); + System.LoadCart(ExeFsDir, RomFsFile); } public void LoadProgram(string FileName) { - Os.LoadProgram(FileName); + System.LoadProgram(FileName); } public bool WaitFifo() @@ -78,10 +76,11 @@ namespace Ryujinx.HLE Gpu.Fifo.DispatchCalls(); } - public virtual void OnFinish(EventArgs e) + internal void Unload() { - Os.Dispose(); - Finish?.Invoke(this, e); + FileSystem.Dispose(); + + Memory.Dispose(); } public void Dispose() @@ -93,8 +92,7 @@ namespace Ryujinx.HLE { if (Disposing) { - Os.Dispose(); - VFs.Dispose(); + System.Dispose(); } } } diff --git a/Ryujinx.HLE/Utilities/EndianSwap.cs b/Ryujinx.HLE/Utilities/EndianSwap.cs new file mode 100644 index 00000000..d773516d --- /dev/null +++ b/Ryujinx.HLE/Utilities/EndianSwap.cs @@ -0,0 +1,17 @@ +namespace Ryujinx.HLE.Utilities +{ + static class EndianSwap + { + public static short Swap16(short Value) => (short)(((Value >> 8) & 0xff) | (Value << 8)); + + public static int Swap32(int Value) + { + uint UintVal = (uint)Value; + + return (int)(((UintVal >> 24) & 0x000000ff) | + ((UintVal >> 8) & 0x0000ff00) | + ((UintVal << 8) & 0x00ff0000) | + ((UintVal << 24) & 0xff000000)); + } + } +} diff --git a/Ryujinx.HLE/Utilities/IntUtils.cs b/Ryujinx.HLE/Utilities/IntUtils.cs new file mode 100644 index 00000000..57e9d396 --- /dev/null +++ b/Ryujinx.HLE/Utilities/IntUtils.cs @@ -0,0 +1,25 @@ +namespace Ryujinx.HLE.Utilities +{ + static class IntUtils + { + public static int AlignUp(int Value, int Size) + { + return (Value + (Size - 1)) & ~(Size - 1); + } + + public static long AlignUp(long Value, int Size) + { + return (Value + (Size - 1)) & ~((long)Size - 1); + } + + public static int AlignDown(int Value, int Size) + { + return Value & ~(Size - 1); + } + + public static long AlignDown(long Value, int Size) + { + return Value & ~((long)Size - 1); + } + } +} diff --git a/Ryujinx.HLE/Utilities/StringUtils.cs b/Ryujinx.HLE/Utilities/StringUtils.cs new file mode 100644 index 00000000..e8d6550a --- /dev/null +++ b/Ryujinx.HLE/Utilities/StringUtils.cs @@ -0,0 +1,51 @@ +using System; +using System.Globalization; +using System.Linq; +using System.Text; + +namespace Ryujinx.HLE.Utilities +{ + static class StringUtils + { + public static byte[] GetFixedLengthBytes(string InputString, int Size, Encoding Encoding) + { + InputString = InputString + "\0"; + + int BytesCount = Encoding.GetByteCount(InputString); + + byte[] Output = new byte[Size]; + + if (BytesCount < Size) + { + Encoding.GetBytes(InputString, 0, InputString.Length, Output, 0); + } + else + { + int NullSize = Encoding.GetByteCount("\0"); + + Output = Encoding.GetBytes(InputString); + + Array.Resize(ref Output, Size - NullSize); + + Output = Output.Concat(Encoding.GetBytes("\0")).ToArray(); + } + + return Output; + } + + public static byte[] HexToBytes(string HexString) + { + //Ignore last charactor if HexLength % 2 != 0. + int BytesInHex = HexString.Length / 2; + + byte[] Output = new byte[BytesInHex]; + + for (int Index = 0; Index < BytesInHex; Index++) + { + Output[Index] = byte.Parse(HexString.Substring(Index * 2, 2), NumberStyles.HexNumber); + } + + return Output; + } + } +} diff --git a/Ryujinx.HLE/Utilities/StructReader.cs b/Ryujinx.HLE/Utilities/StructReader.cs new file mode 100644 index 00000000..6e942a9b --- /dev/null +++ b/Ryujinx.HLE/Utilities/StructReader.cs @@ -0,0 +1,45 @@ +using ChocolArm64.Memory; +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.Utilities +{ + class StructReader + { + private AMemory Memory; + + public long Position { get; private set; } + + public StructReader(AMemory Memory, long Position) + { + this.Memory = Memory; + this.Position = Position; + } + + public T Read() where T : struct + { + T Value = AMemoryHelper.Read(Memory, Position); + + Position += Marshal.SizeOf(); + + return Value; + } + + public T[] Read(int Size) where T : struct + { + int StructSize = Marshal.SizeOf(); + + int Count = Size / StructSize; + + T[] Output = new T[Count]; + + for (int Index = 0; Index < Count; Index++) + { + Output[Index] = AMemoryHelper.Read(Memory, Position); + + Position += StructSize; + } + + return Output; + } + } +} diff --git a/Ryujinx.HLE/Utilities/StructWriter.cs b/Ryujinx.HLE/Utilities/StructWriter.cs new file mode 100644 index 00000000..8b88105c --- /dev/null +++ b/Ryujinx.HLE/Utilities/StructWriter.cs @@ -0,0 +1,25 @@ +using ChocolArm64.Memory; +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.Utilities +{ + class StructWriter + { + private AMemory Memory; + + public long Position { get; private set; } + + public StructWriter(AMemory Memory, long Position) + { + this.Memory = Memory; + this.Position = Position; + } + + public void Write(T Value) where T : struct + { + AMemoryHelper.Write(Memory, Position, Value); + + Position += Marshal.SizeOf(); + } + } +} diff --git a/Ryujinx/Config.cs b/Ryujinx/Config.cs index ec0f05b7..2c02c50f 100644 --- a/Ryujinx/Config.cs +++ b/Ryujinx/Config.cs @@ -31,7 +31,7 @@ namespace Ryujinx Device.Log.SetEnable(LogLevel.Warning, Convert.ToBoolean(Parser.Value("Logging_Enable_Warn"))); Device.Log.SetEnable(LogLevel.Error, Convert.ToBoolean(Parser.Value("Logging_Enable_Error"))); - Device.Os.SystemState.DockedMode = Convert.ToBoolean(Parser.Value("Docked_Mode")); + Device.System.State.DockedMode = Convert.ToBoolean(Parser.Value("Docked_Mode")); string[] FilteredLogClasses = Parser.Value("Logging_Filtered_Classes").Split(',', StringSplitOptions.RemoveEmptyEntries); diff --git a/Ryujinx/Ui/GLScreen.cs b/Ryujinx/Ui/GLScreen.cs index dfc0b9a4..2c683f5e 100644 --- a/Ryujinx/Ui/GLScreen.cs +++ b/Ryujinx/Ui/GLScreen.cs @@ -4,7 +4,6 @@ using OpenTK.Input; using Ryujinx.Graphics.Gal; using Ryujinx.HLE; using Ryujinx.HLE.Input; -using Ryujinx.UI.Input; using System; using System.Threading; @@ -19,7 +18,7 @@ namespace Ryujinx private const int TargetFPS = 60; - private Switch Ns; + private Switch Device; private IGalRenderer Renderer; @@ -35,13 +34,13 @@ namespace Ryujinx private string NewTitle; - public GLScreen(Switch Ns, IGalRenderer Renderer) + public GLScreen(Switch Device, IGalRenderer Renderer) : base(1280, 720, new GraphicsMode(), "Ryujinx", 0, DisplayDevice.Default, 3, 3, GraphicsContextFlags.ForwardCompatible) { - this.Ns = Ns; + this.Device = Device; this.Renderer = Renderer; Location = new Point( @@ -63,9 +62,9 @@ namespace Ryujinx while (Exists && !IsExiting) { - if (Ns.WaitFifo()) + if (Device.WaitFifo()) { - Ns.ProcessFrame(); + Device.ProcessFrame(); } Renderer.RunActions(); @@ -152,7 +151,7 @@ namespace Ryujinx //Controller Input CurrentButton |= Config.JoyConController.GetButtons(); - + //Keyboard has priority stick-wise if (LeftJoystickDX == 0 && LeftJoystickDY == 0) { @@ -163,7 +162,7 @@ namespace Ryujinx { (RightJoystickDX, RightJoystickDY) = Config.JoyConController.GetRightStick(); } - + LeftJoystick = new HidJoystickPosition { DX = LeftJoystickDX, @@ -226,23 +225,23 @@ namespace Ryujinx HasTouch = true; - Ns.Hid.SetTouchPoints(CurrentPoint); + Device.Hid.SetTouchPoints(CurrentPoint); } } if (!HasTouch) { - Ns.Hid.SetTouchPoints(); + Device.Hid.SetTouchPoints(); } - Ns.Hid.SetJoyconButton( + Device.Hid.SetJoyconButton( HidControllerId.CONTROLLER_HANDHELD, HidControllerLayouts.Handheld_Joined, CurrentButton, LeftJoystick, RightJoystick); - Ns.Hid.SetJoyconButton( + Device.Hid.SetJoyconButton( HidControllerId.CONTROLLER_HANDHELD, HidControllerLayouts.Main, CurrentButton, @@ -254,10 +253,10 @@ namespace Ryujinx { Renderer.FrameBuffer.Render(); - Ns.Statistics.RecordSystemFrameTime(); + Device.Statistics.RecordSystemFrameTime(); - double HostFps = Ns.Statistics.GetSystemFrameRate(); - double GameFps = Ns.Statistics.GetGameFrameRate(); + double HostFps = Device.Statistics.GetSystemFrameRate(); + double GameFps = Device.Statistics.GetGameFrameRate(); NewTitle = $"Ryujinx | Host FPS: {HostFps:0.0} | Game FPS: {GameFps:0.0}"; @@ -265,7 +264,7 @@ namespace Ryujinx SwapBuffers(); - Ns.Os.SignalVsync(); + Device.System.SignalVsync(); } protected override void OnUnload(EventArgs e) diff --git a/Ryujinx/Ui/Program.cs b/Ryujinx/Ui/Program.cs index a0de2e9f..7acf73a5 100644 --- a/Ryujinx/Ui/Program.cs +++ b/Ryujinx/Ui/Program.cs @@ -18,11 +18,11 @@ namespace Ryujinx IAalOutput AudioOut = new OpenALAudioOut(); - Switch Ns = new Switch(Renderer, AudioOut); + Switch Device = new Switch(Renderer, AudioOut); - Config.Read(Ns); + Config.Read(Device); - Ns.Log.Updated += ConsoleLog.PrintLog; + Device.Log.Updated += ConsoleLog.PrintLog; if (args.Length == 1) { @@ -39,20 +39,20 @@ namespace Ryujinx { Console.WriteLine("Loading as cart with RomFS."); - Ns.LoadCart(args[0], RomFsFiles[0]); + Device.LoadCart(args[0], RomFsFiles[0]); } else { Console.WriteLine("Loading as cart WITHOUT RomFS."); - Ns.LoadCart(args[0]); + Device.LoadCart(args[0]); } } else if (File.Exists(args[0])) { Console.WriteLine("Loading as homebrew."); - Ns.LoadProgram(args[0]); + Device.LoadProgram(args[0]); } } else @@ -60,18 +60,14 @@ namespace Ryujinx Console.WriteLine("Please specify the folder with the NSOs/IStorage or a NSO/NRO."); } - using (GLScreen Screen = new GLScreen(Ns, Renderer)) + using (GLScreen Screen = new GLScreen(Device, Renderer)) { - Ns.Finish += (Sender, Args) => - { - Screen.Exit(); - }; - Screen.MainLoop(); - Ns.OnFinish(EventArgs.Empty); + + Device.Dispose(); } - Environment.Exit(0); + AudioOut.Dispose(); } } } -- cgit v1.2.3