From e174100474fcfe484cc8e93c4db447886096615d Mon Sep 17 00:00:00 2001 From: Ac_K Date: Sun, 25 Feb 2018 19:58:16 +0100 Subject: Implement many objects, improve logging. (#42) * Implement many objects, improve logging. Change and rename folders of Services Add Logging of IpcMessage. Add "lm" Log Service. Parse Errors of SetTerminateResult Add Svc Calls. Add many object implementations. * Corrections Forgotten Debug Conf * Corrections 2 * Corrections 3 * Corrections 4 --- CONFIG.md | 4 + Ryujinx.Core/Config.cs | 14 +- Ryujinx.Core/Logging.cs | 93 ++- Ryujinx.Core/OsHle/Handles/HThread.cs | 2 +- Ryujinx.Core/OsHle/Ipc/IpcLog.cs | 179 ++++++ Ryujinx.Core/OsHle/Ipc/IpcMessage.cs | 2 + .../IpcServices/Acc/IManagerForApplication.cs | 33 -- Ryujinx.Core/OsHle/IpcServices/Acc/IProfile.cs | 33 -- Ryujinx.Core/OsHle/IpcServices/Acc/ServiceAcc.cs | 49 -- .../OsHle/IpcServices/Am/IApplicationFunctions.cs | 80 --- .../OsHle/IpcServices/Am/IApplicationProxy.cs | 85 --- .../OsHle/IpcServices/Am/IAudioController.cs | 20 - .../OsHle/IpcServices/Am/ICommonStateGetter.cs | 74 --- .../OsHle/IpcServices/Am/IDebugFunctions.cs | 20 - .../OsHle/IpcServices/Am/IDisplayController.cs | 20 - .../OsHle/IpcServices/Am/ILibraryAppletCreator.cs | 20 - .../OsHle/IpcServices/Am/ISelfController.cs | 61 -- Ryujinx.Core/OsHle/IpcServices/Am/IStorage.cs | 33 -- .../OsHle/IpcServices/Am/IStorageAccessor.cs | 62 -- .../OsHle/IpcServices/Am/IWindowController.cs | 33 -- .../OsHle/IpcServices/Am/ServiceAppletOE.cs | 29 - .../OsHle/IpcServices/Android/GbpBuffer.cs | 60 -- .../OsHle/IpcServices/Android/NvFlinger.cs | 395 ------------- Ryujinx.Core/OsHle/IpcServices/Android/Parcel.cs | 58 -- Ryujinx.Core/OsHle/IpcServices/Apm/ISession.cs | 28 - Ryujinx.Core/OsHle/IpcServices/Apm/ServiceApm.cs | 29 - Ryujinx.Core/OsHle/IpcServices/Aud/IAudioOut.cs | 180 ------ .../OsHle/IpcServices/Aud/IAudioRenderer.cs | 66 --- .../OsHle/IpcServices/Aud/ServiceAudOut.cs | 57 -- .../OsHle/IpcServices/Aud/ServiceAudRen.cs | 51 -- Ryujinx.Core/OsHle/IpcServices/ErrorCode.cs | 10 - Ryujinx.Core/OsHle/IpcServices/ErrorModule.cs | 7 - .../OsHle/IpcServices/Friend/IFriendService.cs | 20 - .../OsHle/IpcServices/Friend/ServiceFriend.cs | 29 - Ryujinx.Core/OsHle/IpcServices/FspSrv/FsErr.cs | 9 - .../OsHle/IpcServices/FspSrv/IDirectory.cs | 117 ---- Ryujinx.Core/OsHle/IpcServices/FspSrv/IFile.cs | 111 ---- .../OsHle/IpcServices/FspSrv/IFileSystem.cs | 383 ------------- Ryujinx.Core/OsHle/IpcServices/FspSrv/IStorage.cs | 52 -- .../OsHle/IpcServices/FspSrv/ServiceFspSrv.cs | 67 --- .../IpcServices/Hid/IActiveVibrationDeviceList.cs | 17 - .../OsHle/IpcServices/Hid/IAppletResource.cs | 32 -- Ryujinx.Core/OsHle/IpcServices/Hid/ServiceHid.cs | 98 ---- Ryujinx.Core/OsHle/IpcServices/IIpcService.cs | 10 - Ryujinx.Core/OsHle/IpcServices/Lm/ServiceLm.cs | 27 - .../OsHle/IpcServices/NvServices/ServiceNvDrv.cs | 627 --------------------- Ryujinx.Core/OsHle/IpcServices/ObjHelper.cs | 24 - .../IpcServices/Pctl/IParentalControlService.cs | 20 - Ryujinx.Core/OsHle/IpcServices/Pctl/ServicePctl.cs | 29 - Ryujinx.Core/OsHle/IpcServices/Pl/ServicePl.cs | 51 -- Ryujinx.Core/OsHle/IpcServices/ServiceFactory.cs | 50 -- Ryujinx.Core/OsHle/IpcServices/Set/ServiceSet.cs | 46 -- Ryujinx.Core/OsHle/IpcServices/Sm/ServiceSm.cs | 67 --- .../OsHle/IpcServices/Time/ISteadyClock.cs | 20 - .../OsHle/IpcServices/Time/ISystemClock.cs | 42 -- .../OsHle/IpcServices/Time/ITimeZoneService.cs | 20 - Ryujinx.Core/OsHle/IpcServices/Time/ServiceTime.cs | 62 -- .../OsHle/IpcServices/Time/SystemClockType.cs | 9 - .../IpcServices/Vi/IApplicationDisplayService.cs | 176 ------ .../OsHle/IpcServices/Vi/IHOSBinderDriver.cs | 76 --- .../OsHle/IpcServices/Vi/IManagerDisplayService.cs | 33 -- .../OsHle/IpcServices/Vi/ISystemDisplayService.cs | 25 - Ryujinx.Core/OsHle/IpcServices/Vi/ServiceVi.cs | 31 - .../OsHle/Services/Acc/IManagerForApplication.cs | 33 ++ Ryujinx.Core/OsHle/Services/Acc/IProfile.cs | 33 ++ Ryujinx.Core/OsHle/Services/Acc/ServiceAcc.cs | 49 ++ .../OsHle/Services/Am/IApplicationFunctions.cs | 94 +++ .../OsHle/Services/Am/IApplicationProxy.cs | 85 +++ Ryujinx.Core/OsHle/Services/Am/IAudioController.cs | 20 + .../OsHle/Services/Am/ICommonStateGetter.cs | 74 +++ Ryujinx.Core/OsHle/Services/Am/IDebugFunctions.cs | 20 + .../OsHle/Services/Am/IDisplayController.cs | 20 + .../OsHle/Services/Am/ILibraryAppletCreator.cs | 20 + Ryujinx.Core/OsHle/Services/Am/ISelfController.cs | 75 +++ Ryujinx.Core/OsHle/Services/Am/IStorage.cs | 33 ++ Ryujinx.Core/OsHle/Services/Am/IStorageAccessor.cs | 62 ++ .../OsHle/Services/Am/IWindowController.cs | 33 ++ Ryujinx.Core/OsHle/Services/Am/ServiceAppletOE.cs | 29 + Ryujinx.Core/OsHle/Services/Apm/ISession.cs | 28 + Ryujinx.Core/OsHle/Services/Apm/ServiceApm.cs | 29 + Ryujinx.Core/OsHle/Services/Aud/IAudioOut.cs | 180 ++++++ Ryujinx.Core/OsHle/Services/Aud/IAudioRenderer.cs | 66 +++ Ryujinx.Core/OsHle/Services/Aud/ServiceAudOut.cs | 57 ++ Ryujinx.Core/OsHle/Services/Aud/ServiceAudRen.cs | 51 ++ Ryujinx.Core/OsHle/Services/ErrorCode.cs | 10 + Ryujinx.Core/OsHle/Services/ErrorModule.cs | 63 +++ .../OsHle/Services/Friend/IFriendService.cs | 20 + .../OsHle/Services/Friend/ServiceFriend.cs | 29 + Ryujinx.Core/OsHle/Services/FspSrv/FsErr.cs | 9 + Ryujinx.Core/OsHle/Services/FspSrv/IDirectory.cs | 117 ++++ Ryujinx.Core/OsHle/Services/FspSrv/IFile.cs | 111 ++++ Ryujinx.Core/OsHle/Services/FspSrv/IFileSystem.cs | 383 +++++++++++++ Ryujinx.Core/OsHle/Services/FspSrv/IStorage.cs | 52 ++ .../OsHle/Services/FspSrv/ServiceFspSrv.cs | 67 +++ .../Services/Hid/IActiveVibrationDeviceList.cs | 27 + Ryujinx.Core/OsHle/Services/Hid/IAppletResource.cs | 32 ++ Ryujinx.Core/OsHle/Services/Hid/ServiceHid.cs | 108 ++++ Ryujinx.Core/OsHle/Services/IIpcService.cs | 10 + Ryujinx.Core/OsHle/Services/Lm/ILogger.cs | 143 +++++ Ryujinx.Core/OsHle/Services/Lm/ServiceLm.cs | 31 + Ryujinx.Core/OsHle/Services/Ns/ServiceNs.cs | 20 + Ryujinx.Core/OsHle/Services/Nv/ServiceNvDrv.cs | 627 +++++++++++++++++++++ Ryujinx.Core/OsHle/Services/ObjHelper.cs | 24 + .../OsHle/Services/Pctl/IParentalControlService.cs | 20 + Ryujinx.Core/OsHle/Services/Pctl/ServicePctl.cs | 29 + Ryujinx.Core/OsHle/Services/Pl/ServicePl.cs | 51 ++ Ryujinx.Core/OsHle/Services/ServiceFactory.cs | 54 ++ Ryujinx.Core/OsHle/Services/Set/ServiceSet.cs | 46 ++ Ryujinx.Core/OsHle/Services/Sm/ServiceSm.cs | 67 +++ Ryujinx.Core/OsHle/Services/Time/ISteadyClock.cs | 20 + Ryujinx.Core/OsHle/Services/Time/ISystemClock.cs | 42 ++ .../OsHle/Services/Time/ITimeZoneService.cs | 69 +++ Ryujinx.Core/OsHle/Services/Time/ServiceTime.cs | 62 ++ .../OsHle/Services/Time/SystemClockType.cs | 9 + Ryujinx.Core/OsHle/Services/Vi/GbpBuffer.cs | 60 ++ .../Services/Vi/IApplicationDisplayService.cs | 176 ++++++ Ryujinx.Core/OsHle/Services/Vi/IHOSBinderDriver.cs | 76 +++ .../OsHle/Services/Vi/IManagerDisplayService.cs | 33 ++ .../OsHle/Services/Vi/ISystemDisplayService.cs | 25 + Ryujinx.Core/OsHle/Services/Vi/NvFlinger.cs | 395 +++++++++++++ Ryujinx.Core/OsHle/Services/Vi/Parcel.cs | 58 ++ Ryujinx.Core/OsHle/Services/Vi/ServiceVi.cs | 31 + Ryujinx.Core/OsHle/Svc/SvcHandler.cs | 3 + Ryujinx.Core/OsHle/Svc/SvcThread.cs | 39 ++ Ryujinx/Ryujinx.conf | 3 + 125 files changed, 4621 insertions(+), 3988 deletions(-) create mode 100644 Ryujinx.Core/OsHle/Ipc/IpcLog.cs delete mode 100644 Ryujinx.Core/OsHle/IpcServices/Acc/IManagerForApplication.cs delete mode 100644 Ryujinx.Core/OsHle/IpcServices/Acc/IProfile.cs delete mode 100644 Ryujinx.Core/OsHle/IpcServices/Acc/ServiceAcc.cs delete mode 100644 Ryujinx.Core/OsHle/IpcServices/Am/IApplicationFunctions.cs delete mode 100644 Ryujinx.Core/OsHle/IpcServices/Am/IApplicationProxy.cs delete mode 100644 Ryujinx.Core/OsHle/IpcServices/Am/IAudioController.cs delete mode 100644 Ryujinx.Core/OsHle/IpcServices/Am/ICommonStateGetter.cs delete mode 100644 Ryujinx.Core/OsHle/IpcServices/Am/IDebugFunctions.cs delete mode 100644 Ryujinx.Core/OsHle/IpcServices/Am/IDisplayController.cs delete mode 100644 Ryujinx.Core/OsHle/IpcServices/Am/ILibraryAppletCreator.cs delete mode 100644 Ryujinx.Core/OsHle/IpcServices/Am/ISelfController.cs delete mode 100644 Ryujinx.Core/OsHle/IpcServices/Am/IStorage.cs delete mode 100644 Ryujinx.Core/OsHle/IpcServices/Am/IStorageAccessor.cs delete mode 100644 Ryujinx.Core/OsHle/IpcServices/Am/IWindowController.cs delete mode 100644 Ryujinx.Core/OsHle/IpcServices/Am/ServiceAppletOE.cs delete mode 100644 Ryujinx.Core/OsHle/IpcServices/Android/GbpBuffer.cs delete mode 100644 Ryujinx.Core/OsHle/IpcServices/Android/NvFlinger.cs delete mode 100644 Ryujinx.Core/OsHle/IpcServices/Android/Parcel.cs delete mode 100644 Ryujinx.Core/OsHle/IpcServices/Apm/ISession.cs delete mode 100644 Ryujinx.Core/OsHle/IpcServices/Apm/ServiceApm.cs delete mode 100644 Ryujinx.Core/OsHle/IpcServices/Aud/IAudioOut.cs delete mode 100644 Ryujinx.Core/OsHle/IpcServices/Aud/IAudioRenderer.cs delete mode 100644 Ryujinx.Core/OsHle/IpcServices/Aud/ServiceAudOut.cs delete mode 100644 Ryujinx.Core/OsHle/IpcServices/Aud/ServiceAudRen.cs delete mode 100644 Ryujinx.Core/OsHle/IpcServices/ErrorCode.cs delete mode 100644 Ryujinx.Core/OsHle/IpcServices/ErrorModule.cs delete mode 100644 Ryujinx.Core/OsHle/IpcServices/Friend/IFriendService.cs delete mode 100644 Ryujinx.Core/OsHle/IpcServices/Friend/ServiceFriend.cs delete mode 100644 Ryujinx.Core/OsHle/IpcServices/FspSrv/FsErr.cs delete mode 100644 Ryujinx.Core/OsHle/IpcServices/FspSrv/IDirectory.cs delete mode 100644 Ryujinx.Core/OsHle/IpcServices/FspSrv/IFile.cs delete mode 100644 Ryujinx.Core/OsHle/IpcServices/FspSrv/IFileSystem.cs delete mode 100644 Ryujinx.Core/OsHle/IpcServices/FspSrv/IStorage.cs delete mode 100644 Ryujinx.Core/OsHle/IpcServices/FspSrv/ServiceFspSrv.cs delete mode 100644 Ryujinx.Core/OsHle/IpcServices/Hid/IActiveVibrationDeviceList.cs delete mode 100644 Ryujinx.Core/OsHle/IpcServices/Hid/IAppletResource.cs delete mode 100644 Ryujinx.Core/OsHle/IpcServices/Hid/ServiceHid.cs delete mode 100644 Ryujinx.Core/OsHle/IpcServices/IIpcService.cs delete mode 100644 Ryujinx.Core/OsHle/IpcServices/Lm/ServiceLm.cs delete mode 100644 Ryujinx.Core/OsHle/IpcServices/NvServices/ServiceNvDrv.cs delete mode 100644 Ryujinx.Core/OsHle/IpcServices/ObjHelper.cs delete mode 100644 Ryujinx.Core/OsHle/IpcServices/Pctl/IParentalControlService.cs delete mode 100644 Ryujinx.Core/OsHle/IpcServices/Pctl/ServicePctl.cs delete mode 100644 Ryujinx.Core/OsHle/IpcServices/Pl/ServicePl.cs delete mode 100644 Ryujinx.Core/OsHle/IpcServices/ServiceFactory.cs delete mode 100644 Ryujinx.Core/OsHle/IpcServices/Set/ServiceSet.cs delete mode 100644 Ryujinx.Core/OsHle/IpcServices/Sm/ServiceSm.cs delete mode 100644 Ryujinx.Core/OsHle/IpcServices/Time/ISteadyClock.cs delete mode 100644 Ryujinx.Core/OsHle/IpcServices/Time/ISystemClock.cs delete mode 100644 Ryujinx.Core/OsHle/IpcServices/Time/ITimeZoneService.cs delete mode 100644 Ryujinx.Core/OsHle/IpcServices/Time/ServiceTime.cs delete mode 100644 Ryujinx.Core/OsHle/IpcServices/Time/SystemClockType.cs delete mode 100644 Ryujinx.Core/OsHle/IpcServices/Vi/IApplicationDisplayService.cs delete mode 100644 Ryujinx.Core/OsHle/IpcServices/Vi/IHOSBinderDriver.cs delete mode 100644 Ryujinx.Core/OsHle/IpcServices/Vi/IManagerDisplayService.cs delete mode 100644 Ryujinx.Core/OsHle/IpcServices/Vi/ISystemDisplayService.cs delete mode 100644 Ryujinx.Core/OsHle/IpcServices/Vi/ServiceVi.cs create mode 100644 Ryujinx.Core/OsHle/Services/Acc/IManagerForApplication.cs create mode 100644 Ryujinx.Core/OsHle/Services/Acc/IProfile.cs create mode 100644 Ryujinx.Core/OsHle/Services/Acc/ServiceAcc.cs create mode 100644 Ryujinx.Core/OsHle/Services/Am/IApplicationFunctions.cs create mode 100644 Ryujinx.Core/OsHle/Services/Am/IApplicationProxy.cs create mode 100644 Ryujinx.Core/OsHle/Services/Am/IAudioController.cs create mode 100644 Ryujinx.Core/OsHle/Services/Am/ICommonStateGetter.cs create mode 100644 Ryujinx.Core/OsHle/Services/Am/IDebugFunctions.cs create mode 100644 Ryujinx.Core/OsHle/Services/Am/IDisplayController.cs create mode 100644 Ryujinx.Core/OsHle/Services/Am/ILibraryAppletCreator.cs create mode 100644 Ryujinx.Core/OsHle/Services/Am/ISelfController.cs create mode 100644 Ryujinx.Core/OsHle/Services/Am/IStorage.cs create mode 100644 Ryujinx.Core/OsHle/Services/Am/IStorageAccessor.cs create mode 100644 Ryujinx.Core/OsHle/Services/Am/IWindowController.cs create mode 100644 Ryujinx.Core/OsHle/Services/Am/ServiceAppletOE.cs create mode 100644 Ryujinx.Core/OsHle/Services/Apm/ISession.cs create mode 100644 Ryujinx.Core/OsHle/Services/Apm/ServiceApm.cs create mode 100644 Ryujinx.Core/OsHle/Services/Aud/IAudioOut.cs create mode 100644 Ryujinx.Core/OsHle/Services/Aud/IAudioRenderer.cs create mode 100644 Ryujinx.Core/OsHle/Services/Aud/ServiceAudOut.cs create mode 100644 Ryujinx.Core/OsHle/Services/Aud/ServiceAudRen.cs create mode 100644 Ryujinx.Core/OsHle/Services/ErrorCode.cs create mode 100644 Ryujinx.Core/OsHle/Services/ErrorModule.cs create mode 100644 Ryujinx.Core/OsHle/Services/Friend/IFriendService.cs create mode 100644 Ryujinx.Core/OsHle/Services/Friend/ServiceFriend.cs create mode 100644 Ryujinx.Core/OsHle/Services/FspSrv/FsErr.cs create mode 100644 Ryujinx.Core/OsHle/Services/FspSrv/IDirectory.cs create mode 100644 Ryujinx.Core/OsHle/Services/FspSrv/IFile.cs create mode 100644 Ryujinx.Core/OsHle/Services/FspSrv/IFileSystem.cs create mode 100644 Ryujinx.Core/OsHle/Services/FspSrv/IStorage.cs create mode 100644 Ryujinx.Core/OsHle/Services/FspSrv/ServiceFspSrv.cs create mode 100644 Ryujinx.Core/OsHle/Services/Hid/IActiveVibrationDeviceList.cs create mode 100644 Ryujinx.Core/OsHle/Services/Hid/IAppletResource.cs create mode 100644 Ryujinx.Core/OsHle/Services/Hid/ServiceHid.cs create mode 100644 Ryujinx.Core/OsHle/Services/IIpcService.cs create mode 100644 Ryujinx.Core/OsHle/Services/Lm/ILogger.cs create mode 100644 Ryujinx.Core/OsHle/Services/Lm/ServiceLm.cs create mode 100644 Ryujinx.Core/OsHle/Services/Ns/ServiceNs.cs create mode 100644 Ryujinx.Core/OsHle/Services/Nv/ServiceNvDrv.cs create mode 100644 Ryujinx.Core/OsHle/Services/ObjHelper.cs create mode 100644 Ryujinx.Core/OsHle/Services/Pctl/IParentalControlService.cs create mode 100644 Ryujinx.Core/OsHle/Services/Pctl/ServicePctl.cs create mode 100644 Ryujinx.Core/OsHle/Services/Pl/ServicePl.cs create mode 100644 Ryujinx.Core/OsHle/Services/ServiceFactory.cs create mode 100644 Ryujinx.Core/OsHle/Services/Set/ServiceSet.cs create mode 100644 Ryujinx.Core/OsHle/Services/Sm/ServiceSm.cs create mode 100644 Ryujinx.Core/OsHle/Services/Time/ISteadyClock.cs create mode 100644 Ryujinx.Core/OsHle/Services/Time/ISystemClock.cs create mode 100644 Ryujinx.Core/OsHle/Services/Time/ITimeZoneService.cs create mode 100644 Ryujinx.Core/OsHle/Services/Time/ServiceTime.cs create mode 100644 Ryujinx.Core/OsHle/Services/Time/SystemClockType.cs create mode 100644 Ryujinx.Core/OsHle/Services/Vi/GbpBuffer.cs create mode 100644 Ryujinx.Core/OsHle/Services/Vi/IApplicationDisplayService.cs create mode 100644 Ryujinx.Core/OsHle/Services/Vi/IHOSBinderDriver.cs create mode 100644 Ryujinx.Core/OsHle/Services/Vi/IManagerDisplayService.cs create mode 100644 Ryujinx.Core/OsHle/Services/Vi/ISystemDisplayService.cs create mode 100644 Ryujinx.Core/OsHle/Services/Vi/NvFlinger.cs create mode 100644 Ryujinx.Core/OsHle/Services/Vi/Parcel.cs create mode 100644 Ryujinx.Core/OsHle/Services/Vi/ServiceVi.cs diff --git a/CONFIG.md b/CONFIG.md index 09fa13b7..764eb528 100644 --- a/CONFIG.md +++ b/CONFIG.md @@ -26,6 +26,10 @@ Enable the Fatal Logging (Enabled in Debug recommanded). +- `Logging_Enable_Ipc` *(bool)* + + Enable the Ipc Message Logging. + - `Logging_Enable_LogFile` *(bool)* Enable writing the logging inside a Ryujinx.log file. diff --git a/Ryujinx.Core/Config.cs b/Ryujinx.Core/Config.cs index b97e80b8..7db49319 100644 --- a/Ryujinx.Core/Config.cs +++ b/Ryujinx.Core/Config.cs @@ -8,12 +8,13 @@ namespace Ryujinx.Core { public static class Config { - public static bool LoggingEnableInfo { get; private set; } - public static bool LoggingEnableTrace { get; private set; } - public static bool LoggingEnableDebug { get; private set; } - public static bool LoggingEnableWarn { get; private set; } - public static bool LoggingEnableError { get; private set; } - public static bool LoggingEnableFatal { get; private set; } + public static bool LoggingEnableInfo { get; private set; } + public static bool LoggingEnableTrace { get; private set; } + public static bool LoggingEnableDebug { get; private set; } + public static bool LoggingEnableWarn { get; private set; } + public static bool LoggingEnableError { get; private set; } + public static bool LoggingEnableFatal { get; private set; } + public static bool LoggingEnableIpc { get; private set; } public static bool LoggingEnableLogFile { get; private set; } public static JoyCon FakeJoyCon { get; private set; } @@ -30,6 +31,7 @@ namespace Ryujinx.Core LoggingEnableWarn = Convert.ToBoolean(Parser.Value("Logging_Enable_Warn")); LoggingEnableError = Convert.ToBoolean(Parser.Value("Logging_Enable_Error")); LoggingEnableFatal = Convert.ToBoolean(Parser.Value("Logging_Enable_Fatal")); + LoggingEnableIpc = Convert.ToBoolean(Parser.Value("Logging_Enable_Ipc")); LoggingEnableLogFile = Convert.ToBoolean(Parser.Value("Logging_Enable_LogFile")); FakeJoyCon = new JoyCon diff --git a/Ryujinx.Core/Logging.cs b/Ryujinx.Core/Logging.cs index e14e5587..b14f2665 100644 --- a/Ryujinx.Core/Logging.cs +++ b/Ryujinx.Core/Logging.cs @@ -1,6 +1,8 @@ -using System; +using Ryujinx.Core.OsHle.Ipc; +using System; using System.Diagnostics; using System.IO; +using System.Text; namespace Ryujinx.Core { @@ -9,13 +11,14 @@ namespace Ryujinx.Core private static Stopwatch ExecutionTime = new Stopwatch(); private const string LogFileName = "Ryujinx.log"; - public static bool EnableInfo = Config.LoggingEnableInfo; - public static bool EnableTrace = Config.LoggingEnableTrace; - public static bool EnableDebug = Config.LoggingEnableDebug; - public static bool EnableWarn = Config.LoggingEnableWarn; - public static bool EnableError = Config.LoggingEnableError; - public static bool EnableFatal = Config.LoggingEnableFatal; - public static bool EnableLogFile = Config.LoggingEnableLogFile; + private static bool EnableInfo = Config.LoggingEnableInfo; + private static bool EnableTrace = Config.LoggingEnableTrace; + private static bool EnableDebug = Config.LoggingEnableDebug; + private static bool EnableWarn = Config.LoggingEnableWarn; + private static bool EnableError = Config.LoggingEnableError; + private static bool EnableFatal = Config.LoggingEnableFatal; + private static bool EnableIpc = Config.LoggingEnableIpc; + private static bool EnableLogFile = Config.LoggingEnableLogFile; static Logging() { @@ -128,5 +131,79 @@ namespace Ryujinx.Core LogFile(Text); } } + + public static void Ipc(byte[] Data, long CmdPtr, bool Domain) + { + if (EnableIpc) + { + Console.ForegroundColor = ConsoleColor.Cyan; + Console.WriteLine(IpcLog.Message(Data, CmdPtr, Domain)); + Console.ResetColor(); + } + } + + //https://www.codeproject.com/Articles/36747/Quick-and-Dirty-HexDump-of-a-Byte-Array + public static string HexDump(byte[] bytes, int bytesPerLine = 16) + { + if (bytes == null) return ""; + int bytesLength = bytes.Length; + + char[] HexChars = "0123456789ABCDEF".ToCharArray(); + + int firstHexColumn = + 8 // 8 characters for the address + + 3; // 3 spaces + + int firstCharColumn = firstHexColumn + + bytesPerLine * 3 // - 2 digit for the hexadecimal value and 1 space + + (bytesPerLine - 1) / 8 // - 1 extra space every 8 characters from the 9th + + 2; // 2 spaces + + int lineLength = firstCharColumn + + bytesPerLine // - characters to show the ascii value + + Environment.NewLine.Length; // Carriage return and line feed (should normally be 2) + + char[] line = (new String(' ', lineLength - Environment.NewLine.Length) + Environment.NewLine).ToCharArray(); + int expectedLines = (bytesLength + bytesPerLine - 1) / bytesPerLine; + StringBuilder result = new StringBuilder(expectedLines * lineLength); + + for (int i = 0; i < bytesLength; i += bytesPerLine) + { + line[0] = HexChars[(i >> 28) & 0xF]; + line[1] = HexChars[(i >> 24) & 0xF]; + line[2] = HexChars[(i >> 20) & 0xF]; + line[3] = HexChars[(i >> 16) & 0xF]; + line[4] = HexChars[(i >> 12) & 0xF]; + line[5] = HexChars[(i >> 8) & 0xF]; + line[6] = HexChars[(i >> 4) & 0xF]; + line[7] = HexChars[(i >> 0) & 0xF]; + + int hexColumn = firstHexColumn; + int charColumn = firstCharColumn; + + for (int j = 0; j < bytesPerLine; j++) + { + if (j > 0 && (j & 7) == 0) hexColumn++; + if (i + j >= bytesLength) + { + line[hexColumn] = ' '; + line[hexColumn + 1] = ' '; + line[charColumn] = ' '; + } + else + { + byte b = bytes[i + j]; + line[hexColumn] = HexChars[(b >> 4) & 0xF]; + line[hexColumn + 1] = HexChars[b & 0xF]; + line[charColumn] = (b < 32 ? '·' : (char)b); + } + hexColumn += 3; + charColumn++; + } + + result.Append(line); + } + return result.ToString(); + } } } diff --git a/Ryujinx.Core/OsHle/Handles/HThread.cs b/Ryujinx.Core/OsHle/Handles/HThread.cs index 8bb276fa..c631cedc 100644 --- a/Ryujinx.Core/OsHle/Handles/HThread.cs +++ b/Ryujinx.Core/OsHle/Handles/HThread.cs @@ -7,7 +7,7 @@ namespace Ryujinx.Core.OsHle.Handles public AThread Thread { get; private set; } public int ProcessorId { get; private set; } - public int Priority { get; private set; } + public int Priority { get; set; } public int ThreadId => Thread.ThreadId; diff --git a/Ryujinx.Core/OsHle/Ipc/IpcLog.cs b/Ryujinx.Core/OsHle/Ipc/IpcLog.cs new file mode 100644 index 00000000..dfec7ccf --- /dev/null +++ b/Ryujinx.Core/OsHle/Ipc/IpcLog.cs @@ -0,0 +1,179 @@ +using System; +using System.IO; + +namespace Ryujinx.Core.OsHle.Ipc +{ + public static class IpcLog + { + public static string Message(byte[] Data, long CmdPtr, bool Domain) + { + string IpcMessage = ""; + + using (MemoryStream MS = new MemoryStream(Data)) + { + BinaryReader Reader = new BinaryReader(MS); + + int Word0 = Reader.ReadInt32(); + int Word1 = Reader.ReadInt32(); + + int Type = (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; + + IpcMessage += Environment.NewLine + $" {Logging.GetExecutionTime()} | IpcMessage >" + Environment.NewLine + + $" Type: {Enum.GetName(typeof(IpcMessageType), Type)}" + Environment.NewLine + + + $" PtrBuffCount: {PtrBuffCount.ToString()}" + Environment.NewLine + + $" SendBuffCount: {SendBuffCount.ToString()}" + Environment.NewLine + + $" RecvBuffCount: {RecvBuffCount.ToString()}" + Environment.NewLine + + $" XchgBuffCount: {XchgBuffCount.ToString()}" + Environment.NewLine + + + $" RawDataSize: {RawDataSize.ToString()}" + Environment.NewLine + + $" RecvListFlags: {RecvListFlags.ToString()}" + Environment.NewLine + + $" HndDescEnable: {HndDescEnable.ToString()}" + Environment.NewLine; + + if (HndDescEnable) + { + int Word = Reader.ReadInt32(); + + bool HasPId = (Word & 1) != 0; + + int[] ToCopy = new int[(Word >> 1) & 0xf]; + int[] ToMove = new int[(Word >> 5) & 0xf]; + + long 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(); + } + + IpcMessage += Environment.NewLine + " HndDesc:" + Environment.NewLine + + $" PId: {PId.ToString()}" + Environment.NewLine + + $" ToCopy.Length: {ToCopy.Length.ToString()}" + Environment.NewLine + + $" ToMove.Length: {ToMove.Length.ToString()}" + Environment.NewLine; + } + + for (int Index = 0; Index < PtrBuffCount; Index++) + { + long IpcPtrBuffDescWord0 = Reader.ReadUInt32(); + long IpcPtrBuffDescWord1 = Reader.ReadUInt32(); + + long Position = IpcPtrBuffDescWord1; + Position |= (IpcPtrBuffDescWord0 << 20) & 0x0f00000000; + Position |= (IpcPtrBuffDescWord0 << 30) & 0x7000000000; + + int IpcPtrBuffDescIndex = ((int)IpcPtrBuffDescWord0 >> 0) & 0x03f; + IpcPtrBuffDescIndex |= ((int)IpcPtrBuffDescWord0 >> 3) & 0x1c0; + + short Size = (short)(IpcPtrBuffDescWord0 >> 16); + + IpcMessage += Environment.NewLine + $" PtrBuff[{Index}]:" + Environment.NewLine + + $" Position: {Position.ToString()}" + Environment.NewLine + + $" IpcPtrBuffDescIndex: {IpcPtrBuffDescIndex.ToString()}" + Environment.NewLine + + $" Size: {Size.ToString()}" + Environment.NewLine; + } + + ReadIpcBuffValues(Reader, SendBuffCount, IpcMessage, "SendBuff"); + ReadIpcBuffValues(Reader, RecvBuffCount, IpcMessage, "RecvBuff"); + ReadIpcBuffValues(Reader, XchgBuffCount, IpcMessage, "XchgBuff"); + + RawDataSize *= 4; + + long RecvListPos = Reader.BaseStream.Position + RawDataSize; + long Pad0 = 0; + + if ((Reader.BaseStream.Position + CmdPtr & 0xf) != 0) + { + Pad0 = 0x10 - (Reader.BaseStream.Position + CmdPtr & 0xf); + } + + Reader.BaseStream.Seek(Pad0, SeekOrigin.Current); + + int RecvListCount = RecvListFlags - 2; + + if (RecvListCount == 0) + { + RecvListCount = 1; + } + else if (RecvListCount < 0) + { + RecvListCount = 0; + } + + if (Domain && (IpcMessageType)Type == IpcMessageType.Request) + { + int DomWord0 = Reader.ReadInt32(); + + int DomCmd = (DomWord0 & 0xff); + + RawDataSize = (DomWord0 >> 16) & 0xffff; + + int DomObjId = Reader.ReadInt32(); + + Reader.ReadInt64(); //Padding + + IpcMessage += Environment.NewLine + $" Domain:" + Environment.NewLine + + $" DomCmd: {Enum.GetName(typeof(IpcDomCmd), DomCmd)}" + Environment.NewLine + + $" DomObjId: {DomObjId.ToString()}" + Environment.NewLine; + } + + byte[] RawData = Reader.ReadBytes(RawDataSize); + + IpcMessage += Environment.NewLine + $" RawData:" + Environment.NewLine + Logging.HexDump(RawData); + + Reader.BaseStream.Seek(RecvListPos, SeekOrigin.Begin); + + for (int Index = 0; Index < RecvListCount; Index++) + { + long RecvListBuffValue = Reader.ReadInt64(); + long RecvListBuffPosition = RecvListBuffValue & 0xffffffffffff; + long RecvListBuffSize = (short)(RecvListBuffValue >> 48); + + IpcMessage += Environment.NewLine + $" RecvList[{Index}]:" + Environment.NewLine + + $" Value: {RecvListBuffValue.ToString()}" + Environment.NewLine + + $" Position: {RecvListBuffPosition.ToString()}" + Environment.NewLine + + $" Size: {RecvListBuffSize.ToString()}" + Environment.NewLine; + } + } + + return IpcMessage; + } + + private static void ReadIpcBuffValues(BinaryReader Reader, int Count, string IpcMessage, string BufferName) + { + for (int Index = 0; Index < Count; Index++) + { + long Word0 = Reader.ReadUInt32(); + long Word1 = Reader.ReadUInt32(); + long Word2 = Reader.ReadUInt32(); + + long Position = Word1; + Position |= (Word2 << 4) & 0x0f00000000; + Position |= (Word2 << 34) & 0x7000000000; + + long Size = Word0; + Size |= (Word2 << 8) & 0xf00000000; + + int Flags = (int)Word2 & 3; + + IpcMessage += Environment.NewLine + $" {BufferName}[{Index}]:" + Environment.NewLine + + $" Position: {Position.ToString()}" + Environment.NewLine + + $" Flags: {Flags.ToString()}" + Environment.NewLine + + $" Size: {Size.ToString()}" + Environment.NewLine; + } + } + } +} diff --git a/Ryujinx.Core/OsHle/Ipc/IpcMessage.cs b/Ryujinx.Core/OsHle/Ipc/IpcMessage.cs index 447f3f9a..cc26df10 100644 --- a/Ryujinx.Core/OsHle/Ipc/IpcMessage.cs +++ b/Ryujinx.Core/OsHle/Ipc/IpcMessage.cs @@ -41,6 +41,8 @@ namespace Ryujinx.Core.OsHle.Ipc public IpcMessage(byte[] Data, long CmdPtr, bool Domain) : this() { + Logging.Ipc(Data, CmdPtr, Domain); + using (MemoryStream MS = new MemoryStream(Data)) { BinaryReader Reader = new BinaryReader(MS); diff --git a/Ryujinx.Core/OsHle/IpcServices/Acc/IManagerForApplication.cs b/Ryujinx.Core/OsHle/IpcServices/Acc/IManagerForApplication.cs deleted file mode 100644 index ab491eac..00000000 --- a/Ryujinx.Core/OsHle/IpcServices/Acc/IManagerForApplication.cs +++ /dev/null @@ -1,33 +0,0 @@ -using Ryujinx.Core.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.Core.OsHle.IpcServices.Acc -{ - class IManagerForApplication : IIpcService - { - private Dictionary m_Commands; - - public IReadOnlyDictionary Commands => m_Commands; - - public IManagerForApplication() - { - m_Commands = new Dictionary() - { - { 0, CheckAvailability }, - { 1, GetAccountId } - }; - } - - public long CheckAvailability(ServiceCtx Context) - { - return 0; - } - - public long GetAccountId(ServiceCtx Context) - { - Context.ResponseData.Write(0xcafeL); - - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/IpcServices/Acc/IProfile.cs b/Ryujinx.Core/OsHle/IpcServices/Acc/IProfile.cs deleted file mode 100644 index 77fe2b48..00000000 --- a/Ryujinx.Core/OsHle/IpcServices/Acc/IProfile.cs +++ /dev/null @@ -1,33 +0,0 @@ -using Ryujinx.Core.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.Core.OsHle.IpcServices.Acc -{ - class IProfile : IIpcService - { - private Dictionary m_Commands; - - public IReadOnlyDictionary Commands => m_Commands; - - public IProfile() - { - m_Commands = new Dictionary() - { - { 1, GetBase } - }; - } - - public long GetBase(ServiceCtx Context) - { - Context.ResponseData.Write(0L); - Context.ResponseData.Write(0L); - Context.ResponseData.Write(0L); - Context.ResponseData.Write(0L); - Context.ResponseData.Write(0L); - Context.ResponseData.Write(0L); - Context.ResponseData.Write(0L); - - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/IpcServices/Acc/ServiceAcc.cs b/Ryujinx.Core/OsHle/IpcServices/Acc/ServiceAcc.cs deleted file mode 100644 index 8844bb5d..00000000 --- a/Ryujinx.Core/OsHle/IpcServices/Acc/ServiceAcc.cs +++ /dev/null @@ -1,49 +0,0 @@ -using Ryujinx.Core.OsHle.Ipc; -using System.Collections.Generic; - -using static Ryujinx.Core.OsHle.IpcServices.ObjHelper; - -namespace Ryujinx.Core.OsHle.IpcServices.Acc -{ - class ServiceAcc : IIpcService - { - private Dictionary m_Commands; - - public IReadOnlyDictionary Commands => m_Commands; - - public ServiceAcc() - { - m_Commands = new Dictionary() - { - { 3, ListOpenUsers }, - { 5, GetProfile }, - { 100, InitializeApplicationInfo }, - { 101, GetBaasAccountManagerForApplication } - }; - } - - public long ListOpenUsers(ServiceCtx Context) - { - return 0; - } - - public long GetProfile(ServiceCtx Context) - { - MakeObject(Context, new IProfile()); - - return 0; - } - - public long InitializeApplicationInfo(ServiceCtx Context) - { - return 0; - } - - public long GetBaasAccountManagerForApplication(ServiceCtx Context) - { - MakeObject(Context, new IManagerForApplication()); - - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/IpcServices/Am/IApplicationFunctions.cs b/Ryujinx.Core/OsHle/IpcServices/Am/IApplicationFunctions.cs deleted file mode 100644 index 30020c1d..00000000 --- a/Ryujinx.Core/OsHle/IpcServices/Am/IApplicationFunctions.cs +++ /dev/null @@ -1,80 +0,0 @@ -using Ryujinx.Core.OsHle.Ipc; -using System.Collections.Generic; -using System.IO; - -using static Ryujinx.Core.OsHle.IpcServices.ObjHelper; - -namespace Ryujinx.Core.OsHle.IpcServices.Am -{ - class IApplicationFunctions : IIpcService - { - private Dictionary m_Commands; - - public IReadOnlyDictionary Commands => m_Commands; - - public IApplicationFunctions() - { - m_Commands = new Dictionary() - { - { 1, PopLaunchParameter }, - { 20, EnsureSaveData }, - { 21, GetDesiredLanguage }, - { 40, NotifyRunning } - }; - } - - private const uint LaunchParamsMagic = 0xc79497ca; - - public long PopLaunchParameter(ServiceCtx Context) - { - //Only the first 0x18 bytes of the Data seems to be actually used. - MakeObject(Context, new IStorage(MakeLaunchParams())); - - return 0; - } - - public long EnsureSaveData(ServiceCtx Context) - { - long UIdLow = Context.RequestData.ReadInt64(); - long UIdHigh = Context.RequestData.ReadInt64(); - - Context.ResponseData.Write(0L); - - return 0; - } - - public long GetDesiredLanguage(ServiceCtx Context) - { - //This is an enumerator where each number is a differnet language. - //0 is Japanese and 1 is English, need to figure out the other codes. - Context.ResponseData.Write(1L); - - return 0; - } - - public long NotifyRunning(ServiceCtx Context) - { - Context.ResponseData.Write(1); - - return 0; - } - - private 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(); - } - } - } -} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/IpcServices/Am/IApplicationProxy.cs b/Ryujinx.Core/OsHle/IpcServices/Am/IApplicationProxy.cs deleted file mode 100644 index 5417d7f0..00000000 --- a/Ryujinx.Core/OsHle/IpcServices/Am/IApplicationProxy.cs +++ /dev/null @@ -1,85 +0,0 @@ -using Ryujinx.Core.OsHle.Ipc; -using System.Collections.Generic; - -using static Ryujinx.Core.OsHle.IpcServices.ObjHelper; - -namespace Ryujinx.Core.OsHle.IpcServices.Am -{ - class IApplicationProxy : IIpcService - { - private Dictionary m_Commands; - - public 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.Core/OsHle/IpcServices/Am/IAudioController.cs b/Ryujinx.Core/OsHle/IpcServices/Am/IAudioController.cs deleted file mode 100644 index 1212f1e2..00000000 --- a/Ryujinx.Core/OsHle/IpcServices/Am/IAudioController.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Ryujinx.Core.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.Core.OsHle.IpcServices.Am -{ - class IAudioController : IIpcService - { - private Dictionary m_Commands; - - public IReadOnlyDictionary Commands => m_Commands; - - public IAudioController() - { - m_Commands = new Dictionary() - { - //... - }; - } - } -} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/IpcServices/Am/ICommonStateGetter.cs b/Ryujinx.Core/OsHle/IpcServices/Am/ICommonStateGetter.cs deleted file mode 100644 index 2999bbba..00000000 --- a/Ryujinx.Core/OsHle/IpcServices/Am/ICommonStateGetter.cs +++ /dev/null @@ -1,74 +0,0 @@ -using Ryujinx.Core.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.Core.OsHle.IpcServices.Am -{ - class ICommonStateGetter : IIpcService - { - private Dictionary m_Commands; - - public IReadOnlyDictionary Commands => m_Commands; - - public ICommonStateGetter() - { - m_Commands = new Dictionary() - { - { 0, GetEventHandle }, - { 1, ReceiveMessage }, - { 5, GetOperationMode }, - { 6, GetPerformanceMode }, - { 9, GetCurrentFocusState }, - }; - } - - private enum FocusState - { - InFocus = 1, - OutOfFocus = 2 - } - - private enum OperationMode - { - Handheld = 0, - Docked = 1 - } - - public long GetEventHandle(ServiceCtx Context) - { - Context.ResponseData.Write(0L); - - return 0; - } - - public long ReceiveMessage(ServiceCtx Context) - { - //Program expects 0xF at 0x17ae70 on puyo sdk, - //otherwise runs on a infinite loop until it reads said value. - //What it means is still unknown. - Context.ResponseData.Write(0xfL); - - return 0; //0x680; - } - - public long GetOperationMode(ServiceCtx Context) - { - Context.ResponseData.Write((byte)OperationMode.Handheld); - - return 0; - } - - public long GetPerformanceMode(ServiceCtx Context) - { - Context.ResponseData.Write((byte)0); - - return 0; - } - - public long GetCurrentFocusState(ServiceCtx Context) - { - Context.ResponseData.Write((byte)FocusState.InFocus); - - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/IpcServices/Am/IDebugFunctions.cs b/Ryujinx.Core/OsHle/IpcServices/Am/IDebugFunctions.cs deleted file mode 100644 index 944e58d8..00000000 --- a/Ryujinx.Core/OsHle/IpcServices/Am/IDebugFunctions.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Ryujinx.Core.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.Core.OsHle.IpcServices.Am -{ - class IDebugFunctions : IIpcService - { - private Dictionary m_Commands; - - public IReadOnlyDictionary Commands => m_Commands; - - public IDebugFunctions() - { - m_Commands = new Dictionary() - { - //... - }; - } - } -} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/IpcServices/Am/IDisplayController.cs b/Ryujinx.Core/OsHle/IpcServices/Am/IDisplayController.cs deleted file mode 100644 index 979e842a..00000000 --- a/Ryujinx.Core/OsHle/IpcServices/Am/IDisplayController.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Ryujinx.Core.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.Core.OsHle.IpcServices.Am -{ - class IDisplayController : IIpcService - { - private Dictionary m_Commands; - - public IReadOnlyDictionary Commands => m_Commands; - - public IDisplayController() - { - m_Commands = new Dictionary() - { - //... - }; - } - } -} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/IpcServices/Am/ILibraryAppletCreator.cs b/Ryujinx.Core/OsHle/IpcServices/Am/ILibraryAppletCreator.cs deleted file mode 100644 index 9f5b5e69..00000000 --- a/Ryujinx.Core/OsHle/IpcServices/Am/ILibraryAppletCreator.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Ryujinx.Core.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.Core.OsHle.IpcServices.Am -{ - class ILibraryAppletCreator : IIpcService - { - private Dictionary m_Commands; - - public IReadOnlyDictionary Commands => m_Commands; - - public ILibraryAppletCreator() - { - m_Commands = new Dictionary() - { - //... - }; - } - } -} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/IpcServices/Am/ISelfController.cs b/Ryujinx.Core/OsHle/IpcServices/Am/ISelfController.cs deleted file mode 100644 index 90ddd54b..00000000 --- a/Ryujinx.Core/OsHle/IpcServices/Am/ISelfController.cs +++ /dev/null @@ -1,61 +0,0 @@ -using Ryujinx.Core.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.Core.OsHle.IpcServices.Am -{ - class ISelfController : IIpcService - { - private Dictionary m_Commands; - - public IReadOnlyDictionary Commands => m_Commands; - - public ISelfController() - { - m_Commands = new Dictionary() - { - { 10, SetScreenShotPermission }, - { 11, SetOperationModeChangedNotification }, - { 12, SetPerformanceModeChangedNotification }, - { 13, SetFocusHandlingMode }, - { 16, SetOutOfFocusSuspendingEnabled } - }; - } - - public long SetScreenShotPermission(ServiceCtx Context) - { - bool Enable = Context.RequestData.ReadByte() != 0 ? true : false; - - return 0; - } - - public long SetOperationModeChangedNotification(ServiceCtx Context) - { - bool Enable = Context.RequestData.ReadByte() != 0 ? true : false; - - return 0; - } - - public long SetPerformanceModeChangedNotification(ServiceCtx Context) - { - bool Enable = Context.RequestData.ReadByte() != 0 ? true : false; - - 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; - - return 0; - } - - public long SetOutOfFocusSuspendingEnabled(ServiceCtx Context) - { - bool Enable = Context.RequestData.ReadByte() != 0 ? true : false; - - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/IpcServices/Am/IStorage.cs b/Ryujinx.Core/OsHle/IpcServices/Am/IStorage.cs deleted file mode 100644 index 375b960b..00000000 --- a/Ryujinx.Core/OsHle/IpcServices/Am/IStorage.cs +++ /dev/null @@ -1,33 +0,0 @@ -using Ryujinx.Core.OsHle.Ipc; -using System.Collections.Generic; - -using static Ryujinx.Core.OsHle.IpcServices.ObjHelper; - -namespace Ryujinx.Core.OsHle.IpcServices.Am -{ - class IStorage : IIpcService - { - private Dictionary m_Commands; - - public 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.Core/OsHle/IpcServices/Am/IStorageAccessor.cs b/Ryujinx.Core/OsHle/IpcServices/Am/IStorageAccessor.cs deleted file mode 100644 index 6d83e6f9..00000000 --- a/Ryujinx.Core/OsHle/IpcServices/Am/IStorageAccessor.cs +++ /dev/null @@ -1,62 +0,0 @@ -using ChocolArm64.Memory; -using Ryujinx.Core.OsHle.Ipc; -using System; -using System.Collections.Generic; - -namespace Ryujinx.Core.OsHle.IpcServices.Am -{ - class IStorageAccessor : IIpcService - { - private Dictionary m_Commands; - - public IReadOnlyDictionary Commands => m_Commands; - - private IStorage Storage; - - public IStorageAccessor(IStorage Storage) - { - m_Commands = new Dictionary() - { - { 0, GetSize }, - { 11, Read } - }; - - this.Storage = Storage; - } - - public long GetSize(ServiceCtx Context) - { - Context.ResponseData.Write((long)Storage.Data.Length); - - return 0; - } - - public long Read(ServiceCtx Context) - { - long ReadPosition = Context.RequestData.ReadInt64(); - - if (Context.Request.RecvListBuff.Count > 0) - { - long Position = Context.Request.RecvListBuff[0].Position; - short Size = Context.Request.RecvListBuff[0].Size; - - byte[] Data; - - if (Storage.Data.Length > Size) - { - Data = new byte[Size]; - - Buffer.BlockCopy(Storage.Data, 0, Data, 0, Size); - } - else - { - Data = Storage.Data; - } - - AMemoryHelper.WriteBytes(Context.Memory, Position, Data); - } - - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/IpcServices/Am/IWindowController.cs b/Ryujinx.Core/OsHle/IpcServices/Am/IWindowController.cs deleted file mode 100644 index ddc73bce..00000000 --- a/Ryujinx.Core/OsHle/IpcServices/Am/IWindowController.cs +++ /dev/null @@ -1,33 +0,0 @@ -using Ryujinx.Core.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.Core.OsHle.IpcServices.Am -{ - class IWindowController : IIpcService - { - private Dictionary m_Commands; - - public IReadOnlyDictionary Commands => m_Commands; - - public IWindowController() - { - m_Commands = new Dictionary() - { - { 1, GetAppletResourceUserId }, - { 10, AcquireForegroundRights } - }; - } - - public long GetAppletResourceUserId(ServiceCtx Context) - { - Context.ResponseData.Write(0L); - - return 0; - } - - public long AcquireForegroundRights(ServiceCtx Context) - { - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/IpcServices/Am/ServiceAppletOE.cs b/Ryujinx.Core/OsHle/IpcServices/Am/ServiceAppletOE.cs deleted file mode 100644 index b60c93dd..00000000 --- a/Ryujinx.Core/OsHle/IpcServices/Am/ServiceAppletOE.cs +++ /dev/null @@ -1,29 +0,0 @@ -using Ryujinx.Core.OsHle.Ipc; -using System.Collections.Generic; - -using static Ryujinx.Core.OsHle.IpcServices.ObjHelper; - -namespace Ryujinx.Core.OsHle.IpcServices.Am -{ - class ServiceAppletOE : IIpcService - { - private Dictionary m_Commands; - - public IReadOnlyDictionary Commands => m_Commands; - - public ServiceAppletOE() - { - 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.Core/OsHle/IpcServices/Android/GbpBuffer.cs b/Ryujinx.Core/OsHle/IpcServices/Android/GbpBuffer.cs deleted file mode 100644 index 5fe585d0..00000000 --- a/Ryujinx.Core/OsHle/IpcServices/Android/GbpBuffer.cs +++ /dev/null @@ -1,60 +0,0 @@ -using System.IO; - -namespace Ryujinx.Core.OsHle.IpcServices.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.Core/OsHle/IpcServices/Android/NvFlinger.cs b/Ryujinx.Core/OsHle/IpcServices/Android/NvFlinger.cs deleted file mode 100644 index 85a06cea..00000000 --- a/Ryujinx.Core/OsHle/IpcServices/Android/NvFlinger.cs +++ /dev/null @@ -1,395 +0,0 @@ -using ChocolArm64.Memory; -using Ryujinx.Core.OsHle.Handles; -using System; -using System.IO; -using System.Collections.Generic; -using System.Text; -using System.Threading; - -using static Ryujinx.Core.OsHle.IpcServices.Android.Parcel; - -namespace Ryujinx.Core.OsHle.IpcServices.Android -{ - class NvFlinger : IDisposable - { - private delegate long ServiceProcessParcel(ServiceCtx Context, BinaryReader ParcelReader); - - private Dictionary<(string, int), ServiceProcessParcel> Commands; - - 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 BufferEntry - { - public BufferState State; - - public HalTransform Transform; - - public GbpBuffer Data; - } - - private BufferEntry[] BufferQueue; - - private ManualResetEvent WaitBufferFree; - - private bool KeepRunning; - - public NvFlinger() - { - Commands = new Dictionary<(string, int), ServiceProcessParcel>() - { - { ("android.gui.IGraphicBufferProducer", 0x1), GbpRequestBuffer }, - { ("android.gui.IGraphicBufferProducer", 0x3), GbpDequeueBuffer }, - { ("android.gui.IGraphicBufferProducer", 0x7), GbpQueueBuffer }, - { ("android.gui.IGraphicBufferProducer", 0x8), GbpCancelBuffer }, - { ("android.gui.IGraphicBufferProducer", 0x9), GbpQuery }, - { ("android.gui.IGraphicBufferProducer", 0xa), GbpConnect }, - { ("android.gui.IGraphicBufferProducer", 0xe), GbpPreallocBuffer } - }; - - BufferQueue = new BufferEntry[0x40]; - - WaitBufferFree = new ManualResetEvent(false); - - KeepRunning = true; - } - - 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)) - { - Logging.Debug($"{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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); - } - - private long GbpQueueBuffer(ServiceCtx Context, BinaryReader ParcelReader) - { - //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].State = BufferState.Queued; - - SendFrameBuffer(Context, Slot); - - return MakeReplyParcel(Context, 1280, 720, 0, 0, 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 GbpPreallocBuffer(ServiceCtx Context, BinaryReader ParcelReader) - { - int Slot = ParcelReader.ReadInt32(); - - int BufferCount = ParcelReader.ReadInt32(); - 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]); - - AMemoryHelper.WriteBytes(Context.Memory, ReplyPos, Reply); - - return 0; - } - - private unsafe void SendFrameBuffer(ServiceCtx Context, int Slot) - { - int FbWidth = BufferQueue[Slot].Data.Width; - int FbHeight = BufferQueue[Slot].Data.Height; - - int FbSize = FbWidth * FbHeight * 4; - - HNvMap NvMap = GetNvMap(Context, Slot); - - if (FbSize < 0 || NvMap.Address < 0 || NvMap.Address + FbSize > AMemoryMgr.AddrSize) - { - Logging.Error($"Frame buffer address {NvMap.Address:x16} is invalid!"); - - BufferQueue[Slot].State = BufferState.Free; - - WaitBufferFree.Set(); - - return; - } - - BufferQueue[Slot].State = BufferState.Acquired; - - float ScaleX = 1; - float ScaleY = 1; - float Rotate = 0; - - if (BufferQueue[Slot].Transform.HasFlag(HalTransform.FlipX)) - { - ScaleX = -1; - } - - if (BufferQueue[Slot].Transform.HasFlag(HalTransform.FlipY)) - { - ScaleY = -1; - } - - if (BufferQueue[Slot].Transform.HasFlag(HalTransform.Rotate90)) - { - Rotate = MathF.PI * 0.5f; - } - - byte* Fb = (byte*)Context.Ns.Ram + NvMap.Address; - - Context.Ns.Gpu.Renderer.QueueAction(delegate() - { - Context.Ns.Gpu.Renderer.SetFrameBuffer( - Fb, - FbWidth, - FbHeight, - ScaleX, - ScaleY, - Rotate); - - BufferQueue[Slot].State = BufferState.Free; - - lock (WaitBufferFree) - { - WaitBufferFree.Set(); - } - }); - } - - private HNvMap GetNvMap(ServiceCtx Context, int Slot) - { - int NvMapHandle = BitConverter.ToInt32(BufferQueue[Slot].Data.RawData, 0x4c); - - if (!BitConverter.IsLittleEndian) - { - byte[] RawValue = BitConverter.GetBytes(NvMapHandle); - - Array.Reverse(RawValue); - - NvMapHandle = BitConverter.ToInt32(RawValue, 0); - } - - return Context.Ns.Os.Handles.GetData(NvMapHandle); - } - - private int GetFreeSlotBlocking(int Width, int Height) - { - int Slot; - - do - { - lock (WaitBufferFree) - { - if ((Slot = GetFreeSlot(Width, Height)) != -1) - { - break; - } - - Logging.Debug("Waiting for a free BufferQueue slot..."); - - if (!KeepRunning) - { - break; - } - - WaitBufferFree.Reset(); - } - - WaitBufferFree.WaitOne(); - } - while (KeepRunning); - - Logging.Debug($"Found free BufferQueue slot {Slot}!"); - - 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) - { - lock (WaitBufferFree) - { - KeepRunning = false; - - WaitBufferFree.Set(); - } - - WaitBufferFree.Dispose(); - } - } - } -} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/IpcServices/Android/Parcel.cs b/Ryujinx.Core/OsHle/IpcServices/Android/Parcel.cs deleted file mode 100644 index 3404c227..00000000 --- a/Ryujinx.Core/OsHle/IpcServices/Android/Parcel.cs +++ /dev/null @@ -1,58 +0,0 @@ -using System; -using System.IO; - -namespace Ryujinx.Core.OsHle.IpcServices.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.Core/OsHle/IpcServices/Apm/ISession.cs b/Ryujinx.Core/OsHle/IpcServices/Apm/ISession.cs deleted file mode 100644 index 500f7596..00000000 --- a/Ryujinx.Core/OsHle/IpcServices/Apm/ISession.cs +++ /dev/null @@ -1,28 +0,0 @@ -using Ryujinx.Core.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.Core.OsHle.IpcServices.Apm -{ - class ISession : IIpcService - { - private Dictionary m_Commands; - - public IReadOnlyDictionary Commands => m_Commands; - - public ISession() - { - m_Commands = new Dictionary() - { - { 0, SetPerformanceConfiguration } - }; - } - - public long SetPerformanceConfiguration(ServiceCtx Context) - { - int PerfMode = Context.RequestData.ReadInt32(); - int PerfConfig = Context.RequestData.ReadInt32(); - - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/IpcServices/Apm/ServiceApm.cs b/Ryujinx.Core/OsHle/IpcServices/Apm/ServiceApm.cs deleted file mode 100644 index d6c0400a..00000000 --- a/Ryujinx.Core/OsHle/IpcServices/Apm/ServiceApm.cs +++ /dev/null @@ -1,29 +0,0 @@ -using Ryujinx.Core.OsHle.Ipc; -using System.Collections.Generic; - -using static Ryujinx.Core.OsHle.IpcServices.ObjHelper; - -namespace Ryujinx.Core.OsHle.IpcServices.Apm -{ - class ServiceApm : IIpcService - { - private Dictionary m_Commands; - - public IReadOnlyDictionary Commands => m_Commands; - - public ServiceApm() - { - 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.Core/OsHle/IpcServices/Aud/IAudioOut.cs b/Ryujinx.Core/OsHle/IpcServices/Aud/IAudioOut.cs deleted file mode 100644 index a45b23cc..00000000 --- a/Ryujinx.Core/OsHle/IpcServices/Aud/IAudioOut.cs +++ /dev/null @@ -1,180 +0,0 @@ -using ChocolArm64.Memory; -using Ryujinx.Core.OsHle.Handles; -using Ryujinx.Core.OsHle.Ipc; -using OpenTK.Audio; -using OpenTK.Audio.OpenAL; -using System; -using System.Collections.Generic; -using System.IO; - -namespace Ryujinx.Core.OsHle.IpcServices.Aud -{ - class IAudioOut : IIpcService - { - private Dictionary m_Commands; - - public IReadOnlyDictionary Commands => m_Commands; - - public IAudioOut() - { - m_Commands = new Dictionary() - { - { 0, GetAudioOutState }, - { 1, StartAudioOut }, - { 2, StopAudioOut }, - { 3, AppendAudioOutBuffer }, - { 4, RegisterBufferEvent }, - { 5, GetReleasedAudioOutBuffer }, - { 6, ContainsAudioOutBuffer }, - { 7, AppendAudioOutBuffer_ex }, - { 8, GetReleasedAudioOutBuffer_ex } - }; - } - - enum AudioOutState - { - Started, - Stopped - }; - - //IAudioOut - private AudioOutState State = AudioOutState.Stopped; - private Queue KeysQueue = new Queue(); - - //OpenAL - private bool OpenALInstalled = true; - private AudioContext AudioCtx; - private int Source; - private int Buffer; - - //Return State of IAudioOut - public long GetAudioOutState(ServiceCtx Context) - { - Context.ResponseData.Write((int)State); - - return 0; - } - - public long StartAudioOut(ServiceCtx Context) - { - if (State == AudioOutState.Stopped) - { - State = AudioOutState.Started; - - try - { - AudioCtx = new AudioContext(); //Create the audio context - } - catch (Exception) - { - Logging.Warn("OpenAL Error! PS: Install OpenAL Core SDK!"); - OpenALInstalled = false; - } - - if (OpenALInstalled) AL.Listener(ALListenerf.Gain, (float)8.0); //Add more gain to it - } - - return 0; - } - - public long StopAudioOut(ServiceCtx Context) - { - if (State == AudioOutState.Started) - { - if (OpenALInstalled) - { - if (AudioCtx == null) //Needed to call the instance of AudioContext() - return 0; - - AL.SourceStop(Source); - AL.DeleteSource(Source); - } - State = AudioOutState.Stopped; - } - - return 0; - } - - public long AppendAudioOutBuffer(ServiceCtx Context) - { - long BufferId = Context.RequestData.ReadInt64(); - - KeysQueue.Enqueue(BufferId); - - byte[] AudioOutBuffer = AMemoryHelper.ReadBytes(Context.Memory, Context.Request.SendBuff[0].Position, sizeof(long) * 5); - using (MemoryStream MS = new MemoryStream(AudioOutBuffer)) - { - BinaryReader Reader = new BinaryReader(MS); - long PointerNextBuffer = Reader.ReadInt64(); - long PointerSampleBuffer = Reader.ReadInt64(); - long CapacitySampleBuffer = Reader.ReadInt64(); - long SizeDataInSampleBuffer = Reader.ReadInt64(); - long OffsetDataInSampleBuffer = Reader.ReadInt64(); - - byte[] AudioSampleBuffer = AMemoryHelper.ReadBytes(Context.Memory, PointerSampleBuffer + OffsetDataInSampleBuffer, (int)SizeDataInSampleBuffer); - - if (OpenALInstalled) - { - if (AudioCtx == null) //Needed to call the instance of AudioContext() - return 0; - - Buffer = AL.GenBuffer(); - AL.BufferData(Buffer, ALFormat.Stereo16, AudioSampleBuffer, AudioSampleBuffer.Length, 48000); - - Source = AL.GenSource(); - AL.SourceQueueBuffer(Source, Buffer); - } - } - - return 0; - } - - public long RegisterBufferEvent(ServiceCtx Context) - { - int Handle = Context.Ns.Os.Handles.GenerateId(new HEvent()); - - Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle); - - return 0; - } - - public long GetReleasedAudioOutBuffer(ServiceCtx Context) - { - long TempKey = 0; - - if (KeysQueue.Count > 0) TempKey = KeysQueue.Dequeue(); - - AMemoryHelper.WriteBytes(Context.Memory, Context.Request.ReceiveBuff[0].Position, BitConverter.GetBytes(TempKey)); - - int ReleasedBuffersCount = 1; - Context.ResponseData.Write(ReleasedBuffersCount); - - if (OpenALInstalled) - { - if (AudioCtx == null) //Needed to call the instance of AudioContext() - return 0; - - AL.SourcePlay(Source); - int[] FreeBuffers = AL.SourceUnqueueBuffers(Source, 1); - AL.DeleteBuffers(FreeBuffers); - } - - return 0; - } - - public long ContainsAudioOutBuffer(ServiceCtx Context) - { - return 0; - } - - public long AppendAudioOutBuffer_ex(ServiceCtx Context) - { - return 0; - } - - public long GetReleasedAudioOutBuffer_ex(ServiceCtx Context) - { - return 0; - } - } -} diff --git a/Ryujinx.Core/OsHle/IpcServices/Aud/IAudioRenderer.cs b/Ryujinx.Core/OsHle/IpcServices/Aud/IAudioRenderer.cs deleted file mode 100644 index bfde0b65..00000000 --- a/Ryujinx.Core/OsHle/IpcServices/Aud/IAudioRenderer.cs +++ /dev/null @@ -1,66 +0,0 @@ -using Ryujinx.Core.OsHle.Handles; -using Ryujinx.Core.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.Core.OsHle.IpcServices.Aud -{ - class IAudioRenderer : IIpcService - { - private Dictionary m_Commands; - - public IReadOnlyDictionary Commands => m_Commands; - - public IAudioRenderer() - { - m_Commands = new Dictionary() - { - { 4, RequestUpdateAudioRenderer }, - { 5, StartAudioRenderer }, - { 6, StopAudioRenderer }, - { 7, QuerySystemEvent } - }; - } - - public long RequestUpdateAudioRenderer(ServiceCtx Context) - { - //(buffer) -> (buffer, buffer) - - long Position = Context.Request.ReceiveBuff[0].Position; - - //0x40 bytes header - Context.Memory.WriteInt32(Position + 0x4, 0xb0); //Behavior Out State Size? (note: this is the last section) - Context.Memory.WriteInt32(Position + 0x8, 0x18e0); //Memory Pool Out State Size? - Context.Memory.WriteInt32(Position + 0xc, 0x600); //Voice Out State Size? - Context.Memory.WriteInt32(Position + 0x14, 0xe0); //Effect Out State Size? - Context.Memory.WriteInt32(Position + 0x1c, 0x20); //Sink Out State Size? - Context.Memory.WriteInt32(Position + 0x20, 0x10); //Performance Out State Size? - Context.Memory.WriteInt32(Position + 0x3c, 0x20e0); //Total Size (including 0x40 bytes header) - - for (int Offset = 0x40; Offset < 0x40 + 0x18e0; Offset += 0x10) - { - Context.Memory.WriteInt32(Position + Offset, 5); - } - - return 0; - } - - public long StartAudioRenderer(ServiceCtx Context) - { - return 0; - } - - public long StopAudioRenderer(ServiceCtx Context) - { - return 0; - } - - public long QuerySystemEvent(ServiceCtx Context) - { - int Handle = Context.Ns.Os.Handles.GenerateId(new HEvent()); - - Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle); - - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/IpcServices/Aud/ServiceAudOut.cs b/Ryujinx.Core/OsHle/IpcServices/Aud/ServiceAudOut.cs deleted file mode 100644 index eb923562..00000000 --- a/Ryujinx.Core/OsHle/IpcServices/Aud/ServiceAudOut.cs +++ /dev/null @@ -1,57 +0,0 @@ -using ChocolArm64.Memory; -using Ryujinx.Core.OsHle.Ipc; -using System.Collections.Generic; -using System.Text; - -using static Ryujinx.Core.OsHle.IpcServices.ObjHelper; - -namespace Ryujinx.Core.OsHle.IpcServices.Aud -{ - class ServiceAudOut : IIpcService - { - private Dictionary m_Commands; - - public IReadOnlyDictionary Commands => m_Commands; - - public ServiceAudOut() - { - m_Commands = new Dictionary() - { - { 0, ListAudioOuts }, - { 1, OpenAudioOut }, - }; - } - - public long ListAudioOuts(ServiceCtx Context) - { - long Position = Context.Request.ReceiveBuff[0].Position; - - AMemoryHelper.WriteBytes(Context.Memory, Position, Encoding.ASCII.GetBytes("iface")); - - Context.ResponseData.Write(1); - - return 0; - } - - public long OpenAudioOut(ServiceCtx Context) - { - MakeObject(Context, new IAudioOut()); - - Context.ResponseData.Write(48000); //Sample Rate - Context.ResponseData.Write(2); //Channel Count - Context.ResponseData.Write(2); //PCM Format - /* - 0 - Invalid - 1 - INT8 - 2 - INT16 - 3 - INT24 - 4 - INT32 - 5 - PCM Float - 6 - ADPCM - */ - Context.ResponseData.Write(0); //Unknown - - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/IpcServices/Aud/ServiceAudRen.cs b/Ryujinx.Core/OsHle/IpcServices/Aud/ServiceAudRen.cs deleted file mode 100644 index eccc699c..00000000 --- a/Ryujinx.Core/OsHle/IpcServices/Aud/ServiceAudRen.cs +++ /dev/null @@ -1,51 +0,0 @@ -using Ryujinx.Core.OsHle.Ipc; -using System.Collections.Generic; - -using static Ryujinx.Core.OsHle.IpcServices.ObjHelper; - -namespace Ryujinx.Core.OsHle.IpcServices.Aud -{ - class ServiceAudRen : IIpcService - { - private Dictionary m_Commands; - - public IReadOnlyDictionary Commands => m_Commands; - - public ServiceAudRen() - { - m_Commands = new Dictionary() - { - { 0, OpenAudioRenderer }, - { 1, GetAudioRendererWorkBufferSize }, - }; - } - - public long OpenAudioRenderer(ServiceCtx Context) - { - MakeObject(Context, new IAudioRenderer()); - - return 0; - } - - public long GetAudioRendererWorkBufferSize(ServiceCtx Context) - { - int SampleRate = Context.RequestData.ReadInt32(); - int Unknown4 = Context.RequestData.ReadInt32(); - int Unknown8 = Context.RequestData.ReadInt32(); - int UnknownC = Context.RequestData.ReadInt32(); - int Unknown10 = Context.RequestData.ReadInt32(); - int Unknown14 = Context.RequestData.ReadInt32(); - int Unknown18 = Context.RequestData.ReadInt32(); - int Unknown1c = Context.RequestData.ReadInt32(); - int Unknown20 = Context.RequestData.ReadInt32(); - int Unknown24 = Context.RequestData.ReadInt32(); - int Unknown28 = Context.RequestData.ReadInt32(); - int Unknown2c = Context.RequestData.ReadInt32(); - int Rev1Magic = Context.RequestData.ReadInt32(); - - Context.ResponseData.Write(0x400L); - - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/IpcServices/ErrorCode.cs b/Ryujinx.Core/OsHle/IpcServices/ErrorCode.cs deleted file mode 100644 index a4e197b2..00000000 --- a/Ryujinx.Core/OsHle/IpcServices/ErrorCode.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Ryujinx.Core.OsHle.IpcServices -{ - static class ErrorCode - { - public static long MakeError(ErrorModule Module, int Code) - { - return (int)Module | (Code << 9); - } - } -} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/IpcServices/ErrorModule.cs b/Ryujinx.Core/OsHle/IpcServices/ErrorModule.cs deleted file mode 100644 index 0d15db60..00000000 --- a/Ryujinx.Core/OsHle/IpcServices/ErrorModule.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Ryujinx.Core.OsHle.IpcServices -{ - enum ErrorModule - { - Fs = 2, - } -} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/IpcServices/Friend/IFriendService.cs b/Ryujinx.Core/OsHle/IpcServices/Friend/IFriendService.cs deleted file mode 100644 index e3e03da8..00000000 --- a/Ryujinx.Core/OsHle/IpcServices/Friend/IFriendService.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Ryujinx.Core.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.Core.OsHle.IpcServices.Friend -{ - class IFriendService : IIpcService - { - private Dictionary m_Commands; - - public IReadOnlyDictionary Commands => m_Commands; - - public IFriendService() - { - m_Commands = new Dictionary() - { - //... - }; - } - } -} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/IpcServices/Friend/ServiceFriend.cs b/Ryujinx.Core/OsHle/IpcServices/Friend/ServiceFriend.cs deleted file mode 100644 index 674877f6..00000000 --- a/Ryujinx.Core/OsHle/IpcServices/Friend/ServiceFriend.cs +++ /dev/null @@ -1,29 +0,0 @@ -using Ryujinx.Core.OsHle.Ipc; -using System.Collections.Generic; - -using static Ryujinx.Core.OsHle.IpcServices.ObjHelper; - -namespace Ryujinx.Core.OsHle.IpcServices.Friend -{ - class ServiceFriend : IIpcService - { - private Dictionary m_Commands; - - public IReadOnlyDictionary Commands => m_Commands; - - public ServiceFriend() - { - 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.Core/OsHle/IpcServices/FspSrv/FsErr.cs b/Ryujinx.Core/OsHle/IpcServices/FspSrv/FsErr.cs deleted file mode 100644 index 656d529f..00000000 --- a/Ryujinx.Core/OsHle/IpcServices/FspSrv/FsErr.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Ryujinx.Core.OsHle.IpcServices.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.Core/OsHle/IpcServices/FspSrv/IDirectory.cs b/Ryujinx.Core/OsHle/IpcServices/FspSrv/IDirectory.cs deleted file mode 100644 index 54dbec74..00000000 --- a/Ryujinx.Core/OsHle/IpcServices/FspSrv/IDirectory.cs +++ /dev/null @@ -1,117 +0,0 @@ -using ChocolArm64.Memory; -using Ryujinx.Core.OsHle.Ipc; -using System; -using System.Collections.Generic; -using System.IO; -using System.Text; - -namespace Ryujinx.Core.OsHle.IpcServices.FspSrv -{ - class IDirectory : IIpcService, IDisposable - { - private const int DirectoryEntrySize = 0x310; - - private Dictionary m_Commands; - - public 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)); - - AMemoryHelper.WriteBytes(Context.Memory, 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.Core/OsHle/IpcServices/FspSrv/IFile.cs b/Ryujinx.Core/OsHle/IpcServices/FspSrv/IFile.cs deleted file mode 100644 index ac2100f2..00000000 --- a/Ryujinx.Core/OsHle/IpcServices/FspSrv/IFile.cs +++ /dev/null @@ -1,111 +0,0 @@ -using ChocolArm64.Memory; -using Ryujinx.Core.OsHle.Ipc; -using System; -using System.Collections.Generic; -using System.IO; - -namespace Ryujinx.Core.OsHle.IpcServices.FspSrv -{ - class IFile : IIpcService, IDisposable - { - private Dictionary m_Commands; - - public 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); - - AMemoryHelper.WriteBytes(Context.Memory, 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 = AMemoryHelper.ReadBytes(Context.Memory, Position, (int)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.Core/OsHle/IpcServices/FspSrv/IFileSystem.cs b/Ryujinx.Core/OsHle/IpcServices/FspSrv/IFileSystem.cs deleted file mode 100644 index ee9de8bc..00000000 --- a/Ryujinx.Core/OsHle/IpcServices/FspSrv/IFileSystem.cs +++ /dev/null @@ -1,383 +0,0 @@ -using ChocolArm64.Memory; -using Ryujinx.Core.OsHle.Ipc; -using System; -using System.Collections.Generic; -using System.IO; - -using static Ryujinx.Core.OsHle.IpcServices.ErrorCode; -using static Ryujinx.Core.OsHle.IpcServices.ObjHelper; - -namespace Ryujinx.Core.OsHle.IpcServices.FspSrv -{ - class IFileSystem : IIpcService - { - private Dictionary m_Commands; - - public 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) - { - long Position = Context.Request.PtrBuff[0].Position; - - string Name = AMemoryHelper.ReadAsciiString(Context.Memory, Position); - - 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) - { - long Position = Context.Request.PtrBuff[0].Position; - - string Name = AMemoryHelper.ReadAsciiString(Context.Memory, Position); - - 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) - { - long Position = Context.Request.PtrBuff[0].Position; - - string Name = AMemoryHelper.ReadAsciiString(Context.Memory, Position); - - 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) - { - long Position = Context.Request.PtrBuff[0].Position; - - string Name = AMemoryHelper.ReadAsciiString(Context.Memory, Position); - - 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) - { - long OldPosition = Context.Request.PtrBuff[0].Position; - long NewPosition = Context.Request.PtrBuff[0].Position; - - string OldName = AMemoryHelper.ReadAsciiString(Context.Memory, OldPosition); - string NewName = AMemoryHelper.ReadAsciiString(Context.Memory, NewPosition); - - 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) - { - long OldPosition = Context.Request.PtrBuff[0].Position; - long NewPosition = Context.Request.PtrBuff[0].Position; - - string OldName = AMemoryHelper.ReadAsciiString(Context.Memory, OldPosition); - string NewName = AMemoryHelper.ReadAsciiString(Context.Memory, NewPosition); - - 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) - { - long Position = Context.Request.PtrBuff[0].Position; - - string Name = AMemoryHelper.ReadAsciiString(Context.Memory, Position); - - 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) - { - long Position = Context.Request.PtrBuff[0].Position; - - int FilterFlags = Context.RequestData.ReadInt32(); - - string Name = AMemoryHelper.ReadAsciiString(Context.Memory, Position); - - 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) - { - long Position = Context.Request.PtrBuff[0].Position; - - int FilterFlags = Context.RequestData.ReadInt32(); - - string Name = AMemoryHelper.ReadAsciiString(Context.Memory, Position); - - 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) - { - long Position = Context.Request.PtrBuff[0].Position; - - string Name = AMemoryHelper.ReadAsciiString(Context.Memory, Position); - - Context.ResponseData.Write(Context.Ns.VFs.GetDrive().AvailableFreeSpace); - - return 0; - } - - public long GetTotalSpaceSize(ServiceCtx Context) - { - long Position = Context.Request.PtrBuff[0].Position; - - string Name = AMemoryHelper.ReadAsciiString(Context.Memory, Position); - - Context.ResponseData.Write(Context.Ns.VFs.GetDrive().TotalSize); - - 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); - } - } - } -} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/IpcServices/FspSrv/IStorage.cs b/Ryujinx.Core/OsHle/IpcServices/FspSrv/IStorage.cs deleted file mode 100644 index 297461a0..00000000 --- a/Ryujinx.Core/OsHle/IpcServices/FspSrv/IStorage.cs +++ /dev/null @@ -1,52 +0,0 @@ -using ChocolArm64.Memory; -using Ryujinx.Core.OsHle.Ipc; -using System.Collections.Generic; -using System.IO; - -namespace Ryujinx.Core.OsHle.IpcServices.FspSrv -{ - class IStorage : IIpcService - { - private Dictionary m_Commands; - - public 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); - - AMemoryHelper.WriteBytes(Context.Memory, BuffDesc.Position, Data); - } - - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/IpcServices/FspSrv/ServiceFspSrv.cs b/Ryujinx.Core/OsHle/IpcServices/FspSrv/ServiceFspSrv.cs deleted file mode 100644 index 991f4027..00000000 --- a/Ryujinx.Core/OsHle/IpcServices/FspSrv/ServiceFspSrv.cs +++ /dev/null @@ -1,67 +0,0 @@ -using Ryujinx.Core.OsHle.Ipc; -using System.Collections.Generic; - -using static Ryujinx.Core.OsHle.IpcServices.ObjHelper; - -namespace Ryujinx.Core.OsHle.IpcServices.FspSrv -{ - class ServiceFspSrv : IIpcService - { - private Dictionary m_Commands; - - public IReadOnlyDictionary Commands => m_Commands; - - public ServiceFspSrv() - { - m_Commands = new Dictionary() - { - { 1, Initialize }, - { 18, MountSdCard }, - { 51, MountSaveData }, - { 200, OpenDataStorageByCurrentProcess }, - { 203, OpenRomStorage }, - { 1005, GetGlobalAccessLogMode } - }; - } - - public long Initialize(ServiceCtx Context) - { - return 0; - } - - public long MountSdCard(ServiceCtx Context) - { - MakeObject(Context, new IFileSystem(Context.Ns.VFs.GetSdCardPath())); - - return 0; - } - - public long MountSaveData(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 OpenRomStorage(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.Core/OsHle/IpcServices/Hid/IActiveVibrationDeviceList.cs b/Ryujinx.Core/OsHle/IpcServices/Hid/IActiveVibrationDeviceList.cs deleted file mode 100644 index 020e8e7e..00000000 --- a/Ryujinx.Core/OsHle/IpcServices/Hid/IActiveVibrationDeviceList.cs +++ /dev/null @@ -1,17 +0,0 @@ -using Ryujinx.Core.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.Core.OsHle.IpcServices.Hid -{ - class IActiveApplicationDeviceList : IIpcService - { - private Dictionary m_Commands; - - public IReadOnlyDictionary Commands => m_Commands; - - public IActiveApplicationDeviceList() - { - m_Commands = new Dictionary() { }; - } - } -} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/IpcServices/Hid/IAppletResource.cs b/Ryujinx.Core/OsHle/IpcServices/Hid/IAppletResource.cs deleted file mode 100644 index d22e0ff2..00000000 --- a/Ryujinx.Core/OsHle/IpcServices/Hid/IAppletResource.cs +++ /dev/null @@ -1,32 +0,0 @@ -using Ryujinx.Core.OsHle.Handles; -using Ryujinx.Core.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.Core.OsHle.IpcServices.Hid -{ - class IAppletResource : IIpcService - { - private Dictionary m_Commands; - - public IReadOnlyDictionary Commands => m_Commands; - - private HSharedMem Handle; - - public IAppletResource(HSharedMem Handle) - { - m_Commands = new Dictionary() - { - { 0, GetSharedMemoryHandle } - }; - - this.Handle = Handle; - } - - public static long GetSharedMemoryHandle(ServiceCtx Context) - { - Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Context.Ns.Os.HidHandle); - - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/IpcServices/Hid/ServiceHid.cs b/Ryujinx.Core/OsHle/IpcServices/Hid/ServiceHid.cs deleted file mode 100644 index 5cca9319..00000000 --- a/Ryujinx.Core/OsHle/IpcServices/Hid/ServiceHid.cs +++ /dev/null @@ -1,98 +0,0 @@ -using Ryujinx.Core.OsHle.Handles; -using Ryujinx.Core.OsHle.Ipc; -using System.Collections.Generic; - -using static Ryujinx.Core.OsHle.IpcServices.ObjHelper; - -namespace Ryujinx.Core.OsHle.IpcServices.Hid -{ - class ServiceHid : IIpcService - { - private Dictionary m_Commands; - - public IReadOnlyDictionary Commands => m_Commands; - - public ServiceHid() - { - m_Commands = new Dictionary() - { - { 0, CreateAppletResource }, - { 11, ActivateTouchScreen }, - { 100, SetSupportedNpadStyleSet }, - { 101, GetSupportedNpadStyleSet }, - { 102, SetSupportedNpadIdType }, - { 103, ActivateNpad }, - { 120, SetNpadJoyHoldType }, - { 121, GetNpadJoyHoldType }, - { 203, CreateActiveVibrationDeviceList }, - }; - } - - public long CreateAppletResource(ServiceCtx Context) - { - HSharedMem HidHndData = Context.Ns.Os.Handles.GetData(Context.Ns.Os.HidHandle); - - MakeObject(Context, new IAppletResource(HidHndData)); - - return 0; - } - - public long ActivateTouchScreen(ServiceCtx Context) - { - long Unknown = Context.RequestData.ReadInt64(); - - return 0; - } - - public long GetSupportedNpadStyleSet(ServiceCtx Context) - { - Context.ResponseData.Write(0); - - return 0; - } - - public long SetSupportedNpadStyleSet(ServiceCtx Context) - { - long Unknown0 = Context.RequestData.ReadInt64(); - long Unknown8 = Context.RequestData.ReadInt64(); - - return 0; - } - - public long SetSupportedNpadIdType(ServiceCtx Context) - { - long Unknown = Context.RequestData.ReadInt64(); - - return 0; - } - - public long ActivateNpad(ServiceCtx Context) - { - long Unknown = Context.RequestData.ReadInt64(); - - return 0; - } - - public long SetNpadJoyHoldType(ServiceCtx Context) - { - long Unknown0 = Context.RequestData.ReadInt64(); - long Unknown8 = Context.RequestData.ReadInt64(); - - return 0; - } - - public long GetNpadJoyHoldType(ServiceCtx Context) - { - Context.ResponseData.Write(0L); - - return 0; - } - - public long CreateActiveVibrationDeviceList(ServiceCtx Context) - { - MakeObject(Context, new IActiveApplicationDeviceList()); - - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/IpcServices/IIpcService.cs b/Ryujinx.Core/OsHle/IpcServices/IIpcService.cs deleted file mode 100644 index eebcdfbe..00000000 --- a/Ryujinx.Core/OsHle/IpcServices/IIpcService.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Ryujinx.Core.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.Core.OsHle.IpcServices -{ - interface IIpcService - { - IReadOnlyDictionary Commands { get; } - } -} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/IpcServices/Lm/ServiceLm.cs b/Ryujinx.Core/OsHle/IpcServices/Lm/ServiceLm.cs deleted file mode 100644 index e665253c..00000000 --- a/Ryujinx.Core/OsHle/IpcServices/Lm/ServiceLm.cs +++ /dev/null @@ -1,27 +0,0 @@ -using Ryujinx.Core.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.Core.OsHle.IpcServices.Lm -{ - class ServiceLm : IIpcService - { - private Dictionary m_Commands; - - public IReadOnlyDictionary Commands => m_Commands; - - public ServiceLm() - { - m_Commands = new Dictionary() - { - { 0, Initialize } - }; - } - - public long Initialize(ServiceCtx Context) - { - Context.Session.Initialize(); - - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/IpcServices/NvServices/ServiceNvDrv.cs b/Ryujinx.Core/OsHle/IpcServices/NvServices/ServiceNvDrv.cs deleted file mode 100644 index 1de0ab70..00000000 --- a/Ryujinx.Core/OsHle/IpcServices/NvServices/ServiceNvDrv.cs +++ /dev/null @@ -1,627 +0,0 @@ -using ChocolArm64.Memory; -using Ryujinx.Core.OsHle.Handles; -using Ryujinx.Core.OsHle.Ipc; -using Ryujinx.Core.OsHle.Utilities; -using Ryujinx.Graphics.Gpu; -using System; -using System.Collections.Generic; - -namespace Ryujinx.Core.OsHle.IpcServices.NvServices -{ - class ServiceNvDrv : IIpcService - { - private delegate long ServiceProcessIoctl(ServiceCtx Context); - - private static Dictionary<(string, int), ServiceProcessIoctl> IoctlCmds = - new Dictionary<(string, int), ServiceProcessIoctl>() - { - { ("/dev/nvhost-as-gpu", 0x4101), NvGpuAsIoctlBindChannel }, - { ("/dev/nvhost-as-gpu", 0x4102), NvGpuAsIoctlAllocSpace }, - { ("/dev/nvhost-as-gpu", 0x4106), NvGpuAsIoctlMapBufferEx }, - { ("/dev/nvhost-as-gpu", 0x4108), NvGpuAsIoctlGetVaRegions }, - { ("/dev/nvhost-as-gpu", 0x4109), NvGpuAsIoctlInitializeEx }, - { ("/dev/nvhost-ctrl", 0x001b), NvHostIoctlCtrlGetConfig }, - { ("/dev/nvhost-ctrl", 0x001d), NvHostIoctlCtrlEventWait }, - { ("/dev/nvhost-ctrl-gpu", 0x4701), NvGpuIoctlZcullGetCtxSize }, - { ("/dev/nvhost-ctrl-gpu", 0x4702), NvGpuIoctlZcullGetInfo }, - { ("/dev/nvhost-ctrl-gpu", 0x4705), NvGpuIoctlGetCharacteristics }, - { ("/dev/nvhost-ctrl-gpu", 0x4706), NvGpuIoctlGetTpcMasks }, - { ("/dev/nvhost-ctrl-gpu", 0x4714), NvGpuIoctlZbcGetActiveSlotMask }, - { ("/dev/nvhost-gpu", 0x4714), NvMapIoctlChannelSetUserData }, - { ("/dev/nvhost-gpu", 0x4801), NvMapIoctlChannelSetNvMap }, - { ("/dev/nvhost-gpu", 0x4808), NvMapIoctlChannelSubmitGpFifo }, - { ("/dev/nvhost-gpu", 0x4809), NvMapIoctlChannelAllocObjCtx }, - { ("/dev/nvhost-gpu", 0x480b), NvMapIoctlChannelZcullBind }, - { ("/dev/nvhost-gpu", 0x480c), NvMapIoctlChannelSetErrorNotifier }, - { ("/dev/nvhost-gpu", 0x480d), NvMapIoctlChannelSetPriority }, - { ("/dev/nvhost-gpu", 0x481a), NvMapIoctlChannelAllocGpFifoEx2 }, - { ("/dev/nvmap", 0x0101), NvMapIocCreate }, - { ("/dev/nvmap", 0x0103), NvMapIocFromId }, - { ("/dev/nvmap", 0x0104), NvMapIocAlloc }, - { ("/dev/nvmap", 0x0109), NvMapIocParam }, - { ("/dev/nvmap", 0x010e), NvMapIocGetId }, - }; - - private Dictionary m_Commands; - - public IReadOnlyDictionary Commands => m_Commands; - - public ServiceNvDrv() - { - m_Commands = new Dictionary() - { - { 0, Open }, - { 1, Ioctl }, - { 2, Close }, - { 3, Initialize }, - { 4, QueryEvent }, - { 8, SetClientPid }, - }; - } - - public static long Open(ServiceCtx Context) - { - long NamePtr = Context.Request.SendBuff[0].Position; - - string Name = AMemoryHelper.ReadAsciiString(Context.Memory, NamePtr); - - int Fd = Context.Ns.Os.Fds.GenerateId(new FileDesc(Name)); - - Context.ResponseData.Write(Fd); - Context.ResponseData.Write(0); - - return 0; - } - - public static long Ioctl(ServiceCtx Context) - { - int Fd = Context.RequestData.ReadInt32(); - int Cmd = Context.RequestData.ReadInt32() & 0xffff; - - FileDesc FdData = Context.Ns.Os.Fds.GetData(Fd); - - long Position = Context.Request.PtrBuff[0].Position; - - Context.ResponseData.Write(0); - - if (IoctlCmds.TryGetValue((FdData.Name, Cmd), out ServiceProcessIoctl ProcReq)) - { - return ProcReq(Context); - } - else - { - throw new NotImplementedException($"{FdData.Name} {Cmd:x4}"); - } - } - - public static long Close(ServiceCtx Context) - { - int Fd = Context.RequestData.ReadInt32(); - - Context.Ns.Os.Fds.Delete(Fd); - - Context.ResponseData.Write(0); - - return 0; - } - - public static long Initialize(ServiceCtx Context) - { - long TransferMemSize = Context.RequestData.ReadInt64(); - int TransferMemHandle = Context.Request.HandleDesc.ToCopy[0]; - - Context.ResponseData.Write(0); - - return 0; - } - - public static long QueryEvent(ServiceCtx Context) - { - int Fd = Context.RequestData.ReadInt32(); - int EventId = Context.RequestData.ReadInt32(); - - Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(0xcafe); - - Context.ResponseData.Write(0); - - return 0; - } - - public static long SetClientPid(ServiceCtx Context) - { - long Pid = Context.RequestData.ReadInt64(); - - Context.ResponseData.Write(0); - - return 0; - } - - private static long NvGpuAsIoctlBindChannel(ServiceCtx Context) - { - long Position = Context.Request.PtrBuff[0].Position; - - int Fd = Context.Memory.ReadInt32(Position); - - return 0; - } - - private static long NvGpuAsIoctlAllocSpace(ServiceCtx Context) - { - long Position = Context.Request.PtrBuff[0].Position; - - MemReader Reader = new MemReader(Context.Memory, Position); - - int Pages = Reader.ReadInt32(); - int PageSize = Reader.ReadInt32(); - int Flags = Reader.ReadInt32(); - int Padding = Reader.ReadInt32(); - long Align = Reader.ReadInt64(); - - if ((Flags & 1) != 0) - { - Align = Context.Ns.Gpu.ReserveMemory(Align, (long)Pages * PageSize, 1); - } - else - { - Align = Context.Ns.Gpu.ReserveMemory((long)Pages * PageSize, Align); - } - - Context.Memory.WriteInt64(Position + 0x10, Align); - - return 0; - } - - private static long NvGpuAsIoctlMapBufferEx(ServiceCtx Context) - { - long Position = Context.Request.PtrBuff[0].Position; - - MemReader Reader = new MemReader(Context.Memory, Position); - - int Flags = Reader.ReadInt32(); - int Kind = Reader.ReadInt32(); - int Handle = Reader.ReadInt32(); - int PageSize = Reader.ReadInt32(); - long BuffAddr = Reader.ReadInt64(); - long MapSize = Reader.ReadInt64(); - long Offset = Reader.ReadInt64(); - - HNvMap NvMap = Context.Ns.Os.Handles.GetData(Handle); - - if (NvMap != null) - { - if ((Flags & 1) != 0) - { - Offset = Context.Ns.Gpu.MapMemory(NvMap.Address, Offset, NvMap.Size); - } - else - { - Offset = Context.Ns.Gpu.MapMemory(NvMap.Address, NvMap.Size); - } - } - - Context.Memory.WriteInt64(Position + 0x20, Offset); - - return 0; - } - - private static long NvGpuAsIoctlGetVaRegions(ServiceCtx Context) - { - long Position = Context.Request.PtrBuff[0].Position; - - MemReader Reader = new MemReader(Context.Memory, Position); - MemWriter Writer = new MemWriter(Context.Memory, Position); - - long Unused = Reader.ReadInt64(); - int BuffSize = Reader.ReadInt32(); - int Padding = Reader.ReadInt32(); - - BuffSize = 0x30; - - Writer.WriteInt64(Unused); - Writer.WriteInt32(BuffSize); - Writer.WriteInt32(Padding); - - Writer.WriteInt64(0); - Writer.WriteInt32(0); - Writer.WriteInt32(0); - Writer.WriteInt64(0); - - Writer.WriteInt64(0); - Writer.WriteInt32(0); - Writer.WriteInt32(0); - Writer.WriteInt64(0); - - return 0; - } - - private static long NvGpuAsIoctlInitializeEx(ServiceCtx Context) - { - long Position = Context.Request.PtrBuff[0].Position; - - MemReader Reader = new MemReader(Context.Memory, Position); - - int BigPageSize = Reader.ReadInt32(); - int AsFd = Reader.ReadInt32(); - int Flags = Reader.ReadInt32(); - int Reserved = Reader.ReadInt32(); - long Unknown10 = Reader.ReadInt64(); - long Unknown18 = Reader.ReadInt64(); - long Unknown20 = Reader.ReadInt64(); - - return 0; - } - - private static long NvHostIoctlCtrlGetConfig(ServiceCtx Context) - { - long Position = Context.Request.PtrBuff[0].Position; - - MemReader Reader = new MemReader(Context.Memory, Position); - MemWriter Writer = new MemWriter(Context.Memory, Position + 0x82); - - for (int Index = 0; Index < 0x101; Index++) - { - Writer.WriteByte(0); - } - - return 0; - } - - private static long NvHostIoctlCtrlEventWait(ServiceCtx Context) - { - long Position = Context.Request.PtrBuff[0].Position; - - MemReader Reader = new MemReader(Context.Memory, Position); - - int SyncPtId = Reader.ReadInt32(); - int Threshold = Reader.ReadInt32(); - int Timeout = Reader.ReadInt32(); - int Value = Reader.ReadInt32(); - - Context.Memory.WriteInt32(Position + 0xc, 0xcafe); - - return 0; - } - - private static long NvGpuIoctlZcullGetCtxSize(ServiceCtx Context) - { - long Position = Context.Request.PtrBuff[0].Position; - - Context.Memory.WriteInt32(Position, 1); - - return 0; - } - - private static long NvGpuIoctlZcullGetInfo(ServiceCtx Context) - { - long Position = Context.Request.PtrBuff[0].Position; - - MemWriter Writer = new MemWriter(Context.Memory, Position); - - Writer.WriteInt32(0); - Writer.WriteInt32(0); - Writer.WriteInt32(0); - Writer.WriteInt32(0); - Writer.WriteInt32(0); - Writer.WriteInt32(0); - Writer.WriteInt32(0); - Writer.WriteInt32(0); - Writer.WriteInt32(0); - Writer.WriteInt32(0); - - return 0; - } - - private static long NvGpuIoctlGetCharacteristics(ServiceCtx Context) - { - long Position = Context.Request.PtrBuff[0].Position; - - MemReader Reader = new MemReader(Context.Memory, Position); - MemWriter Writer = new MemWriter(Context.Memory, Position); - - //Note: We should just ignore the BuffAddr, because official code - //does __memcpy_device from Position + 0x10 to BuffAddr. - long BuffSize = Reader.ReadInt64(); - long BuffAddr = Reader.ReadInt64(); - - BuffSize = 0xa0; - - Writer.WriteInt64(BuffSize); - Writer.WriteInt64(BuffAddr); - Writer.WriteInt32(0x120); //NVGPU_GPU_ARCH_GM200 - Writer.WriteInt32(0xb); //NVGPU_GPU_IMPL_GM20B - Writer.WriteInt32(0xa1); - Writer.WriteInt32(1); - Writer.WriteInt64(0x40000); - Writer.WriteInt64(0); - Writer.WriteInt32(2); - Writer.WriteInt32(0x20); //NVGPU_GPU_BUS_TYPE_AXI - Writer.WriteInt32(0x20000); - Writer.WriteInt32(0x20000); - Writer.WriteInt32(0x1b); - Writer.WriteInt32(0x30000); - Writer.WriteInt32(1); - Writer.WriteInt32(0x503); - Writer.WriteInt32(0x503); - Writer.WriteInt32(0x80); - Writer.WriteInt32(0x28); - Writer.WriteInt32(0); - Writer.WriteInt64(0x55); - Writer.WriteInt32(0x902d); //FERMI_TWOD_A - Writer.WriteInt32(0xb197); //MAXWELL_B - Writer.WriteInt32(0xb1c0); //MAXWELL_COMPUTE_B - Writer.WriteInt32(0xb06f); //MAXWELL_CHANNEL_GPFIFO_A - Writer.WriteInt32(0xa140); //KEPLER_INLINE_TO_MEMORY_B - Writer.WriteInt32(0xb0b5); //MAXWELL_DMA_COPY_A - Writer.WriteInt32(1); - Writer.WriteInt32(0); - Writer.WriteInt32(2); - Writer.WriteInt32(1); - Writer.WriteInt32(0); - Writer.WriteInt32(1); - Writer.WriteInt32(0x21d70); - Writer.WriteInt32(0); - Writer.WriteByte((byte)'g'); - Writer.WriteByte((byte)'m'); - Writer.WriteByte((byte)'2'); - Writer.WriteByte((byte)'0'); - Writer.WriteByte((byte)'b'); - Writer.WriteByte((byte)'\0'); - Writer.WriteByte((byte)'\0'); - Writer.WriteByte((byte)'\0'); - Writer.WriteInt64(0); - - return 0; - } - - private static long NvGpuIoctlGetTpcMasks(ServiceCtx Context) - { - long Position = Context.Request.PtrBuff[0].Position; - - MemReader Reader = new MemReader(Context.Memory, Position); - - int MaskBuffSize = Reader.ReadInt32(); - int Reserved = Reader.ReadInt32(); - long MaskBuffAddr = Reader.ReadInt64(); - long Unknown = Reader.ReadInt64(); - - return 0; - } - - private static long NvGpuIoctlZbcGetActiveSlotMask(ServiceCtx Context) - { - long Position = Context.Request.PtrBuff[0].Position; - - Context.Memory.WriteInt32(Position + 0, 7); - Context.Memory.WriteInt32(Position + 4, 1); - - return 0; - } - - private static long NvMapIoctlChannelSetUserData(ServiceCtx Context) - { - long Position = Context.Request.PtrBuff[0].Position; - - return 0; - } - - private static long NvMapIoctlChannelSetNvMap(ServiceCtx Context) - { - long Position = Context.Request.PtrBuff[0].Position; - - int Fd = Context.Memory.ReadInt32(Position); - - return 0; - } - - private static long NvMapIoctlChannelSubmitGpFifo(ServiceCtx Context) - { - long Position = Context.Request.PtrBuff[0].Position; - - MemReader Reader = new MemReader(Context.Memory, Position); - MemWriter Writer = new MemWriter(Context.Memory, Position + 0x10); - - long GpFifo = Reader.ReadInt64(); - int Count = Reader.ReadInt32(); - int Flags = Reader.ReadInt32(); - int FenceId = Reader.ReadInt32(); - int FenceVal = Reader.ReadInt32(); - - for (int Index = 0; Index < Count; Index++) - { - long GpFifoHdr = Reader.ReadInt64(); - - long GpuAddr = GpFifoHdr & 0xffffffffff; - - int Size = (int)(GpFifoHdr >> 40) & 0x7ffffc; - - long CpuAddr = Context.Ns.Gpu.GetCpuAddr(GpuAddr); - - if (CpuAddr != -1) - { - byte[] Data = AMemoryHelper.ReadBytes(Context.Memory, CpuAddr, Size); - - NsGpuPBEntry[] PushBuffer = NsGpuPBEntry.DecodePushBuffer(Data); - - Context.Ns.Gpu.ProcessPushBuffer(PushBuffer, Context.Memory); - } - } - - Writer.WriteInt32(0); - Writer.WriteInt32(0); - - return 0; - } - - private static long NvMapIoctlChannelAllocObjCtx(ServiceCtx Context) - { - long Position = Context.Request.PtrBuff[0].Position; - - int ClassNum = Context.Memory.ReadInt32(Position + 0); - int Flags = Context.Memory.ReadInt32(Position + 4); - - Context.Memory.WriteInt32(Position + 8, 0); - - return 0; - } - - private static long NvMapIoctlChannelZcullBind(ServiceCtx Context) - { - long Position = Context.Request.PtrBuff[0].Position; - - MemReader Reader = new MemReader(Context.Memory, Position); - - long GpuVa = Reader.ReadInt64(); - int Mode = Reader.ReadInt32(); - int Padding = Reader.ReadInt32(); - - return 0; - } - - private static long NvMapIoctlChannelSetErrorNotifier(ServiceCtx Context) - { - long Position = Context.Request.PtrBuff[0].Position; - - MemReader Reader = new MemReader(Context.Memory, Position); - - long Offset = Reader.ReadInt64(); - long Size = Reader.ReadInt64(); - int Mem = Reader.ReadInt32(); - int Padding = Reader.ReadInt32(); - - return 0; - } - - private static long NvMapIoctlChannelSetPriority(ServiceCtx Context) - { - long Position = Context.Request.PtrBuff[0].Position; - - int Priority = Context.Memory.ReadInt32(Position); - - return 0; - } - - private static long NvMapIoctlChannelAllocGpFifoEx2(ServiceCtx Context) - { - long Position = Context.Request.PtrBuff[0].Position; - - MemReader Reader = new MemReader(Context.Memory, Position); - MemWriter Writer = new MemWriter(Context.Memory, Position + 0xc); - - int Count = Reader.ReadInt32(); - int Flags = Reader.ReadInt32(); - int Unknown8 = Reader.ReadInt32(); - long Fence = Reader.ReadInt64(); - int Unknown14 = Reader.ReadInt32(); - int Unknown18 = Reader.ReadInt32(); - - Writer.WriteInt32(0); - Writer.WriteInt32(0); - - return 0; - } - - private static long NvMapIocCreate(ServiceCtx Context) - { - long Position = Context.Request.GetSendBuffPtr(); - - int Size = Context.Memory.ReadInt32(Position); - - int Id = Context.Ns.Os.NvMapIds.GenerateId(); - - int Handle = Context.Ns.Os.Handles.GenerateId(new HNvMap(Id, Size)); - - Context.Memory.WriteInt32(Position + 4, Handle); - - return 0; - } - - private static long NvMapIocFromId(ServiceCtx Context) - { - long Position = Context.Request.GetSendBuffPtr(); - - int Id = Context.Memory.ReadInt32(Position); - - int Handle = -1; - - foreach (KeyValuePair KV in Context.Ns.Os.Handles) - { - if (KV.Value is HNvMap NvMap && NvMap.Id == Id) - { - Handle = KV.Key; - - break; - } - } - - Context.Memory.WriteInt32(Position + 4, Handle); - - return 0; - } - - private static long NvMapIocAlloc(ServiceCtx Context) - { - long Position = Context.Request.GetSendBuffPtr(); - - MemReader Reader = new MemReader(Context.Memory, Position); - - int Handle = Reader.ReadInt32(); - int HeapMask = Reader.ReadInt32(); - int Flags = Reader.ReadInt32(); - int Align = Reader.ReadInt32(); - byte Kind = (byte)Reader.ReadInt64(); - long Addr = Reader.ReadInt64(); - - HNvMap NvMap = Context.Ns.Os.Handles.GetData(Handle); - - if (NvMap != null) - { - NvMap.Address = Addr; - NvMap.Align = Align; - NvMap.Kind = Kind; - } - - Logging.Debug($"NvMapIocAlloc at {NvMap.Address:x16}"); - - return 0; - } - - private static long NvMapIocParam(ServiceCtx Context) - { - long Position = Context.Request.GetSendBuffPtr(); - - MemReader Reader = new MemReader(Context.Memory, Position); - - int Handle = Reader.ReadInt32(); - int Param = Reader.ReadInt32(); - - HNvMap NvMap = Context.Ns.Os.Handles.GetData(Handle); - - int Response = 0; - - switch (Param) - { - case 1: Response = NvMap.Size; break; - case 2: Response = NvMap.Align; break; - case 4: Response = 0x40000000; break; - case 5: Response = NvMap.Kind; break; - } - - Context.Memory.WriteInt32(Position + 8, Response); - - return 0; - } - - private static long NvMapIocGetId(ServiceCtx Context) - { - long Position = Context.Request.GetSendBuffPtr(); - - int Handle = Context.Memory.ReadInt32(Position + 4); - - HNvMap NvMap = Context.Ns.Os.Handles.GetData(Handle); - - Context.Memory.WriteInt32(Position, NvMap.Id); - - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/IpcServices/ObjHelper.cs b/Ryujinx.Core/OsHle/IpcServices/ObjHelper.cs deleted file mode 100644 index ff71838a..00000000 --- a/Ryujinx.Core/OsHle/IpcServices/ObjHelper.cs +++ /dev/null @@ -1,24 +0,0 @@ -using Ryujinx.Core.OsHle.Handles; -using Ryujinx.Core.OsHle.Ipc; - -namespace Ryujinx.Core.OsHle.IpcServices -{ - static class ObjHelper - { - public static void MakeObject(ServiceCtx Context, object Obj) - { - if (Context.Session is HDomain Dom) - { - Context.Response.ResponseObjIds.Add(Dom.GenerateObjectId(Obj)); - } - else - { - HSessionObj HndData = new HSessionObj(Context.Session, Obj); - - int VHandle = Context.Ns.Os.Handles.GenerateId(HndData); - - Context.Response.HandleDesc = IpcHandleDesc.MakeMove(VHandle); - } - } - } -} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/IpcServices/Pctl/IParentalControlService.cs b/Ryujinx.Core/OsHle/IpcServices/Pctl/IParentalControlService.cs deleted file mode 100644 index 4eb92d31..00000000 --- a/Ryujinx.Core/OsHle/IpcServices/Pctl/IParentalControlService.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Ryujinx.Core.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.Core.OsHle.IpcServices.Pctl -{ - class IParentalControlService : IIpcService - { - private Dictionary m_Commands; - - public IReadOnlyDictionary Commands => m_Commands; - - public IParentalControlService() - { - m_Commands = new Dictionary() - { - //... - }; - } - } -} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/IpcServices/Pctl/ServicePctl.cs b/Ryujinx.Core/OsHle/IpcServices/Pctl/ServicePctl.cs deleted file mode 100644 index 2d5e22a4..00000000 --- a/Ryujinx.Core/OsHle/IpcServices/Pctl/ServicePctl.cs +++ /dev/null @@ -1,29 +0,0 @@ -using Ryujinx.Core.OsHle.Ipc; -using System.Collections.Generic; - -using static Ryujinx.Core.OsHle.IpcServices.ObjHelper; - -namespace Ryujinx.Core.OsHle.IpcServices.Pctl -{ - class ServicePctl : IIpcService - { - private Dictionary m_Commands; - - public IReadOnlyDictionary Commands => m_Commands; - - public ServicePctl() - { - m_Commands = new Dictionary() - { - { 0, CreateService } - }; - } - - public static long CreateService(ServiceCtx Context) - { - MakeObject(Context, new IParentalControlService()); - - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/IpcServices/Pl/ServicePl.cs b/Ryujinx.Core/OsHle/IpcServices/Pl/ServicePl.cs deleted file mode 100644 index abc34ed2..00000000 --- a/Ryujinx.Core/OsHle/IpcServices/Pl/ServicePl.cs +++ /dev/null @@ -1,51 +0,0 @@ -using Ryujinx.Core.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.Core.OsHle.IpcServices.Pl -{ - class ServicePl : IIpcService - { - private Dictionary m_Commands; - - public IReadOnlyDictionary Commands => m_Commands; - - public ServicePl() - { - m_Commands = new Dictionary() - { - { 1, GetLoadState }, - { 2, GetFontSize }, - { 3, GetSharedMemoryAddressOffset }, - { 4, GetSharedMemoryNativeHandle } - }; - } - - public static long GetLoadState(ServiceCtx Context) - { - Context.ResponseData.Write(1); //Loaded - - return 0; - } - - public static long GetFontSize(ServiceCtx Context) - { - Context.ResponseData.Write(Horizon.FontSize); - - return 0; - } - - public static long GetSharedMemoryAddressOffset(ServiceCtx Context) - { - Context.ResponseData.Write(0); - - return 0; - } - - public static long GetSharedMemoryNativeHandle(ServiceCtx Context) - { - Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Context.Ns.Os.FontHandle); - - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/IpcServices/ServiceFactory.cs b/Ryujinx.Core/OsHle/IpcServices/ServiceFactory.cs deleted file mode 100644 index e9613050..00000000 --- a/Ryujinx.Core/OsHle/IpcServices/ServiceFactory.cs +++ /dev/null @@ -1,50 +0,0 @@ -using Ryujinx.Core.OsHle.IpcServices.Acc; -using Ryujinx.Core.OsHle.IpcServices.Am; -using Ryujinx.Core.OsHle.IpcServices.Apm; -using Ryujinx.Core.OsHle.IpcServices.Aud; -using Ryujinx.Core.OsHle.IpcServices.Friend; -using Ryujinx.Core.OsHle.IpcServices.FspSrv; -using Ryujinx.Core.OsHle.IpcServices.Hid; -using Ryujinx.Core.OsHle.IpcServices.Lm; -using Ryujinx.Core.OsHle.IpcServices.NvServices; -using Ryujinx.Core.OsHle.IpcServices.Pctl; -using Ryujinx.Core.OsHle.IpcServices.Pl; -using Ryujinx.Core.OsHle.IpcServices.Set; -using Ryujinx.Core.OsHle.IpcServices.Sm; -using Ryujinx.Core.OsHle.IpcServices.Time; -using Ryujinx.Core.OsHle.IpcServices.Vi; -using System; - -namespace Ryujinx.Core.OsHle.IpcServices -{ - static class ServiceFactory - { - public static IIpcService MakeService(string Name) - { - switch (Name) - { - case "acc:u0": return new ServiceAcc(); - case "apm": return new ServiceApm(); - case "apm:p": return new ServiceApm(); - case "appletOE": return new ServiceAppletOE(); - case "audout:u": return new ServiceAudOut(); - case "audren:u": return new ServiceAudRen(); - case "friend:a": return new ServiceFriend(); - case "fsp-srv": return new ServiceFspSrv(); - case "hid": return new ServiceHid(); - case "lm": return new ServiceLm(); - case "nvdrv": return new ServiceNvDrv(); - case "nvdrv:a": return new ServiceNvDrv(); - case "pctl:a": return new ServicePctl(); - case "pl:u": return new ServicePl(); - case "set": return new ServiceSet(); - case "sm:": return new ServiceSm(); - case "time:s": return new ServiceTime(); - case "time:u": return new ServiceTime(); - case "vi:m": return new ServiceVi(); - } - - throw new NotImplementedException(Name); - } - } -} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/IpcServices/Set/ServiceSet.cs b/Ryujinx.Core/OsHle/IpcServices/Set/ServiceSet.cs deleted file mode 100644 index 05e409b0..00000000 --- a/Ryujinx.Core/OsHle/IpcServices/Set/ServiceSet.cs +++ /dev/null @@ -1,46 +0,0 @@ -using ChocolArm64.Memory; -using Ryujinx.Core.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.Core.OsHle.IpcServices.Set -{ - class ServiceSet : IIpcService - { - private Dictionary m_Commands; - - public IReadOnlyDictionary Commands => m_Commands; - - public ServiceSet() - { - m_Commands = new Dictionary() - { - { 1, GetAvailableLanguageCodes } - }; - } - - private const int LangCodesCount = 13; - - public static long GetAvailableLanguageCodes(ServiceCtx Context) - { - int PtrBuffSize = Context.RequestData.ReadInt32(); - - if (Context.Request.RecvListBuff.Count > 0) - { - long Position = Context.Request.RecvListBuff[0].Position; - short Size = Context.Request.RecvListBuff[0].Size; - - //This should return an array of ints with values matching the LanguageCode enum. - byte[] Data = new byte[Size]; - - Data[0] = 0; - Data[1] = 1; - - AMemoryHelper.WriteBytes(Context.Memory, Position, Data); - } - - Context.ResponseData.Write(LangCodesCount); - - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/IpcServices/Sm/ServiceSm.cs b/Ryujinx.Core/OsHle/IpcServices/Sm/ServiceSm.cs deleted file mode 100644 index a5f1b329..00000000 --- a/Ryujinx.Core/OsHle/IpcServices/Sm/ServiceSm.cs +++ /dev/null @@ -1,67 +0,0 @@ -using Ryujinx.Core.OsHle.Handles; -using Ryujinx.Core.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.Core.OsHle.IpcServices.Sm -{ - class ServiceSm : IIpcService - { - private Dictionary m_Commands; - - public IReadOnlyDictionary Commands => m_Commands; - - public ServiceSm() - { - m_Commands = new Dictionary() - { - { 0, Initialize }, - { 1, GetService } - }; - } - - private const int SmNotInitialized = 0x415; - - public long Initialize(ServiceCtx Context) - { - Context.Session.Initialize(); - - return 0; - } - - public long GetService(ServiceCtx Context) - { - //Only for kernel version > 3.0.0. - if (!Context.Session.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; - } - - HSession Session = new HSession(ServiceFactory.MakeService(Name)); - - int Handle = Context.Ns.Os.Handles.GenerateId(Session); - - Context.Response.HandleDesc = IpcHandleDesc.MakeMove(Handle); - - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/IpcServices/Time/ISteadyClock.cs b/Ryujinx.Core/OsHle/IpcServices/Time/ISteadyClock.cs deleted file mode 100644 index d20e4378..00000000 --- a/Ryujinx.Core/OsHle/IpcServices/Time/ISteadyClock.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Ryujinx.Core.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.Core.OsHle.IpcServices.Time -{ - class ISteadyClock : IIpcService - { - private Dictionary m_Commands; - - public IReadOnlyDictionary Commands => m_Commands; - - public ISteadyClock() - { - m_Commands = new Dictionary() - { - //... - }; - } - } -} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/IpcServices/Time/ISystemClock.cs b/Ryujinx.Core/OsHle/IpcServices/Time/ISystemClock.cs deleted file mode 100644 index 4d4493da..00000000 --- a/Ryujinx.Core/OsHle/IpcServices/Time/ISystemClock.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Ryujinx.Core.OsHle.Ipc; -using System; -using System.Collections.Generic; - -namespace Ryujinx.Core.OsHle.IpcServices.Time -{ - class ISystemClock : IIpcService - { - private Dictionary m_Commands; - - public IReadOnlyDictionary Commands => m_Commands; - - private static DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); - - private SystemClockType ClockType; - - public ISystemClock(SystemClockType ClockType) - { - m_Commands = new Dictionary() - { - { 0, GetCurrentTime } - }; - - this.ClockType = ClockType; - } - - public long GetCurrentTime(ServiceCtx Context) - { - DateTime CurrentTime = DateTime.Now; - - if (ClockType == SystemClockType.User || - ClockType == SystemClockType.Network) - { - CurrentTime = CurrentTime.ToUniversalTime(); - } - - Context.ResponseData.Write((long)(DateTime.Now - Epoch).TotalSeconds); - - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/IpcServices/Time/ITimeZoneService.cs b/Ryujinx.Core/OsHle/IpcServices/Time/ITimeZoneService.cs deleted file mode 100644 index 9875fa2f..00000000 --- a/Ryujinx.Core/OsHle/IpcServices/Time/ITimeZoneService.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Ryujinx.Core.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.Core.OsHle.IpcServices.Time -{ - class ITimeZoneService : IIpcService - { - private Dictionary m_Commands; - - public IReadOnlyDictionary Commands => m_Commands; - - public ITimeZoneService() - { - m_Commands = new Dictionary() - { - //... - }; - } - } -} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/IpcServices/Time/ServiceTime.cs b/Ryujinx.Core/OsHle/IpcServices/Time/ServiceTime.cs deleted file mode 100644 index 43f28bb8..00000000 --- a/Ryujinx.Core/OsHle/IpcServices/Time/ServiceTime.cs +++ /dev/null @@ -1,62 +0,0 @@ -using Ryujinx.Core.OsHle.Ipc; -using System.Collections.Generic; - -using static Ryujinx.Core.OsHle.IpcServices.ObjHelper; - -namespace Ryujinx.Core.OsHle.IpcServices.Time -{ - class ServiceTime : IIpcService - { - private Dictionary m_Commands; - - public IReadOnlyDictionary Commands => m_Commands; - - public ServiceTime() - { - m_Commands = new Dictionary() - { - { 0, GetStandardUserSystemClock }, - { 1, GetStandardNetworkSystemClock }, - { 2, GetStandardSteadyClock }, - { 3, GetTimeZoneService }, - { 4, GetStandardLocalSystemClock } - }; - } - - 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; - } - - } -} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/IpcServices/Time/SystemClockType.cs b/Ryujinx.Core/OsHle/IpcServices/Time/SystemClockType.cs deleted file mode 100644 index 2314942a..00000000 --- a/Ryujinx.Core/OsHle/IpcServices/Time/SystemClockType.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Ryujinx.Core.OsHle.IpcServices.Time -{ - enum SystemClockType - { - User, - Network, - Local - } -} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/IpcServices/Vi/IApplicationDisplayService.cs b/Ryujinx.Core/OsHle/IpcServices/Vi/IApplicationDisplayService.cs deleted file mode 100644 index a899cdd5..00000000 --- a/Ryujinx.Core/OsHle/IpcServices/Vi/IApplicationDisplayService.cs +++ /dev/null @@ -1,176 +0,0 @@ -using ChocolArm64.Memory; -using Ryujinx.Core.OsHle.Handles; -using Ryujinx.Core.OsHle.Ipc; -using System.Collections.Generic; -using System.IO; - -using static Ryujinx.Core.OsHle.IpcServices.Android.Parcel; -using static Ryujinx.Core.OsHle.IpcServices.ObjHelper; - -namespace Ryujinx.Core.OsHle.IpcServices.Vi -{ - class IApplicationDisplayService : IIpcService - { - private Dictionary m_Commands; - - public IReadOnlyDictionary Commands => m_Commands; - - public IApplicationDisplayService() - { - m_Commands = new Dictionary() - { - { 100, GetRelayService }, - { 101, GetSystemDisplayService }, - { 102, GetManagerDisplayService }, - { 103, GetIndirectDisplayTransactionService }, - { 1010, OpenDisplay }, - { 2020, OpenLayer }, - { 2030, CreateStrayLayer }, - { 2101, SetLayerScalingMode }, - { 5202, GetDisplayVSyncEvent } - }; - } - - public long GetRelayService(ServiceCtx Context) - { - MakeObject(Context, new IHOSBinderDriver()); - - 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()); - - return 0; - } - - public long OpenDisplay(ServiceCtx Context) - { - string Name = GetDisplayName(Context); - - long DisplayId = Context.Ns.Os.Displays.GenerateId(new Display(Name)); - - Context.ResponseData.Write(DisplayId); - - 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); - - AMemoryHelper.WriteBytes(Context.Memory, ParcelPtr, Parcel); - - Context.ResponseData.Write((long)Parcel.Length); - - 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 = Context.Ns.Os.Displays.GetData((int)DisplayId); - - byte[] Parcel = MakeIGraphicsBufferProducer(ParcelPtr); - - AMemoryHelper.WriteBytes(Context.Memory, ParcelPtr, Parcel); - - Context.ResponseData.Write(0L); - Context.ResponseData.Write((long)Parcel.Length); - - 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.Ns.Os.Handles.GenerateId(new HEvent()); - - 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.Core/OsHle/IpcServices/Vi/IHOSBinderDriver.cs b/Ryujinx.Core/OsHle/IpcServices/Vi/IHOSBinderDriver.cs deleted file mode 100644 index a89c1df8..00000000 --- a/Ryujinx.Core/OsHle/IpcServices/Vi/IHOSBinderDriver.cs +++ /dev/null @@ -1,76 +0,0 @@ -using ChocolArm64.Memory; -using Ryujinx.Core.OsHle.Ipc; -using Ryujinx.Core.OsHle.IpcServices.Android; -using System; -using System.Collections.Generic; - -namespace Ryujinx.Core.OsHle.IpcServices.Vi -{ - class IHOSBinderDriver : IIpcService, IDisposable - { - private Dictionary m_Commands; - - public IReadOnlyDictionary Commands => m_Commands; - - private NvFlinger Flinger; - - public IHOSBinderDriver() - { - m_Commands = new Dictionary() - { - { 0, TransactParcel }, - { 1, AdjustRefcount }, - { 2, GetNativeHandle } - }; - - Flinger = new NvFlinger(); - } - - 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 = AMemoryHelper.ReadBytes(Context.Memory, DataPos, (int)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(); - - Context.Response.HandleDesc = IpcHandleDesc.MakeMove(0xbadcafe); - - return 0; - } - - public void Dispose() - { - Dispose(true); - } - - protected virtual void Dispose(bool disposing) - { - if (disposing) - { - Flinger.Dispose(); - } - } - } -} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/IpcServices/Vi/IManagerDisplayService.cs b/Ryujinx.Core/OsHle/IpcServices/Vi/IManagerDisplayService.cs deleted file mode 100644 index 5adee78d..00000000 --- a/Ryujinx.Core/OsHle/IpcServices/Vi/IManagerDisplayService.cs +++ /dev/null @@ -1,33 +0,0 @@ -using Ryujinx.Core.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.Core.OsHle.IpcServices.Vi -{ - class IManagerDisplayService : IIpcService - { - private Dictionary m_Commands; - - public IReadOnlyDictionary Commands => m_Commands; - - public IManagerDisplayService() - { - m_Commands = new Dictionary() - { - { 2010, CreateManagedLayer }, - { 6000, AddToLayerStack } - }; - } - - public static long CreateManagedLayer(ServiceCtx Context) - { - Context.ResponseData.Write(0L); //LayerId - - return 0; - } - - public static long AddToLayerStack(ServiceCtx Context) - { - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/IpcServices/Vi/ISystemDisplayService.cs b/Ryujinx.Core/OsHle/IpcServices/Vi/ISystemDisplayService.cs deleted file mode 100644 index d87fcbf6..00000000 --- a/Ryujinx.Core/OsHle/IpcServices/Vi/ISystemDisplayService.cs +++ /dev/null @@ -1,25 +0,0 @@ -using Ryujinx.Core.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.Core.OsHle.IpcServices.Vi -{ - class ISystemDisplayService : IIpcService - { - private Dictionary m_Commands; - - public IReadOnlyDictionary Commands => m_Commands; - - public ISystemDisplayService() - { - m_Commands = new Dictionary() - { - { 2205, SetLayerZ } - }; - } - - public static long SetLayerZ(ServiceCtx Context) - { - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/IpcServices/Vi/ServiceVi.cs b/Ryujinx.Core/OsHle/IpcServices/Vi/ServiceVi.cs deleted file mode 100644 index 2c3dd2a3..00000000 --- a/Ryujinx.Core/OsHle/IpcServices/Vi/ServiceVi.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Ryujinx.Core.OsHle.Ipc; -using System.Collections.Generic; - -using static Ryujinx.Core.OsHle.IpcServices.ObjHelper; - -namespace Ryujinx.Core.OsHle.IpcServices.Vi -{ - class ServiceVi : IIpcService - { - private Dictionary m_Commands; - - public IReadOnlyDictionary Commands => m_Commands; - - public ServiceVi() - { - m_Commands = new Dictionary() - { - { 2, GetDisplayService } - }; - } - - public long GetDisplayService(ServiceCtx Context) - { - int Unknown = Context.RequestData.ReadInt32(); - - MakeObject(Context, new IApplicationDisplayService()); - - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/Acc/IManagerForApplication.cs b/Ryujinx.Core/OsHle/Services/Acc/IManagerForApplication.cs new file mode 100644 index 00000000..ab491eac --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/Acc/IManagerForApplication.cs @@ -0,0 +1,33 @@ +using Ryujinx.Core.OsHle.Ipc; +using System.Collections.Generic; + +namespace Ryujinx.Core.OsHle.IpcServices.Acc +{ + class IManagerForApplication : IIpcService + { + private Dictionary m_Commands; + + public IReadOnlyDictionary Commands => m_Commands; + + public IManagerForApplication() + { + m_Commands = new Dictionary() + { + { 0, CheckAvailability }, + { 1, GetAccountId } + }; + } + + public long CheckAvailability(ServiceCtx Context) + { + return 0; + } + + public long GetAccountId(ServiceCtx Context) + { + Context.ResponseData.Write(0xcafeL); + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/Acc/IProfile.cs b/Ryujinx.Core/OsHle/Services/Acc/IProfile.cs new file mode 100644 index 00000000..77fe2b48 --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/Acc/IProfile.cs @@ -0,0 +1,33 @@ +using Ryujinx.Core.OsHle.Ipc; +using System.Collections.Generic; + +namespace Ryujinx.Core.OsHle.IpcServices.Acc +{ + class IProfile : IIpcService + { + private Dictionary m_Commands; + + public IReadOnlyDictionary Commands => m_Commands; + + public IProfile() + { + m_Commands = new Dictionary() + { + { 1, GetBase } + }; + } + + public long GetBase(ServiceCtx Context) + { + Context.ResponseData.Write(0L); + Context.ResponseData.Write(0L); + Context.ResponseData.Write(0L); + Context.ResponseData.Write(0L); + Context.ResponseData.Write(0L); + Context.ResponseData.Write(0L); + Context.ResponseData.Write(0L); + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/Acc/ServiceAcc.cs b/Ryujinx.Core/OsHle/Services/Acc/ServiceAcc.cs new file mode 100644 index 00000000..8844bb5d --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/Acc/ServiceAcc.cs @@ -0,0 +1,49 @@ +using Ryujinx.Core.OsHle.Ipc; +using System.Collections.Generic; + +using static Ryujinx.Core.OsHle.IpcServices.ObjHelper; + +namespace Ryujinx.Core.OsHle.IpcServices.Acc +{ + class ServiceAcc : IIpcService + { + private Dictionary m_Commands; + + public IReadOnlyDictionary Commands => m_Commands; + + public ServiceAcc() + { + m_Commands = new Dictionary() + { + { 3, ListOpenUsers }, + { 5, GetProfile }, + { 100, InitializeApplicationInfo }, + { 101, GetBaasAccountManagerForApplication } + }; + } + + public long ListOpenUsers(ServiceCtx Context) + { + return 0; + } + + public long GetProfile(ServiceCtx Context) + { + MakeObject(Context, new IProfile()); + + return 0; + } + + public long InitializeApplicationInfo(ServiceCtx Context) + { + return 0; + } + + public long GetBaasAccountManagerForApplication(ServiceCtx Context) + { + MakeObject(Context, new IManagerForApplication()); + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/Am/IApplicationFunctions.cs b/Ryujinx.Core/OsHle/Services/Am/IApplicationFunctions.cs new file mode 100644 index 00000000..6c5beeb3 --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/Am/IApplicationFunctions.cs @@ -0,0 +1,94 @@ +using Ryujinx.Core.OsHle.Ipc; +using System; +using System.Collections.Generic; +using System.IO; + +using static Ryujinx.Core.OsHle.IpcServices.ObjHelper; + +namespace Ryujinx.Core.OsHle.IpcServices.Am +{ + class IApplicationFunctions : IIpcService + { + private Dictionary m_Commands; + + public IReadOnlyDictionary Commands => m_Commands; + + public IApplicationFunctions() + { + m_Commands = new Dictionary() + { + { 1, PopLaunchParameter }, + { 20, EnsureSaveData }, + { 21, GetDesiredLanguage }, + { 22, SetTerminateResult }, + { 40, NotifyRunning } + }; + } + + private const uint LaunchParamsMagic = 0xc79497ca; + + public long PopLaunchParameter(ServiceCtx Context) + { + //Only the first 0x18 bytes of the Data seems to be actually used. + MakeObject(Context, new IStorage(MakeLaunchParams())); + + return 0; + } + + public long EnsureSaveData(ServiceCtx Context) + { + long UIdLow = Context.RequestData.ReadInt64(); + long UIdHigh = Context.RequestData.ReadInt64(); + + Context.ResponseData.Write(0L); + + return 0; + } + + public long GetDesiredLanguage(ServiceCtx Context) + { + //This is an enumerator where each number is a differnet language. + //0 is Japanese and 1 is English, need to figure out the other codes. + Context.ResponseData.Write(1L); + + return 0; + } + + public long SetTerminateResult(ServiceCtx Context) + { + int ErrorCode = Context.RequestData.ReadInt32(); + + int Module = ErrorCode & 0xFF; + int Description = (ErrorCode >> 9) & 0xFFF; + + Logging.Info($"({(ErrorModule)Module}){2000 + Module}-{Description}"); + + return 0; + } + + public long NotifyRunning(ServiceCtx Context) + { + Context.ResponseData.Write(1); + + return 0; + } + + private 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(); + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/Am/IApplicationProxy.cs b/Ryujinx.Core/OsHle/Services/Am/IApplicationProxy.cs new file mode 100644 index 00000000..5417d7f0 --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/Am/IApplicationProxy.cs @@ -0,0 +1,85 @@ +using Ryujinx.Core.OsHle.Ipc; +using System.Collections.Generic; + +using static Ryujinx.Core.OsHle.IpcServices.ObjHelper; + +namespace Ryujinx.Core.OsHle.IpcServices.Am +{ + class IApplicationProxy : IIpcService + { + private Dictionary m_Commands; + + public 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.Core/OsHle/Services/Am/IAudioController.cs b/Ryujinx.Core/OsHle/Services/Am/IAudioController.cs new file mode 100644 index 00000000..1212f1e2 --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/Am/IAudioController.cs @@ -0,0 +1,20 @@ +using Ryujinx.Core.OsHle.Ipc; +using System.Collections.Generic; + +namespace Ryujinx.Core.OsHle.IpcServices.Am +{ + class IAudioController : IIpcService + { + private Dictionary m_Commands; + + public IReadOnlyDictionary Commands => m_Commands; + + public IAudioController() + { + m_Commands = new Dictionary() + { + //... + }; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/Am/ICommonStateGetter.cs b/Ryujinx.Core/OsHle/Services/Am/ICommonStateGetter.cs new file mode 100644 index 00000000..2999bbba --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/Am/ICommonStateGetter.cs @@ -0,0 +1,74 @@ +using Ryujinx.Core.OsHle.Ipc; +using System.Collections.Generic; + +namespace Ryujinx.Core.OsHle.IpcServices.Am +{ + class ICommonStateGetter : IIpcService + { + private Dictionary m_Commands; + + public IReadOnlyDictionary Commands => m_Commands; + + public ICommonStateGetter() + { + m_Commands = new Dictionary() + { + { 0, GetEventHandle }, + { 1, ReceiveMessage }, + { 5, GetOperationMode }, + { 6, GetPerformanceMode }, + { 9, GetCurrentFocusState }, + }; + } + + private enum FocusState + { + InFocus = 1, + OutOfFocus = 2 + } + + private enum OperationMode + { + Handheld = 0, + Docked = 1 + } + + public long GetEventHandle(ServiceCtx Context) + { + Context.ResponseData.Write(0L); + + return 0; + } + + public long ReceiveMessage(ServiceCtx Context) + { + //Program expects 0xF at 0x17ae70 on puyo sdk, + //otherwise runs on a infinite loop until it reads said value. + //What it means is still unknown. + Context.ResponseData.Write(0xfL); + + return 0; //0x680; + } + + public long GetOperationMode(ServiceCtx Context) + { + Context.ResponseData.Write((byte)OperationMode.Handheld); + + return 0; + } + + public long GetPerformanceMode(ServiceCtx Context) + { + Context.ResponseData.Write((byte)0); + + return 0; + } + + public long GetCurrentFocusState(ServiceCtx Context) + { + Context.ResponseData.Write((byte)FocusState.InFocus); + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/Am/IDebugFunctions.cs b/Ryujinx.Core/OsHle/Services/Am/IDebugFunctions.cs new file mode 100644 index 00000000..944e58d8 --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/Am/IDebugFunctions.cs @@ -0,0 +1,20 @@ +using Ryujinx.Core.OsHle.Ipc; +using System.Collections.Generic; + +namespace Ryujinx.Core.OsHle.IpcServices.Am +{ + class IDebugFunctions : IIpcService + { + private Dictionary m_Commands; + + public IReadOnlyDictionary Commands => m_Commands; + + public IDebugFunctions() + { + m_Commands = new Dictionary() + { + //... + }; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/Am/IDisplayController.cs b/Ryujinx.Core/OsHle/Services/Am/IDisplayController.cs new file mode 100644 index 00000000..979e842a --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/Am/IDisplayController.cs @@ -0,0 +1,20 @@ +using Ryujinx.Core.OsHle.Ipc; +using System.Collections.Generic; + +namespace Ryujinx.Core.OsHle.IpcServices.Am +{ + class IDisplayController : IIpcService + { + private Dictionary m_Commands; + + public IReadOnlyDictionary Commands => m_Commands; + + public IDisplayController() + { + m_Commands = new Dictionary() + { + //... + }; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/Am/ILibraryAppletCreator.cs b/Ryujinx.Core/OsHle/Services/Am/ILibraryAppletCreator.cs new file mode 100644 index 00000000..9f5b5e69 --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/Am/ILibraryAppletCreator.cs @@ -0,0 +1,20 @@ +using Ryujinx.Core.OsHle.Ipc; +using System.Collections.Generic; + +namespace Ryujinx.Core.OsHle.IpcServices.Am +{ + class ILibraryAppletCreator : IIpcService + { + private Dictionary m_Commands; + + public IReadOnlyDictionary Commands => m_Commands; + + public ILibraryAppletCreator() + { + m_Commands = new Dictionary() + { + //... + }; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/Am/ISelfController.cs b/Ryujinx.Core/OsHle/Services/Am/ISelfController.cs new file mode 100644 index 00000000..403e4072 --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/Am/ISelfController.cs @@ -0,0 +1,75 @@ +using Ryujinx.Core.OsHle.Ipc; +using System.Collections.Generic; + +namespace Ryujinx.Core.OsHle.IpcServices.Am +{ + class ISelfController : IIpcService + { + private Dictionary m_Commands; + + public IReadOnlyDictionary Commands => m_Commands; + + public ISelfController() + { + m_Commands = new Dictionary() + { + { 1, Exit }, + { 10, SetScreenShotPermission }, + { 11, SetOperationModeChangedNotification }, + { 12, SetPerformanceModeChangedNotification }, + { 13, SetFocusHandlingMode }, + { 14, SetRestartMessageEnabled }, + { 16, SetOutOfFocusSuspendingEnabled } + }; + } + + public long Exit(ServiceCtx Context) + { + return 0; + } + + public long SetScreenShotPermission(ServiceCtx Context) + { + bool Enable = Context.RequestData.ReadByte() != 0 ? true : false; + + return 0; + } + + public long SetOperationModeChangedNotification(ServiceCtx Context) + { + bool Enable = Context.RequestData.ReadByte() != 0 ? true : false; + + return 0; + } + + public long SetPerformanceModeChangedNotification(ServiceCtx Context) + { + bool Enable = Context.RequestData.ReadByte() != 0 ? true : false; + + 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; + + return 0; + } + + public long SetRestartMessageEnabled(ServiceCtx Context) + { + bool Enable = Context.RequestData.ReadByte() != 0 ? true : false; + + return 0; + } + + public long SetOutOfFocusSuspendingEnabled(ServiceCtx Context) + { + bool Enable = Context.RequestData.ReadByte() != 0 ? true : false; + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/Am/IStorage.cs b/Ryujinx.Core/OsHle/Services/Am/IStorage.cs new file mode 100644 index 00000000..375b960b --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/Am/IStorage.cs @@ -0,0 +1,33 @@ +using Ryujinx.Core.OsHle.Ipc; +using System.Collections.Generic; + +using static Ryujinx.Core.OsHle.IpcServices.ObjHelper; + +namespace Ryujinx.Core.OsHle.IpcServices.Am +{ + class IStorage : IIpcService + { + private Dictionary m_Commands; + + public 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.Core/OsHle/Services/Am/IStorageAccessor.cs b/Ryujinx.Core/OsHle/Services/Am/IStorageAccessor.cs new file mode 100644 index 00000000..6d83e6f9 --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/Am/IStorageAccessor.cs @@ -0,0 +1,62 @@ +using ChocolArm64.Memory; +using Ryujinx.Core.OsHle.Ipc; +using System; +using System.Collections.Generic; + +namespace Ryujinx.Core.OsHle.IpcServices.Am +{ + class IStorageAccessor : IIpcService + { + private Dictionary m_Commands; + + public IReadOnlyDictionary Commands => m_Commands; + + private IStorage Storage; + + public IStorageAccessor(IStorage Storage) + { + m_Commands = new Dictionary() + { + { 0, GetSize }, + { 11, Read } + }; + + this.Storage = Storage; + } + + public long GetSize(ServiceCtx Context) + { + Context.ResponseData.Write((long)Storage.Data.Length); + + return 0; + } + + public long Read(ServiceCtx Context) + { + long ReadPosition = Context.RequestData.ReadInt64(); + + if (Context.Request.RecvListBuff.Count > 0) + { + long Position = Context.Request.RecvListBuff[0].Position; + short Size = Context.Request.RecvListBuff[0].Size; + + byte[] Data; + + if (Storage.Data.Length > Size) + { + Data = new byte[Size]; + + Buffer.BlockCopy(Storage.Data, 0, Data, 0, Size); + } + else + { + Data = Storage.Data; + } + + AMemoryHelper.WriteBytes(Context.Memory, Position, Data); + } + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/Am/IWindowController.cs b/Ryujinx.Core/OsHle/Services/Am/IWindowController.cs new file mode 100644 index 00000000..ddc73bce --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/Am/IWindowController.cs @@ -0,0 +1,33 @@ +using Ryujinx.Core.OsHle.Ipc; +using System.Collections.Generic; + +namespace Ryujinx.Core.OsHle.IpcServices.Am +{ + class IWindowController : IIpcService + { + private Dictionary m_Commands; + + public IReadOnlyDictionary Commands => m_Commands; + + public IWindowController() + { + m_Commands = new Dictionary() + { + { 1, GetAppletResourceUserId }, + { 10, AcquireForegroundRights } + }; + } + + public long GetAppletResourceUserId(ServiceCtx Context) + { + Context.ResponseData.Write(0L); + + return 0; + } + + public long AcquireForegroundRights(ServiceCtx Context) + { + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/Am/ServiceAppletOE.cs b/Ryujinx.Core/OsHle/Services/Am/ServiceAppletOE.cs new file mode 100644 index 00000000..b60c93dd --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/Am/ServiceAppletOE.cs @@ -0,0 +1,29 @@ +using Ryujinx.Core.OsHle.Ipc; +using System.Collections.Generic; + +using static Ryujinx.Core.OsHle.IpcServices.ObjHelper; + +namespace Ryujinx.Core.OsHle.IpcServices.Am +{ + class ServiceAppletOE : IIpcService + { + private Dictionary m_Commands; + + public IReadOnlyDictionary Commands => m_Commands; + + public ServiceAppletOE() + { + 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.Core/OsHle/Services/Apm/ISession.cs b/Ryujinx.Core/OsHle/Services/Apm/ISession.cs new file mode 100644 index 00000000..500f7596 --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/Apm/ISession.cs @@ -0,0 +1,28 @@ +using Ryujinx.Core.OsHle.Ipc; +using System.Collections.Generic; + +namespace Ryujinx.Core.OsHle.IpcServices.Apm +{ + class ISession : IIpcService + { + private Dictionary m_Commands; + + public IReadOnlyDictionary Commands => m_Commands; + + public ISession() + { + m_Commands = new Dictionary() + { + { 0, SetPerformanceConfiguration } + }; + } + + public long SetPerformanceConfiguration(ServiceCtx Context) + { + int PerfMode = Context.RequestData.ReadInt32(); + int PerfConfig = Context.RequestData.ReadInt32(); + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/Apm/ServiceApm.cs b/Ryujinx.Core/OsHle/Services/Apm/ServiceApm.cs new file mode 100644 index 00000000..d6c0400a --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/Apm/ServiceApm.cs @@ -0,0 +1,29 @@ +using Ryujinx.Core.OsHle.Ipc; +using System.Collections.Generic; + +using static Ryujinx.Core.OsHle.IpcServices.ObjHelper; + +namespace Ryujinx.Core.OsHle.IpcServices.Apm +{ + class ServiceApm : IIpcService + { + private Dictionary m_Commands; + + public IReadOnlyDictionary Commands => m_Commands; + + public ServiceApm() + { + 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.Core/OsHle/Services/Aud/IAudioOut.cs b/Ryujinx.Core/OsHle/Services/Aud/IAudioOut.cs new file mode 100644 index 00000000..a45b23cc --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/Aud/IAudioOut.cs @@ -0,0 +1,180 @@ +using ChocolArm64.Memory; +using Ryujinx.Core.OsHle.Handles; +using Ryujinx.Core.OsHle.Ipc; +using OpenTK.Audio; +using OpenTK.Audio.OpenAL; +using System; +using System.Collections.Generic; +using System.IO; + +namespace Ryujinx.Core.OsHle.IpcServices.Aud +{ + class IAudioOut : IIpcService + { + private Dictionary m_Commands; + + public IReadOnlyDictionary Commands => m_Commands; + + public IAudioOut() + { + m_Commands = new Dictionary() + { + { 0, GetAudioOutState }, + { 1, StartAudioOut }, + { 2, StopAudioOut }, + { 3, AppendAudioOutBuffer }, + { 4, RegisterBufferEvent }, + { 5, GetReleasedAudioOutBuffer }, + { 6, ContainsAudioOutBuffer }, + { 7, AppendAudioOutBuffer_ex }, + { 8, GetReleasedAudioOutBuffer_ex } + }; + } + + enum AudioOutState + { + Started, + Stopped + }; + + //IAudioOut + private AudioOutState State = AudioOutState.Stopped; + private Queue KeysQueue = new Queue(); + + //OpenAL + private bool OpenALInstalled = true; + private AudioContext AudioCtx; + private int Source; + private int Buffer; + + //Return State of IAudioOut + public long GetAudioOutState(ServiceCtx Context) + { + Context.ResponseData.Write((int)State); + + return 0; + } + + public long StartAudioOut(ServiceCtx Context) + { + if (State == AudioOutState.Stopped) + { + State = AudioOutState.Started; + + try + { + AudioCtx = new AudioContext(); //Create the audio context + } + catch (Exception) + { + Logging.Warn("OpenAL Error! PS: Install OpenAL Core SDK!"); + OpenALInstalled = false; + } + + if (OpenALInstalled) AL.Listener(ALListenerf.Gain, (float)8.0); //Add more gain to it + } + + return 0; + } + + public long StopAudioOut(ServiceCtx Context) + { + if (State == AudioOutState.Started) + { + if (OpenALInstalled) + { + if (AudioCtx == null) //Needed to call the instance of AudioContext() + return 0; + + AL.SourceStop(Source); + AL.DeleteSource(Source); + } + State = AudioOutState.Stopped; + } + + return 0; + } + + public long AppendAudioOutBuffer(ServiceCtx Context) + { + long BufferId = Context.RequestData.ReadInt64(); + + KeysQueue.Enqueue(BufferId); + + byte[] AudioOutBuffer = AMemoryHelper.ReadBytes(Context.Memory, Context.Request.SendBuff[0].Position, sizeof(long) * 5); + using (MemoryStream MS = new MemoryStream(AudioOutBuffer)) + { + BinaryReader Reader = new BinaryReader(MS); + long PointerNextBuffer = Reader.ReadInt64(); + long PointerSampleBuffer = Reader.ReadInt64(); + long CapacitySampleBuffer = Reader.ReadInt64(); + long SizeDataInSampleBuffer = Reader.ReadInt64(); + long OffsetDataInSampleBuffer = Reader.ReadInt64(); + + byte[] AudioSampleBuffer = AMemoryHelper.ReadBytes(Context.Memory, PointerSampleBuffer + OffsetDataInSampleBuffer, (int)SizeDataInSampleBuffer); + + if (OpenALInstalled) + { + if (AudioCtx == null) //Needed to call the instance of AudioContext() + return 0; + + Buffer = AL.GenBuffer(); + AL.BufferData(Buffer, ALFormat.Stereo16, AudioSampleBuffer, AudioSampleBuffer.Length, 48000); + + Source = AL.GenSource(); + AL.SourceQueueBuffer(Source, Buffer); + } + } + + return 0; + } + + public long RegisterBufferEvent(ServiceCtx Context) + { + int Handle = Context.Ns.Os.Handles.GenerateId(new HEvent()); + + Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle); + + return 0; + } + + public long GetReleasedAudioOutBuffer(ServiceCtx Context) + { + long TempKey = 0; + + if (KeysQueue.Count > 0) TempKey = KeysQueue.Dequeue(); + + AMemoryHelper.WriteBytes(Context.Memory, Context.Request.ReceiveBuff[0].Position, BitConverter.GetBytes(TempKey)); + + int ReleasedBuffersCount = 1; + Context.ResponseData.Write(ReleasedBuffersCount); + + if (OpenALInstalled) + { + if (AudioCtx == null) //Needed to call the instance of AudioContext() + return 0; + + AL.SourcePlay(Source); + int[] FreeBuffers = AL.SourceUnqueueBuffers(Source, 1); + AL.DeleteBuffers(FreeBuffers); + } + + return 0; + } + + public long ContainsAudioOutBuffer(ServiceCtx Context) + { + return 0; + } + + public long AppendAudioOutBuffer_ex(ServiceCtx Context) + { + return 0; + } + + public long GetReleasedAudioOutBuffer_ex(ServiceCtx Context) + { + return 0; + } + } +} diff --git a/Ryujinx.Core/OsHle/Services/Aud/IAudioRenderer.cs b/Ryujinx.Core/OsHle/Services/Aud/IAudioRenderer.cs new file mode 100644 index 00000000..bfde0b65 --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/Aud/IAudioRenderer.cs @@ -0,0 +1,66 @@ +using Ryujinx.Core.OsHle.Handles; +using Ryujinx.Core.OsHle.Ipc; +using System.Collections.Generic; + +namespace Ryujinx.Core.OsHle.IpcServices.Aud +{ + class IAudioRenderer : IIpcService + { + private Dictionary m_Commands; + + public IReadOnlyDictionary Commands => m_Commands; + + public IAudioRenderer() + { + m_Commands = new Dictionary() + { + { 4, RequestUpdateAudioRenderer }, + { 5, StartAudioRenderer }, + { 6, StopAudioRenderer }, + { 7, QuerySystemEvent } + }; + } + + public long RequestUpdateAudioRenderer(ServiceCtx Context) + { + //(buffer) -> (buffer, buffer) + + long Position = Context.Request.ReceiveBuff[0].Position; + + //0x40 bytes header + Context.Memory.WriteInt32(Position + 0x4, 0xb0); //Behavior Out State Size? (note: this is the last section) + Context.Memory.WriteInt32(Position + 0x8, 0x18e0); //Memory Pool Out State Size? + Context.Memory.WriteInt32(Position + 0xc, 0x600); //Voice Out State Size? + Context.Memory.WriteInt32(Position + 0x14, 0xe0); //Effect Out State Size? + Context.Memory.WriteInt32(Position + 0x1c, 0x20); //Sink Out State Size? + Context.Memory.WriteInt32(Position + 0x20, 0x10); //Performance Out State Size? + Context.Memory.WriteInt32(Position + 0x3c, 0x20e0); //Total Size (including 0x40 bytes header) + + for (int Offset = 0x40; Offset < 0x40 + 0x18e0; Offset += 0x10) + { + Context.Memory.WriteInt32(Position + Offset, 5); + } + + return 0; + } + + public long StartAudioRenderer(ServiceCtx Context) + { + return 0; + } + + public long StopAudioRenderer(ServiceCtx Context) + { + return 0; + } + + public long QuerySystemEvent(ServiceCtx Context) + { + int Handle = Context.Ns.Os.Handles.GenerateId(new HEvent()); + + Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle); + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/Aud/ServiceAudOut.cs b/Ryujinx.Core/OsHle/Services/Aud/ServiceAudOut.cs new file mode 100644 index 00000000..eb923562 --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/Aud/ServiceAudOut.cs @@ -0,0 +1,57 @@ +using ChocolArm64.Memory; +using Ryujinx.Core.OsHle.Ipc; +using System.Collections.Generic; +using System.Text; + +using static Ryujinx.Core.OsHle.IpcServices.ObjHelper; + +namespace Ryujinx.Core.OsHle.IpcServices.Aud +{ + class ServiceAudOut : IIpcService + { + private Dictionary m_Commands; + + public IReadOnlyDictionary Commands => m_Commands; + + public ServiceAudOut() + { + m_Commands = new Dictionary() + { + { 0, ListAudioOuts }, + { 1, OpenAudioOut }, + }; + } + + public long ListAudioOuts(ServiceCtx Context) + { + long Position = Context.Request.ReceiveBuff[0].Position; + + AMemoryHelper.WriteBytes(Context.Memory, Position, Encoding.ASCII.GetBytes("iface")); + + Context.ResponseData.Write(1); + + return 0; + } + + public long OpenAudioOut(ServiceCtx Context) + { + MakeObject(Context, new IAudioOut()); + + Context.ResponseData.Write(48000); //Sample Rate + Context.ResponseData.Write(2); //Channel Count + Context.ResponseData.Write(2); //PCM Format + /* + 0 - Invalid + 1 - INT8 + 2 - INT16 + 3 - INT24 + 4 - INT32 + 5 - PCM Float + 6 - ADPCM + */ + Context.ResponseData.Write(0); //Unknown + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/Aud/ServiceAudRen.cs b/Ryujinx.Core/OsHle/Services/Aud/ServiceAudRen.cs new file mode 100644 index 00000000..eccc699c --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/Aud/ServiceAudRen.cs @@ -0,0 +1,51 @@ +using Ryujinx.Core.OsHle.Ipc; +using System.Collections.Generic; + +using static Ryujinx.Core.OsHle.IpcServices.ObjHelper; + +namespace Ryujinx.Core.OsHle.IpcServices.Aud +{ + class ServiceAudRen : IIpcService + { + private Dictionary m_Commands; + + public IReadOnlyDictionary Commands => m_Commands; + + public ServiceAudRen() + { + m_Commands = new Dictionary() + { + { 0, OpenAudioRenderer }, + { 1, GetAudioRendererWorkBufferSize }, + }; + } + + public long OpenAudioRenderer(ServiceCtx Context) + { + MakeObject(Context, new IAudioRenderer()); + + return 0; + } + + public long GetAudioRendererWorkBufferSize(ServiceCtx Context) + { + int SampleRate = Context.RequestData.ReadInt32(); + int Unknown4 = Context.RequestData.ReadInt32(); + int Unknown8 = Context.RequestData.ReadInt32(); + int UnknownC = Context.RequestData.ReadInt32(); + int Unknown10 = Context.RequestData.ReadInt32(); + int Unknown14 = Context.RequestData.ReadInt32(); + int Unknown18 = Context.RequestData.ReadInt32(); + int Unknown1c = Context.RequestData.ReadInt32(); + int Unknown20 = Context.RequestData.ReadInt32(); + int Unknown24 = Context.RequestData.ReadInt32(); + int Unknown28 = Context.RequestData.ReadInt32(); + int Unknown2c = Context.RequestData.ReadInt32(); + int Rev1Magic = Context.RequestData.ReadInt32(); + + Context.ResponseData.Write(0x400L); + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/ErrorCode.cs b/Ryujinx.Core/OsHle/Services/ErrorCode.cs new file mode 100644 index 00000000..a4e197b2 --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/ErrorCode.cs @@ -0,0 +1,10 @@ +namespace Ryujinx.Core.OsHle.IpcServices +{ + static class ErrorCode + { + public static long MakeError(ErrorModule Module, int Code) + { + return (int)Module | (Code << 9); + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/ErrorModule.cs b/Ryujinx.Core/OsHle/Services/ErrorModule.cs new file mode 100644 index 00000000..78af6195 --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/ErrorModule.cs @@ -0,0 +1,63 @@ +namespace Ryujinx.Core.OsHle.IpcServices +{ + enum ErrorModule + { + Kernel = 1, + Fs = 2, + Nvidia_TransferMemory = 3, + Ncm = 5, + Dd = 6, + Lr = 8, + Loader = 9, + IPC_Command_Interface = 10, + IPC = 11, + Pm = 15, + Ns = 16, + Htc = 18, + Sm = 21, + RO_Userland = 22, + SdMmc = 24, + Spl = 26, + Ethc = 100, + I2C = 101, + Settings = 105, + Nifm = 110, + Display = 114, + Ntc = 116, + Fdm = 117, + Pcie = 120, + Friends = 121, + SSL = 123, + Account = 124, + Mii = 126, + Am = 128, + Play_Report = 129, + Pcv = 133, + Omm = 134, + Nim = 137, + Psc = 138, + Usb = 140, + Nsd = 141, + Btm = 143, + Erpt = 147, + Apm = 148, + Audio = 153, + Npns = 154, + Arp = 157, + Boot = 158, + Nfc = 161, + Userland_Assert = 162, + Userland_Crash = 168, + Hid = 203, + Capture = 206, + Libnx = 345, + Homebrew_ABI = 346, + Homebrew_Loader = 347, + libnx_Nvidia_Errors = 348, + Tc = 651, + General_Web_Applet = 800, + Wifi_Web_Auth_Applet = 809, + Whitelisted_Applet = 810, + ShopN = 811 + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/Friend/IFriendService.cs b/Ryujinx.Core/OsHle/Services/Friend/IFriendService.cs new file mode 100644 index 00000000..e3e03da8 --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/Friend/IFriendService.cs @@ -0,0 +1,20 @@ +using Ryujinx.Core.OsHle.Ipc; +using System.Collections.Generic; + +namespace Ryujinx.Core.OsHle.IpcServices.Friend +{ + class IFriendService : IIpcService + { + private Dictionary m_Commands; + + public IReadOnlyDictionary Commands => m_Commands; + + public IFriendService() + { + m_Commands = new Dictionary() + { + //... + }; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/Friend/ServiceFriend.cs b/Ryujinx.Core/OsHle/Services/Friend/ServiceFriend.cs new file mode 100644 index 00000000..674877f6 --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/Friend/ServiceFriend.cs @@ -0,0 +1,29 @@ +using Ryujinx.Core.OsHle.Ipc; +using System.Collections.Generic; + +using static Ryujinx.Core.OsHle.IpcServices.ObjHelper; + +namespace Ryujinx.Core.OsHle.IpcServices.Friend +{ + class ServiceFriend : IIpcService + { + private Dictionary m_Commands; + + public IReadOnlyDictionary Commands => m_Commands; + + public ServiceFriend() + { + 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.Core/OsHle/Services/FspSrv/FsErr.cs b/Ryujinx.Core/OsHle/Services/FspSrv/FsErr.cs new file mode 100644 index 00000000..656d529f --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/FspSrv/FsErr.cs @@ -0,0 +1,9 @@ +namespace Ryujinx.Core.OsHle.IpcServices.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.Core/OsHle/Services/FspSrv/IDirectory.cs b/Ryujinx.Core/OsHle/Services/FspSrv/IDirectory.cs new file mode 100644 index 00000000..54dbec74 --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/FspSrv/IDirectory.cs @@ -0,0 +1,117 @@ +using ChocolArm64.Memory; +using Ryujinx.Core.OsHle.Ipc; +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; + +namespace Ryujinx.Core.OsHle.IpcServices.FspSrv +{ + class IDirectory : IIpcService, IDisposable + { + private const int DirectoryEntrySize = 0x310; + + private Dictionary m_Commands; + + public 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)); + + AMemoryHelper.WriteBytes(Context.Memory, 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.Core/OsHle/Services/FspSrv/IFile.cs b/Ryujinx.Core/OsHle/Services/FspSrv/IFile.cs new file mode 100644 index 00000000..ac2100f2 --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/FspSrv/IFile.cs @@ -0,0 +1,111 @@ +using ChocolArm64.Memory; +using Ryujinx.Core.OsHle.Ipc; +using System; +using System.Collections.Generic; +using System.IO; + +namespace Ryujinx.Core.OsHle.IpcServices.FspSrv +{ + class IFile : IIpcService, IDisposable + { + private Dictionary m_Commands; + + public 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); + + AMemoryHelper.WriteBytes(Context.Memory, 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 = AMemoryHelper.ReadBytes(Context.Memory, Position, (int)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.Core/OsHle/Services/FspSrv/IFileSystem.cs b/Ryujinx.Core/OsHle/Services/FspSrv/IFileSystem.cs new file mode 100644 index 00000000..ee9de8bc --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/FspSrv/IFileSystem.cs @@ -0,0 +1,383 @@ +using ChocolArm64.Memory; +using Ryujinx.Core.OsHle.Ipc; +using System; +using System.Collections.Generic; +using System.IO; + +using static Ryujinx.Core.OsHle.IpcServices.ErrorCode; +using static Ryujinx.Core.OsHle.IpcServices.ObjHelper; + +namespace Ryujinx.Core.OsHle.IpcServices.FspSrv +{ + class IFileSystem : IIpcService + { + private Dictionary m_Commands; + + public 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) + { + long Position = Context.Request.PtrBuff[0].Position; + + string Name = AMemoryHelper.ReadAsciiString(Context.Memory, Position); + + 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) + { + long Position = Context.Request.PtrBuff[0].Position; + + string Name = AMemoryHelper.ReadAsciiString(Context.Memory, Position); + + 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) + { + long Position = Context.Request.PtrBuff[0].Position; + + string Name = AMemoryHelper.ReadAsciiString(Context.Memory, Position); + + 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) + { + long Position = Context.Request.PtrBuff[0].Position; + + string Name = AMemoryHelper.ReadAsciiString(Context.Memory, Position); + + 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) + { + long OldPosition = Context.Request.PtrBuff[0].Position; + long NewPosition = Context.Request.PtrBuff[0].Position; + + string OldName = AMemoryHelper.ReadAsciiString(Context.Memory, OldPosition); + string NewName = AMemoryHelper.ReadAsciiString(Context.Memory, NewPosition); + + 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) + { + long OldPosition = Context.Request.PtrBuff[0].Position; + long NewPosition = Context.Request.PtrBuff[0].Position; + + string OldName = AMemoryHelper.ReadAsciiString(Context.Memory, OldPosition); + string NewName = AMemoryHelper.ReadAsciiString(Context.Memory, NewPosition); + + 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) + { + long Position = Context.Request.PtrBuff[0].Position; + + string Name = AMemoryHelper.ReadAsciiString(Context.Memory, Position); + + 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) + { + long Position = Context.Request.PtrBuff[0].Position; + + int FilterFlags = Context.RequestData.ReadInt32(); + + string Name = AMemoryHelper.ReadAsciiString(Context.Memory, Position); + + 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) + { + long Position = Context.Request.PtrBuff[0].Position; + + int FilterFlags = Context.RequestData.ReadInt32(); + + string Name = AMemoryHelper.ReadAsciiString(Context.Memory, Position); + + 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) + { + long Position = Context.Request.PtrBuff[0].Position; + + string Name = AMemoryHelper.ReadAsciiString(Context.Memory, Position); + + Context.ResponseData.Write(Context.Ns.VFs.GetDrive().AvailableFreeSpace); + + return 0; + } + + public long GetTotalSpaceSize(ServiceCtx Context) + { + long Position = Context.Request.PtrBuff[0].Position; + + string Name = AMemoryHelper.ReadAsciiString(Context.Memory, Position); + + Context.ResponseData.Write(Context.Ns.VFs.GetDrive().TotalSize); + + 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); + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/FspSrv/IStorage.cs b/Ryujinx.Core/OsHle/Services/FspSrv/IStorage.cs new file mode 100644 index 00000000..297461a0 --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/FspSrv/IStorage.cs @@ -0,0 +1,52 @@ +using ChocolArm64.Memory; +using Ryujinx.Core.OsHle.Ipc; +using System.Collections.Generic; +using System.IO; + +namespace Ryujinx.Core.OsHle.IpcServices.FspSrv +{ + class IStorage : IIpcService + { + private Dictionary m_Commands; + + public 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); + + AMemoryHelper.WriteBytes(Context.Memory, BuffDesc.Position, Data); + } + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/FspSrv/ServiceFspSrv.cs b/Ryujinx.Core/OsHle/Services/FspSrv/ServiceFspSrv.cs new file mode 100644 index 00000000..991f4027 --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/FspSrv/ServiceFspSrv.cs @@ -0,0 +1,67 @@ +using Ryujinx.Core.OsHle.Ipc; +using System.Collections.Generic; + +using static Ryujinx.Core.OsHle.IpcServices.ObjHelper; + +namespace Ryujinx.Core.OsHle.IpcServices.FspSrv +{ + class ServiceFspSrv : IIpcService + { + private Dictionary m_Commands; + + public IReadOnlyDictionary Commands => m_Commands; + + public ServiceFspSrv() + { + m_Commands = new Dictionary() + { + { 1, Initialize }, + { 18, MountSdCard }, + { 51, MountSaveData }, + { 200, OpenDataStorageByCurrentProcess }, + { 203, OpenRomStorage }, + { 1005, GetGlobalAccessLogMode } + }; + } + + public long Initialize(ServiceCtx Context) + { + return 0; + } + + public long MountSdCard(ServiceCtx Context) + { + MakeObject(Context, new IFileSystem(Context.Ns.VFs.GetSdCardPath())); + + return 0; + } + + public long MountSaveData(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 OpenRomStorage(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.Core/OsHle/Services/Hid/IActiveVibrationDeviceList.cs b/Ryujinx.Core/OsHle/Services/Hid/IActiveVibrationDeviceList.cs new file mode 100644 index 00000000..f6596f42 --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/Hid/IActiveVibrationDeviceList.cs @@ -0,0 +1,27 @@ +using Ryujinx.Core.OsHle.Ipc; +using System.Collections.Generic; + +namespace Ryujinx.Core.OsHle.IpcServices.Hid +{ + class IActiveApplicationDeviceList : IIpcService + { + private Dictionary m_Commands; + + public 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.Core/OsHle/Services/Hid/IAppletResource.cs b/Ryujinx.Core/OsHle/Services/Hid/IAppletResource.cs new file mode 100644 index 00000000..d22e0ff2 --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/Hid/IAppletResource.cs @@ -0,0 +1,32 @@ +using Ryujinx.Core.OsHle.Handles; +using Ryujinx.Core.OsHle.Ipc; +using System.Collections.Generic; + +namespace Ryujinx.Core.OsHle.IpcServices.Hid +{ + class IAppletResource : IIpcService + { + private Dictionary m_Commands; + + public IReadOnlyDictionary Commands => m_Commands; + + private HSharedMem Handle; + + public IAppletResource(HSharedMem Handle) + { + m_Commands = new Dictionary() + { + { 0, GetSharedMemoryHandle } + }; + + this.Handle = Handle; + } + + public static long GetSharedMemoryHandle(ServiceCtx Context) + { + Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Context.Ns.Os.HidHandle); + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/Hid/ServiceHid.cs b/Ryujinx.Core/OsHle/Services/Hid/ServiceHid.cs new file mode 100644 index 00000000..b0e5f44e --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/Hid/ServiceHid.cs @@ -0,0 +1,108 @@ +using Ryujinx.Core.OsHle.Handles; +using Ryujinx.Core.OsHle.Ipc; +using System.Collections.Generic; + +using static Ryujinx.Core.OsHle.IpcServices.ObjHelper; + +namespace Ryujinx.Core.OsHle.IpcServices.Hid +{ + class ServiceHid : IIpcService + { + private Dictionary m_Commands; + + public IReadOnlyDictionary Commands => m_Commands; + + public ServiceHid() + { + m_Commands = new Dictionary() + { + { 0, CreateAppletResource }, + { 11, ActivateTouchScreen }, + { 100, SetSupportedNpadStyleSet }, + { 101, GetSupportedNpadStyleSet }, + { 102, SetSupportedNpadIdType }, + { 103, ActivateNpad }, + { 120, SetNpadJoyHoldType }, + { 121, GetNpadJoyHoldType }, + { 200, GetVibrationDeviceInfo }, + { 203, CreateActiveVibrationDeviceList }, + }; + } + + public long CreateAppletResource(ServiceCtx Context) + { + HSharedMem HidHndData = Context.Ns.Os.Handles.GetData(Context.Ns.Os.HidHandle); + + MakeObject(Context, new IAppletResource(HidHndData)); + + return 0; + } + + public long ActivateTouchScreen(ServiceCtx Context) + { + long Unknown = Context.RequestData.ReadInt64(); + + return 0; + } + + public long GetSupportedNpadStyleSet(ServiceCtx Context) + { + Context.ResponseData.Write(0); + + return 0; + } + + public long SetSupportedNpadStyleSet(ServiceCtx Context) + { + long Unknown0 = Context.RequestData.ReadInt64(); + long Unknown8 = Context.RequestData.ReadInt64(); + + return 0; + } + + public long SetSupportedNpadIdType(ServiceCtx Context) + { + long Unknown = Context.RequestData.ReadInt64(); + + return 0; + } + + public long ActivateNpad(ServiceCtx Context) + { + long Unknown = Context.RequestData.ReadInt64(); + + return 0; + } + + public long SetNpadJoyHoldType(ServiceCtx Context) + { + long Unknown0 = Context.RequestData.ReadInt64(); + long Unknown8 = Context.RequestData.ReadInt64(); + + return 0; + } + + public long GetNpadJoyHoldType(ServiceCtx Context) + { + Context.ResponseData.Write(0L); + + return 0; + } + + public long GetVibrationDeviceInfo(ServiceCtx Context) + { + int VibrationDeviceHandle = Context.RequestData.ReadInt32(); + + Context.ResponseData.Write(0L); //VibrationDeviceInfoForIpc + + return 0; + } + + public long CreateActiveVibrationDeviceList(ServiceCtx Context) + { + MakeObject(Context, new IActiveApplicationDeviceList()); + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/IIpcService.cs b/Ryujinx.Core/OsHle/Services/IIpcService.cs new file mode 100644 index 00000000..eebcdfbe --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/IIpcService.cs @@ -0,0 +1,10 @@ +using Ryujinx.Core.OsHle.Ipc; +using System.Collections.Generic; + +namespace Ryujinx.Core.OsHle.IpcServices +{ + interface IIpcService + { + IReadOnlyDictionary Commands { get; } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/Lm/ILogger.cs b/Ryujinx.Core/OsHle/Services/Lm/ILogger.cs new file mode 100644 index 00000000..5ee097b6 --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/Lm/ILogger.cs @@ -0,0 +1,143 @@ +using ChocolArm64.Memory; +using Ryujinx.Core.OsHle.Ipc; +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; + +namespace Ryujinx.Core.OsHle.IpcServices.Lm +{ + class ILogger : IIpcService + { + private Dictionary m_Commands; + + public IReadOnlyDictionary Commands => m_Commands; + + public ILogger() + { + m_Commands = new Dictionary() + { + { 0, Log } + }; + } + + enum Flags + { + Padding, + IsHead, + IsTail + } + + enum Severity + { + Trace, + Info, + Warning, + Error, + Critical + } + + enum Field + { + Padding, + Skip, + Message, + Line, + Filename, + Function, + Module, + Thread + } + + public long Log(ServiceCtx Context) + { + long BufferPosition = Context.Request.PtrBuff[0].Position; + long BufferLen = Context.Request.PtrBuff[0].Size; + + byte[] LogBuffer = AMemoryHelper.ReadBytes(Context.Memory, BufferPosition, (int)BufferLen); + + MemoryStream LogMessage = new MemoryStream(LogBuffer); + BinaryReader bReader = new BinaryReader(LogMessage); + + //Header reading. + long Pid = bReader.ReadInt64(); + long ThreadCxt = bReader.ReadInt64(); + int Infos = bReader.ReadInt32(); + int PayloadLen = bReader.ReadInt32(); + + int iFlags = Infos & 0xFFFF; + int iSeverity = (Infos >> 17) & 0x7F; + int iVerbosity = (Infos >> 25) & 0x7F; + + //ToDo: For now we don't care about Head or Tail Log. + bool IsHeadLog = Convert.ToBoolean(iFlags & (int)Flags.IsHead); + bool IsTailLog = Convert.ToBoolean(iFlags & (int)Flags.IsTail); + + string LogString = "nn::diag::detail::LogImpl()" + Environment.NewLine + Environment.NewLine + + "Header:" + Environment.NewLine + + $" Pid: {Pid}" + Environment.NewLine + + $" ThreadContext: {ThreadCxt}" + Environment.NewLine + + $" Flags: {IsHeadLog}/{IsTailLog}" + Environment.NewLine + + $" Severity: {Enum.GetName(typeof(Severity), iSeverity)}" + Environment.NewLine + + $" Verbosity: {iVerbosity}"; + + LogString += Environment.NewLine + Environment.NewLine + "Message:" + Environment.NewLine; + + string StrMessage = "", StrLine = "", StrFilename = "", StrFunction = "", + StrModule = "", StrThread = ""; + + do + { + byte FieldType = bReader.ReadByte(); + byte FieldSize = bReader.ReadByte(); + + if ((Field)FieldType != Field.Skip || FieldSize != 0) + { + byte[] Message = bReader.ReadBytes(FieldSize); + switch ((Field)FieldType) + { + case Field.Message: + StrMessage = Encoding.UTF8.GetString(Message); + break; + + case Field.Line: + StrLine = BitConverter.ToInt32(Message, 0).ToString(); + break; + + case Field.Filename: + StrFilename = Encoding.UTF8.GetString(Message); + break; + + case Field.Function: + StrFunction = Encoding.UTF8.GetString(Message); + break; + + case Field.Module: + StrModule = Encoding.UTF8.GetString(Message); + break; + + case Field.Thread: + StrThread = Encoding.UTF8.GetString(Message); + break; + } + } + + } + while (LogMessage.Position != PayloadLen + 0x18); // 0x18 - Size of Header LogMessage. + + LogString += StrModule + " > " + StrThread + ": " + StrFilename + "@" + StrFunction + "(" + StrLine + ") '" + StrMessage + "'" + Environment.NewLine; + + switch((Severity)iSeverity) + { + case Severity.Trace: Logging.Trace(LogString); break; + case Severity.Info: Logging.Info(LogString); break; + case Severity.Warning: Logging.Warn(LogString); break; + case Severity.Error: Logging.Error(LogString); break; + case Severity.Critical: Logging.Fatal(LogString); break; + } + + return 0; + } + } +} + \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/Lm/ServiceLm.cs b/Ryujinx.Core/OsHle/Services/Lm/ServiceLm.cs new file mode 100644 index 00000000..ca3fe35e --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/Lm/ServiceLm.cs @@ -0,0 +1,31 @@ +using Ryujinx.Core.OsHle.Ipc; +using System.Collections.Generic; + +using static Ryujinx.Core.OsHle.IpcServices.ObjHelper; + +namespace Ryujinx.Core.OsHle.IpcServices.Lm +{ + class ServiceLm : IIpcService + { + private Dictionary m_Commands; + + public IReadOnlyDictionary Commands => m_Commands; + + public ServiceLm() + { + m_Commands = new Dictionary() + { + { 0, Initialize } + }; + } + + public long Initialize(ServiceCtx Context) + { + Context.Session.Initialize(); + + MakeObject(Context, new ILogger()); + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/Ns/ServiceNs.cs b/Ryujinx.Core/OsHle/Services/Ns/ServiceNs.cs new file mode 100644 index 00000000..720baa6e --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/Ns/ServiceNs.cs @@ -0,0 +1,20 @@ +using Ryujinx.Core.OsHle.Ipc; +using System.Collections.Generic; + +namespace Ryujinx.Core.OsHle.IpcServices.Ns +{ + class ServiceNs : IIpcService + { + private Dictionary m_Commands; + + public IReadOnlyDictionary Commands => m_Commands; + + public ServiceNs() + { + m_Commands = new Dictionary() + { + //{ 1, Function } + }; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/Nv/ServiceNvDrv.cs b/Ryujinx.Core/OsHle/Services/Nv/ServiceNvDrv.cs new file mode 100644 index 00000000..1de0ab70 --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/Nv/ServiceNvDrv.cs @@ -0,0 +1,627 @@ +using ChocolArm64.Memory; +using Ryujinx.Core.OsHle.Handles; +using Ryujinx.Core.OsHle.Ipc; +using Ryujinx.Core.OsHle.Utilities; +using Ryujinx.Graphics.Gpu; +using System; +using System.Collections.Generic; + +namespace Ryujinx.Core.OsHle.IpcServices.NvServices +{ + class ServiceNvDrv : IIpcService + { + private delegate long ServiceProcessIoctl(ServiceCtx Context); + + private static Dictionary<(string, int), ServiceProcessIoctl> IoctlCmds = + new Dictionary<(string, int), ServiceProcessIoctl>() + { + { ("/dev/nvhost-as-gpu", 0x4101), NvGpuAsIoctlBindChannel }, + { ("/dev/nvhost-as-gpu", 0x4102), NvGpuAsIoctlAllocSpace }, + { ("/dev/nvhost-as-gpu", 0x4106), NvGpuAsIoctlMapBufferEx }, + { ("/dev/nvhost-as-gpu", 0x4108), NvGpuAsIoctlGetVaRegions }, + { ("/dev/nvhost-as-gpu", 0x4109), NvGpuAsIoctlInitializeEx }, + { ("/dev/nvhost-ctrl", 0x001b), NvHostIoctlCtrlGetConfig }, + { ("/dev/nvhost-ctrl", 0x001d), NvHostIoctlCtrlEventWait }, + { ("/dev/nvhost-ctrl-gpu", 0x4701), NvGpuIoctlZcullGetCtxSize }, + { ("/dev/nvhost-ctrl-gpu", 0x4702), NvGpuIoctlZcullGetInfo }, + { ("/dev/nvhost-ctrl-gpu", 0x4705), NvGpuIoctlGetCharacteristics }, + { ("/dev/nvhost-ctrl-gpu", 0x4706), NvGpuIoctlGetTpcMasks }, + { ("/dev/nvhost-ctrl-gpu", 0x4714), NvGpuIoctlZbcGetActiveSlotMask }, + { ("/dev/nvhost-gpu", 0x4714), NvMapIoctlChannelSetUserData }, + { ("/dev/nvhost-gpu", 0x4801), NvMapIoctlChannelSetNvMap }, + { ("/dev/nvhost-gpu", 0x4808), NvMapIoctlChannelSubmitGpFifo }, + { ("/dev/nvhost-gpu", 0x4809), NvMapIoctlChannelAllocObjCtx }, + { ("/dev/nvhost-gpu", 0x480b), NvMapIoctlChannelZcullBind }, + { ("/dev/nvhost-gpu", 0x480c), NvMapIoctlChannelSetErrorNotifier }, + { ("/dev/nvhost-gpu", 0x480d), NvMapIoctlChannelSetPriority }, + { ("/dev/nvhost-gpu", 0x481a), NvMapIoctlChannelAllocGpFifoEx2 }, + { ("/dev/nvmap", 0x0101), NvMapIocCreate }, + { ("/dev/nvmap", 0x0103), NvMapIocFromId }, + { ("/dev/nvmap", 0x0104), NvMapIocAlloc }, + { ("/dev/nvmap", 0x0109), NvMapIocParam }, + { ("/dev/nvmap", 0x010e), NvMapIocGetId }, + }; + + private Dictionary m_Commands; + + public IReadOnlyDictionary Commands => m_Commands; + + public ServiceNvDrv() + { + m_Commands = new Dictionary() + { + { 0, Open }, + { 1, Ioctl }, + { 2, Close }, + { 3, Initialize }, + { 4, QueryEvent }, + { 8, SetClientPid }, + }; + } + + public static long Open(ServiceCtx Context) + { + long NamePtr = Context.Request.SendBuff[0].Position; + + string Name = AMemoryHelper.ReadAsciiString(Context.Memory, NamePtr); + + int Fd = Context.Ns.Os.Fds.GenerateId(new FileDesc(Name)); + + Context.ResponseData.Write(Fd); + Context.ResponseData.Write(0); + + return 0; + } + + public static long Ioctl(ServiceCtx Context) + { + int Fd = Context.RequestData.ReadInt32(); + int Cmd = Context.RequestData.ReadInt32() & 0xffff; + + FileDesc FdData = Context.Ns.Os.Fds.GetData(Fd); + + long Position = Context.Request.PtrBuff[0].Position; + + Context.ResponseData.Write(0); + + if (IoctlCmds.TryGetValue((FdData.Name, Cmd), out ServiceProcessIoctl ProcReq)) + { + return ProcReq(Context); + } + else + { + throw new NotImplementedException($"{FdData.Name} {Cmd:x4}"); + } + } + + public static long Close(ServiceCtx Context) + { + int Fd = Context.RequestData.ReadInt32(); + + Context.Ns.Os.Fds.Delete(Fd); + + Context.ResponseData.Write(0); + + return 0; + } + + public static long Initialize(ServiceCtx Context) + { + long TransferMemSize = Context.RequestData.ReadInt64(); + int TransferMemHandle = Context.Request.HandleDesc.ToCopy[0]; + + Context.ResponseData.Write(0); + + return 0; + } + + public static long QueryEvent(ServiceCtx Context) + { + int Fd = Context.RequestData.ReadInt32(); + int EventId = Context.RequestData.ReadInt32(); + + Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(0xcafe); + + Context.ResponseData.Write(0); + + return 0; + } + + public static long SetClientPid(ServiceCtx Context) + { + long Pid = Context.RequestData.ReadInt64(); + + Context.ResponseData.Write(0); + + return 0; + } + + private static long NvGpuAsIoctlBindChannel(ServiceCtx Context) + { + long Position = Context.Request.PtrBuff[0].Position; + + int Fd = Context.Memory.ReadInt32(Position); + + return 0; + } + + private static long NvGpuAsIoctlAllocSpace(ServiceCtx Context) + { + long Position = Context.Request.PtrBuff[0].Position; + + MemReader Reader = new MemReader(Context.Memory, Position); + + int Pages = Reader.ReadInt32(); + int PageSize = Reader.ReadInt32(); + int Flags = Reader.ReadInt32(); + int Padding = Reader.ReadInt32(); + long Align = Reader.ReadInt64(); + + if ((Flags & 1) != 0) + { + Align = Context.Ns.Gpu.ReserveMemory(Align, (long)Pages * PageSize, 1); + } + else + { + Align = Context.Ns.Gpu.ReserveMemory((long)Pages * PageSize, Align); + } + + Context.Memory.WriteInt64(Position + 0x10, Align); + + return 0; + } + + private static long NvGpuAsIoctlMapBufferEx(ServiceCtx Context) + { + long Position = Context.Request.PtrBuff[0].Position; + + MemReader Reader = new MemReader(Context.Memory, Position); + + int Flags = Reader.ReadInt32(); + int Kind = Reader.ReadInt32(); + int Handle = Reader.ReadInt32(); + int PageSize = Reader.ReadInt32(); + long BuffAddr = Reader.ReadInt64(); + long MapSize = Reader.ReadInt64(); + long Offset = Reader.ReadInt64(); + + HNvMap NvMap = Context.Ns.Os.Handles.GetData(Handle); + + if (NvMap != null) + { + if ((Flags & 1) != 0) + { + Offset = Context.Ns.Gpu.MapMemory(NvMap.Address, Offset, NvMap.Size); + } + else + { + Offset = Context.Ns.Gpu.MapMemory(NvMap.Address, NvMap.Size); + } + } + + Context.Memory.WriteInt64(Position + 0x20, Offset); + + return 0; + } + + private static long NvGpuAsIoctlGetVaRegions(ServiceCtx Context) + { + long Position = Context.Request.PtrBuff[0].Position; + + MemReader Reader = new MemReader(Context.Memory, Position); + MemWriter Writer = new MemWriter(Context.Memory, Position); + + long Unused = Reader.ReadInt64(); + int BuffSize = Reader.ReadInt32(); + int Padding = Reader.ReadInt32(); + + BuffSize = 0x30; + + Writer.WriteInt64(Unused); + Writer.WriteInt32(BuffSize); + Writer.WriteInt32(Padding); + + Writer.WriteInt64(0); + Writer.WriteInt32(0); + Writer.WriteInt32(0); + Writer.WriteInt64(0); + + Writer.WriteInt64(0); + Writer.WriteInt32(0); + Writer.WriteInt32(0); + Writer.WriteInt64(0); + + return 0; + } + + private static long NvGpuAsIoctlInitializeEx(ServiceCtx Context) + { + long Position = Context.Request.PtrBuff[0].Position; + + MemReader Reader = new MemReader(Context.Memory, Position); + + int BigPageSize = Reader.ReadInt32(); + int AsFd = Reader.ReadInt32(); + int Flags = Reader.ReadInt32(); + int Reserved = Reader.ReadInt32(); + long Unknown10 = Reader.ReadInt64(); + long Unknown18 = Reader.ReadInt64(); + long Unknown20 = Reader.ReadInt64(); + + return 0; + } + + private static long NvHostIoctlCtrlGetConfig(ServiceCtx Context) + { + long Position = Context.Request.PtrBuff[0].Position; + + MemReader Reader = new MemReader(Context.Memory, Position); + MemWriter Writer = new MemWriter(Context.Memory, Position + 0x82); + + for (int Index = 0; Index < 0x101; Index++) + { + Writer.WriteByte(0); + } + + return 0; + } + + private static long NvHostIoctlCtrlEventWait(ServiceCtx Context) + { + long Position = Context.Request.PtrBuff[0].Position; + + MemReader Reader = new MemReader(Context.Memory, Position); + + int SyncPtId = Reader.ReadInt32(); + int Threshold = Reader.ReadInt32(); + int Timeout = Reader.ReadInt32(); + int Value = Reader.ReadInt32(); + + Context.Memory.WriteInt32(Position + 0xc, 0xcafe); + + return 0; + } + + private static long NvGpuIoctlZcullGetCtxSize(ServiceCtx Context) + { + long Position = Context.Request.PtrBuff[0].Position; + + Context.Memory.WriteInt32(Position, 1); + + return 0; + } + + private static long NvGpuIoctlZcullGetInfo(ServiceCtx Context) + { + long Position = Context.Request.PtrBuff[0].Position; + + MemWriter Writer = new MemWriter(Context.Memory, Position); + + Writer.WriteInt32(0); + Writer.WriteInt32(0); + Writer.WriteInt32(0); + Writer.WriteInt32(0); + Writer.WriteInt32(0); + Writer.WriteInt32(0); + Writer.WriteInt32(0); + Writer.WriteInt32(0); + Writer.WriteInt32(0); + Writer.WriteInt32(0); + + return 0; + } + + private static long NvGpuIoctlGetCharacteristics(ServiceCtx Context) + { + long Position = Context.Request.PtrBuff[0].Position; + + MemReader Reader = new MemReader(Context.Memory, Position); + MemWriter Writer = new MemWriter(Context.Memory, Position); + + //Note: We should just ignore the BuffAddr, because official code + //does __memcpy_device from Position + 0x10 to BuffAddr. + long BuffSize = Reader.ReadInt64(); + long BuffAddr = Reader.ReadInt64(); + + BuffSize = 0xa0; + + Writer.WriteInt64(BuffSize); + Writer.WriteInt64(BuffAddr); + Writer.WriteInt32(0x120); //NVGPU_GPU_ARCH_GM200 + Writer.WriteInt32(0xb); //NVGPU_GPU_IMPL_GM20B + Writer.WriteInt32(0xa1); + Writer.WriteInt32(1); + Writer.WriteInt64(0x40000); + Writer.WriteInt64(0); + Writer.WriteInt32(2); + Writer.WriteInt32(0x20); //NVGPU_GPU_BUS_TYPE_AXI + Writer.WriteInt32(0x20000); + Writer.WriteInt32(0x20000); + Writer.WriteInt32(0x1b); + Writer.WriteInt32(0x30000); + Writer.WriteInt32(1); + Writer.WriteInt32(0x503); + Writer.WriteInt32(0x503); + Writer.WriteInt32(0x80); + Writer.WriteInt32(0x28); + Writer.WriteInt32(0); + Writer.WriteInt64(0x55); + Writer.WriteInt32(0x902d); //FERMI_TWOD_A + Writer.WriteInt32(0xb197); //MAXWELL_B + Writer.WriteInt32(0xb1c0); //MAXWELL_COMPUTE_B + Writer.WriteInt32(0xb06f); //MAXWELL_CHANNEL_GPFIFO_A + Writer.WriteInt32(0xa140); //KEPLER_INLINE_TO_MEMORY_B + Writer.WriteInt32(0xb0b5); //MAXWELL_DMA_COPY_A + Writer.WriteInt32(1); + Writer.WriteInt32(0); + Writer.WriteInt32(2); + Writer.WriteInt32(1); + Writer.WriteInt32(0); + Writer.WriteInt32(1); + Writer.WriteInt32(0x21d70); + Writer.WriteInt32(0); + Writer.WriteByte((byte)'g'); + Writer.WriteByte((byte)'m'); + Writer.WriteByte((byte)'2'); + Writer.WriteByte((byte)'0'); + Writer.WriteByte((byte)'b'); + Writer.WriteByte((byte)'\0'); + Writer.WriteByte((byte)'\0'); + Writer.WriteByte((byte)'\0'); + Writer.WriteInt64(0); + + return 0; + } + + private static long NvGpuIoctlGetTpcMasks(ServiceCtx Context) + { + long Position = Context.Request.PtrBuff[0].Position; + + MemReader Reader = new MemReader(Context.Memory, Position); + + int MaskBuffSize = Reader.ReadInt32(); + int Reserved = Reader.ReadInt32(); + long MaskBuffAddr = Reader.ReadInt64(); + long Unknown = Reader.ReadInt64(); + + return 0; + } + + private static long NvGpuIoctlZbcGetActiveSlotMask(ServiceCtx Context) + { + long Position = Context.Request.PtrBuff[0].Position; + + Context.Memory.WriteInt32(Position + 0, 7); + Context.Memory.WriteInt32(Position + 4, 1); + + return 0; + } + + private static long NvMapIoctlChannelSetUserData(ServiceCtx Context) + { + long Position = Context.Request.PtrBuff[0].Position; + + return 0; + } + + private static long NvMapIoctlChannelSetNvMap(ServiceCtx Context) + { + long Position = Context.Request.PtrBuff[0].Position; + + int Fd = Context.Memory.ReadInt32(Position); + + return 0; + } + + private static long NvMapIoctlChannelSubmitGpFifo(ServiceCtx Context) + { + long Position = Context.Request.PtrBuff[0].Position; + + MemReader Reader = new MemReader(Context.Memory, Position); + MemWriter Writer = new MemWriter(Context.Memory, Position + 0x10); + + long GpFifo = Reader.ReadInt64(); + int Count = Reader.ReadInt32(); + int Flags = Reader.ReadInt32(); + int FenceId = Reader.ReadInt32(); + int FenceVal = Reader.ReadInt32(); + + for (int Index = 0; Index < Count; Index++) + { + long GpFifoHdr = Reader.ReadInt64(); + + long GpuAddr = GpFifoHdr & 0xffffffffff; + + int Size = (int)(GpFifoHdr >> 40) & 0x7ffffc; + + long CpuAddr = Context.Ns.Gpu.GetCpuAddr(GpuAddr); + + if (CpuAddr != -1) + { + byte[] Data = AMemoryHelper.ReadBytes(Context.Memory, CpuAddr, Size); + + NsGpuPBEntry[] PushBuffer = NsGpuPBEntry.DecodePushBuffer(Data); + + Context.Ns.Gpu.ProcessPushBuffer(PushBuffer, Context.Memory); + } + } + + Writer.WriteInt32(0); + Writer.WriteInt32(0); + + return 0; + } + + private static long NvMapIoctlChannelAllocObjCtx(ServiceCtx Context) + { + long Position = Context.Request.PtrBuff[0].Position; + + int ClassNum = Context.Memory.ReadInt32(Position + 0); + int Flags = Context.Memory.ReadInt32(Position + 4); + + Context.Memory.WriteInt32(Position + 8, 0); + + return 0; + } + + private static long NvMapIoctlChannelZcullBind(ServiceCtx Context) + { + long Position = Context.Request.PtrBuff[0].Position; + + MemReader Reader = new MemReader(Context.Memory, Position); + + long GpuVa = Reader.ReadInt64(); + int Mode = Reader.ReadInt32(); + int Padding = Reader.ReadInt32(); + + return 0; + } + + private static long NvMapIoctlChannelSetErrorNotifier(ServiceCtx Context) + { + long Position = Context.Request.PtrBuff[0].Position; + + MemReader Reader = new MemReader(Context.Memory, Position); + + long Offset = Reader.ReadInt64(); + long Size = Reader.ReadInt64(); + int Mem = Reader.ReadInt32(); + int Padding = Reader.ReadInt32(); + + return 0; + } + + private static long NvMapIoctlChannelSetPriority(ServiceCtx Context) + { + long Position = Context.Request.PtrBuff[0].Position; + + int Priority = Context.Memory.ReadInt32(Position); + + return 0; + } + + private static long NvMapIoctlChannelAllocGpFifoEx2(ServiceCtx Context) + { + long Position = Context.Request.PtrBuff[0].Position; + + MemReader Reader = new MemReader(Context.Memory, Position); + MemWriter Writer = new MemWriter(Context.Memory, Position + 0xc); + + int Count = Reader.ReadInt32(); + int Flags = Reader.ReadInt32(); + int Unknown8 = Reader.ReadInt32(); + long Fence = Reader.ReadInt64(); + int Unknown14 = Reader.ReadInt32(); + int Unknown18 = Reader.ReadInt32(); + + Writer.WriteInt32(0); + Writer.WriteInt32(0); + + return 0; + } + + private static long NvMapIocCreate(ServiceCtx Context) + { + long Position = Context.Request.GetSendBuffPtr(); + + int Size = Context.Memory.ReadInt32(Position); + + int Id = Context.Ns.Os.NvMapIds.GenerateId(); + + int Handle = Context.Ns.Os.Handles.GenerateId(new HNvMap(Id, Size)); + + Context.Memory.WriteInt32(Position + 4, Handle); + + return 0; + } + + private static long NvMapIocFromId(ServiceCtx Context) + { + long Position = Context.Request.GetSendBuffPtr(); + + int Id = Context.Memory.ReadInt32(Position); + + int Handle = -1; + + foreach (KeyValuePair KV in Context.Ns.Os.Handles) + { + if (KV.Value is HNvMap NvMap && NvMap.Id == Id) + { + Handle = KV.Key; + + break; + } + } + + Context.Memory.WriteInt32(Position + 4, Handle); + + return 0; + } + + private static long NvMapIocAlloc(ServiceCtx Context) + { + long Position = Context.Request.GetSendBuffPtr(); + + MemReader Reader = new MemReader(Context.Memory, Position); + + int Handle = Reader.ReadInt32(); + int HeapMask = Reader.ReadInt32(); + int Flags = Reader.ReadInt32(); + int Align = Reader.ReadInt32(); + byte Kind = (byte)Reader.ReadInt64(); + long Addr = Reader.ReadInt64(); + + HNvMap NvMap = Context.Ns.Os.Handles.GetData(Handle); + + if (NvMap != null) + { + NvMap.Address = Addr; + NvMap.Align = Align; + NvMap.Kind = Kind; + } + + Logging.Debug($"NvMapIocAlloc at {NvMap.Address:x16}"); + + return 0; + } + + private static long NvMapIocParam(ServiceCtx Context) + { + long Position = Context.Request.GetSendBuffPtr(); + + MemReader Reader = new MemReader(Context.Memory, Position); + + int Handle = Reader.ReadInt32(); + int Param = Reader.ReadInt32(); + + HNvMap NvMap = Context.Ns.Os.Handles.GetData(Handle); + + int Response = 0; + + switch (Param) + { + case 1: Response = NvMap.Size; break; + case 2: Response = NvMap.Align; break; + case 4: Response = 0x40000000; break; + case 5: Response = NvMap.Kind; break; + } + + Context.Memory.WriteInt32(Position + 8, Response); + + return 0; + } + + private static long NvMapIocGetId(ServiceCtx Context) + { + long Position = Context.Request.GetSendBuffPtr(); + + int Handle = Context.Memory.ReadInt32(Position + 4); + + HNvMap NvMap = Context.Ns.Os.Handles.GetData(Handle); + + Context.Memory.WriteInt32(Position, NvMap.Id); + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/ObjHelper.cs b/Ryujinx.Core/OsHle/Services/ObjHelper.cs new file mode 100644 index 00000000..ff71838a --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/ObjHelper.cs @@ -0,0 +1,24 @@ +using Ryujinx.Core.OsHle.Handles; +using Ryujinx.Core.OsHle.Ipc; + +namespace Ryujinx.Core.OsHle.IpcServices +{ + static class ObjHelper + { + public static void MakeObject(ServiceCtx Context, object Obj) + { + if (Context.Session is HDomain Dom) + { + Context.Response.ResponseObjIds.Add(Dom.GenerateObjectId(Obj)); + } + else + { + HSessionObj HndData = new HSessionObj(Context.Session, Obj); + + int VHandle = Context.Ns.Os.Handles.GenerateId(HndData); + + Context.Response.HandleDesc = IpcHandleDesc.MakeMove(VHandle); + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/Pctl/IParentalControlService.cs b/Ryujinx.Core/OsHle/Services/Pctl/IParentalControlService.cs new file mode 100644 index 00000000..4eb92d31 --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/Pctl/IParentalControlService.cs @@ -0,0 +1,20 @@ +using Ryujinx.Core.OsHle.Ipc; +using System.Collections.Generic; + +namespace Ryujinx.Core.OsHle.IpcServices.Pctl +{ + class IParentalControlService : IIpcService + { + private Dictionary m_Commands; + + public IReadOnlyDictionary Commands => m_Commands; + + public IParentalControlService() + { + m_Commands = new Dictionary() + { + //... + }; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/Pctl/ServicePctl.cs b/Ryujinx.Core/OsHle/Services/Pctl/ServicePctl.cs new file mode 100644 index 00000000..2d5e22a4 --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/Pctl/ServicePctl.cs @@ -0,0 +1,29 @@ +using Ryujinx.Core.OsHle.Ipc; +using System.Collections.Generic; + +using static Ryujinx.Core.OsHle.IpcServices.ObjHelper; + +namespace Ryujinx.Core.OsHle.IpcServices.Pctl +{ + class ServicePctl : IIpcService + { + private Dictionary m_Commands; + + public IReadOnlyDictionary Commands => m_Commands; + + public ServicePctl() + { + m_Commands = new Dictionary() + { + { 0, CreateService } + }; + } + + public static long CreateService(ServiceCtx Context) + { + MakeObject(Context, new IParentalControlService()); + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/Pl/ServicePl.cs b/Ryujinx.Core/OsHle/Services/Pl/ServicePl.cs new file mode 100644 index 00000000..abc34ed2 --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/Pl/ServicePl.cs @@ -0,0 +1,51 @@ +using Ryujinx.Core.OsHle.Ipc; +using System.Collections.Generic; + +namespace Ryujinx.Core.OsHle.IpcServices.Pl +{ + class ServicePl : IIpcService + { + private Dictionary m_Commands; + + public IReadOnlyDictionary Commands => m_Commands; + + public ServicePl() + { + m_Commands = new Dictionary() + { + { 1, GetLoadState }, + { 2, GetFontSize }, + { 3, GetSharedMemoryAddressOffset }, + { 4, GetSharedMemoryNativeHandle } + }; + } + + public static long GetLoadState(ServiceCtx Context) + { + Context.ResponseData.Write(1); //Loaded + + return 0; + } + + public static long GetFontSize(ServiceCtx Context) + { + Context.ResponseData.Write(Horizon.FontSize); + + return 0; + } + + public static long GetSharedMemoryAddressOffset(ServiceCtx Context) + { + Context.ResponseData.Write(0); + + return 0; + } + + public static long GetSharedMemoryNativeHandle(ServiceCtx Context) + { + Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Context.Ns.Os.FontHandle); + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/ServiceFactory.cs b/Ryujinx.Core/OsHle/Services/ServiceFactory.cs new file mode 100644 index 00000000..54fa38ab --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/ServiceFactory.cs @@ -0,0 +1,54 @@ +using Ryujinx.Core.OsHle.IpcServices.Acc; +using Ryujinx.Core.OsHle.IpcServices.Am; +using Ryujinx.Core.OsHle.IpcServices.Apm; +using Ryujinx.Core.OsHle.IpcServices.Aud; +using Ryujinx.Core.OsHle.IpcServices.Friend; +using Ryujinx.Core.OsHle.IpcServices.FspSrv; +using Ryujinx.Core.OsHle.IpcServices.Hid; +using Ryujinx.Core.OsHle.IpcServices.Lm; +using Ryujinx.Core.OsHle.IpcServices.Ns; +using Ryujinx.Core.OsHle.IpcServices.NvServices; +using Ryujinx.Core.OsHle.IpcServices.Pctl; +using Ryujinx.Core.OsHle.IpcServices.Pl; +using Ryujinx.Core.OsHle.IpcServices.Set; +using Ryujinx.Core.OsHle.IpcServices.Sm; +using Ryujinx.Core.OsHle.IpcServices.Time; +using Ryujinx.Core.OsHle.IpcServices.Vi; +using System; + +namespace Ryujinx.Core.OsHle.IpcServices +{ + static class ServiceFactory + { + public static IIpcService MakeService(string Name) + { + switch (Name) + { + case "acc:u0": return new ServiceAcc(); + case "aoc:u": return new ServiceNs(); + case "apm": return new ServiceApm(); + case "apm:p": return new ServiceApm(); + case "appletOE": return new ServiceAppletOE(); + case "audout:u": return new ServiceAudOut(); + case "audren:u": return new ServiceAudRen(); + case "friend:a": return new ServiceFriend(); + case "fsp-srv": return new ServiceFspSrv(); + case "hid": return new ServiceHid(); + case "lm": return new ServiceLm(); + case "nvdrv": return new ServiceNvDrv(); + case "nvdrv:a": return new ServiceNvDrv(); + case "pctl:a": return new ServicePctl(); + case "pl:u": return new ServicePl(); + case "set": return new ServiceSet(); + case "sm:": return new ServiceSm(); + case "time:s": return new ServiceTime(); + case "time:u": return new ServiceTime(); + case "vi:m": return new ServiceVi(); + case "vi:s": return new ServiceVi(); + case "vi:u": return new ServiceVi(); + } + + throw new NotImplementedException(Name); + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/Set/ServiceSet.cs b/Ryujinx.Core/OsHle/Services/Set/ServiceSet.cs new file mode 100644 index 00000000..05e409b0 --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/Set/ServiceSet.cs @@ -0,0 +1,46 @@ +using ChocolArm64.Memory; +using Ryujinx.Core.OsHle.Ipc; +using System.Collections.Generic; + +namespace Ryujinx.Core.OsHle.IpcServices.Set +{ + class ServiceSet : IIpcService + { + private Dictionary m_Commands; + + public IReadOnlyDictionary Commands => m_Commands; + + public ServiceSet() + { + m_Commands = new Dictionary() + { + { 1, GetAvailableLanguageCodes } + }; + } + + private const int LangCodesCount = 13; + + public static long GetAvailableLanguageCodes(ServiceCtx Context) + { + int PtrBuffSize = Context.RequestData.ReadInt32(); + + if (Context.Request.RecvListBuff.Count > 0) + { + long Position = Context.Request.RecvListBuff[0].Position; + short Size = Context.Request.RecvListBuff[0].Size; + + //This should return an array of ints with values matching the LanguageCode enum. + byte[] Data = new byte[Size]; + + Data[0] = 0; + Data[1] = 1; + + AMemoryHelper.WriteBytes(Context.Memory, Position, Data); + } + + Context.ResponseData.Write(LangCodesCount); + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/Sm/ServiceSm.cs b/Ryujinx.Core/OsHle/Services/Sm/ServiceSm.cs new file mode 100644 index 00000000..a5f1b329 --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/Sm/ServiceSm.cs @@ -0,0 +1,67 @@ +using Ryujinx.Core.OsHle.Handles; +using Ryujinx.Core.OsHle.Ipc; +using System.Collections.Generic; + +namespace Ryujinx.Core.OsHle.IpcServices.Sm +{ + class ServiceSm : IIpcService + { + private Dictionary m_Commands; + + public IReadOnlyDictionary Commands => m_Commands; + + public ServiceSm() + { + m_Commands = new Dictionary() + { + { 0, Initialize }, + { 1, GetService } + }; + } + + private const int SmNotInitialized = 0x415; + + public long Initialize(ServiceCtx Context) + { + Context.Session.Initialize(); + + return 0; + } + + public long GetService(ServiceCtx Context) + { + //Only for kernel version > 3.0.0. + if (!Context.Session.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; + } + + HSession Session = new HSession(ServiceFactory.MakeService(Name)); + + int Handle = Context.Ns.Os.Handles.GenerateId(Session); + + Context.Response.HandleDesc = IpcHandleDesc.MakeMove(Handle); + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/Time/ISteadyClock.cs b/Ryujinx.Core/OsHle/Services/Time/ISteadyClock.cs new file mode 100644 index 00000000..d20e4378 --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/Time/ISteadyClock.cs @@ -0,0 +1,20 @@ +using Ryujinx.Core.OsHle.Ipc; +using System.Collections.Generic; + +namespace Ryujinx.Core.OsHle.IpcServices.Time +{ + class ISteadyClock : IIpcService + { + private Dictionary m_Commands; + + public IReadOnlyDictionary Commands => m_Commands; + + public ISteadyClock() + { + m_Commands = new Dictionary() + { + //... + }; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/Time/ISystemClock.cs b/Ryujinx.Core/OsHle/Services/Time/ISystemClock.cs new file mode 100644 index 00000000..4d4493da --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/Time/ISystemClock.cs @@ -0,0 +1,42 @@ +using Ryujinx.Core.OsHle.Ipc; +using System; +using System.Collections.Generic; + +namespace Ryujinx.Core.OsHle.IpcServices.Time +{ + class ISystemClock : IIpcService + { + private Dictionary m_Commands; + + public IReadOnlyDictionary Commands => m_Commands; + + private static DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); + + private SystemClockType ClockType; + + public ISystemClock(SystemClockType ClockType) + { + m_Commands = new Dictionary() + { + { 0, GetCurrentTime } + }; + + this.ClockType = ClockType; + } + + public long GetCurrentTime(ServiceCtx Context) + { + DateTime CurrentTime = DateTime.Now; + + if (ClockType == SystemClockType.User || + ClockType == SystemClockType.Network) + { + CurrentTime = CurrentTime.ToUniversalTime(); + } + + Context.ResponseData.Write((long)(DateTime.Now - Epoch).TotalSeconds); + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/Time/ITimeZoneService.cs b/Ryujinx.Core/OsHle/Services/Time/ITimeZoneService.cs new file mode 100644 index 00000000..d220824c --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/Time/ITimeZoneService.cs @@ -0,0 +1,69 @@ +using Ryujinx.Core.OsHle.Ipc; +using System; +using System.Collections.Generic; + +namespace Ryujinx.Core.OsHle.IpcServices.Time +{ + class ITimeZoneService : IIpcService + { + private Dictionary m_Commands; + + public IReadOnlyDictionary Commands => m_Commands; + + private static DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Local); + + public ITimeZoneService() + { + m_Commands = new Dictionary() + { + { 101, ToCalendarTimeWithMyRule } + }; + } + + //(nn::time::PosixTime)-> (nn::time::CalendarTime, nn::time::sf::CalendarAdditionalInfo) + public long ToCalendarTimeWithMyRule(ServiceCtx Context) + { + long PosixTime = Context.RequestData.ReadInt64(); + + Epoch = Epoch.AddSeconds(PosixTime).ToLocalTime(); + + /* + struct CalendarTime { + u16_le year; + u8 month; // Starts at 1 + u8 day; // Starts at 1 + u8 hour; + u8 minute; + u8 second; + INSERT_PADDING_BYTES(1); + }; + */ + Context.ResponseData.Write((short)Epoch.Year); + Context.ResponseData.Write((byte)Epoch.Month); + Context.ResponseData.Write((byte)Epoch.Day); + Context.ResponseData.Write((byte)Epoch.Hour); + Context.ResponseData.Write((byte)Epoch.Minute); + Context.ResponseData.Write((byte)Epoch.Second); + Context.ResponseData.Write((byte)0); + + /* Thanks to TuxSH + struct CalendarAdditionalInfo { + u32 tm_wday; //day of week [0,6] (Sunday = 0) + s32 tm_yday; //day of year [0,365] + struct timezone { + char[8] tz_name; + bool isDaylightSavingTime; + s32 utcOffsetSeconds; + }; + }; + */ + Context.ResponseData.Write((int)Epoch.DayOfWeek); + Context.ResponseData.Write(Epoch.DayOfYear); + Context.ResponseData.Write(new byte[8]); + Context.ResponseData.Write(Convert.ToByte(Epoch.IsDaylightSavingTime())); + Context.ResponseData.Write(0); + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/Time/ServiceTime.cs b/Ryujinx.Core/OsHle/Services/Time/ServiceTime.cs new file mode 100644 index 00000000..43f28bb8 --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/Time/ServiceTime.cs @@ -0,0 +1,62 @@ +using Ryujinx.Core.OsHle.Ipc; +using System.Collections.Generic; + +using static Ryujinx.Core.OsHle.IpcServices.ObjHelper; + +namespace Ryujinx.Core.OsHle.IpcServices.Time +{ + class ServiceTime : IIpcService + { + private Dictionary m_Commands; + + public IReadOnlyDictionary Commands => m_Commands; + + public ServiceTime() + { + m_Commands = new Dictionary() + { + { 0, GetStandardUserSystemClock }, + { 1, GetStandardNetworkSystemClock }, + { 2, GetStandardSteadyClock }, + { 3, GetTimeZoneService }, + { 4, GetStandardLocalSystemClock } + }; + } + + 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; + } + + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/Time/SystemClockType.cs b/Ryujinx.Core/OsHle/Services/Time/SystemClockType.cs new file mode 100644 index 00000000..2314942a --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/Time/SystemClockType.cs @@ -0,0 +1,9 @@ +namespace Ryujinx.Core.OsHle.IpcServices.Time +{ + enum SystemClockType + { + User, + Network, + Local + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/Vi/GbpBuffer.cs b/Ryujinx.Core/OsHle/Services/Vi/GbpBuffer.cs new file mode 100644 index 00000000..5fe585d0 --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/Vi/GbpBuffer.cs @@ -0,0 +1,60 @@ +using System.IO; + +namespace Ryujinx.Core.OsHle.IpcServices.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.Core/OsHle/Services/Vi/IApplicationDisplayService.cs b/Ryujinx.Core/OsHle/Services/Vi/IApplicationDisplayService.cs new file mode 100644 index 00000000..a899cdd5 --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/Vi/IApplicationDisplayService.cs @@ -0,0 +1,176 @@ +using ChocolArm64.Memory; +using Ryujinx.Core.OsHle.Handles; +using Ryujinx.Core.OsHle.Ipc; +using System.Collections.Generic; +using System.IO; + +using static Ryujinx.Core.OsHle.IpcServices.Android.Parcel; +using static Ryujinx.Core.OsHle.IpcServices.ObjHelper; + +namespace Ryujinx.Core.OsHle.IpcServices.Vi +{ + class IApplicationDisplayService : IIpcService + { + private Dictionary m_Commands; + + public IReadOnlyDictionary Commands => m_Commands; + + public IApplicationDisplayService() + { + m_Commands = new Dictionary() + { + { 100, GetRelayService }, + { 101, GetSystemDisplayService }, + { 102, GetManagerDisplayService }, + { 103, GetIndirectDisplayTransactionService }, + { 1010, OpenDisplay }, + { 2020, OpenLayer }, + { 2030, CreateStrayLayer }, + { 2101, SetLayerScalingMode }, + { 5202, GetDisplayVSyncEvent } + }; + } + + public long GetRelayService(ServiceCtx Context) + { + MakeObject(Context, new IHOSBinderDriver()); + + 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()); + + return 0; + } + + public long OpenDisplay(ServiceCtx Context) + { + string Name = GetDisplayName(Context); + + long DisplayId = Context.Ns.Os.Displays.GenerateId(new Display(Name)); + + Context.ResponseData.Write(DisplayId); + + 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); + + AMemoryHelper.WriteBytes(Context.Memory, ParcelPtr, Parcel); + + Context.ResponseData.Write((long)Parcel.Length); + + 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 = Context.Ns.Os.Displays.GetData((int)DisplayId); + + byte[] Parcel = MakeIGraphicsBufferProducer(ParcelPtr); + + AMemoryHelper.WriteBytes(Context.Memory, ParcelPtr, Parcel); + + Context.ResponseData.Write(0L); + Context.ResponseData.Write((long)Parcel.Length); + + 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.Ns.Os.Handles.GenerateId(new HEvent()); + + 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.Core/OsHle/Services/Vi/IHOSBinderDriver.cs b/Ryujinx.Core/OsHle/Services/Vi/IHOSBinderDriver.cs new file mode 100644 index 00000000..a89c1df8 --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/Vi/IHOSBinderDriver.cs @@ -0,0 +1,76 @@ +using ChocolArm64.Memory; +using Ryujinx.Core.OsHle.Ipc; +using Ryujinx.Core.OsHle.IpcServices.Android; +using System; +using System.Collections.Generic; + +namespace Ryujinx.Core.OsHle.IpcServices.Vi +{ + class IHOSBinderDriver : IIpcService, IDisposable + { + private Dictionary m_Commands; + + public IReadOnlyDictionary Commands => m_Commands; + + private NvFlinger Flinger; + + public IHOSBinderDriver() + { + m_Commands = new Dictionary() + { + { 0, TransactParcel }, + { 1, AdjustRefcount }, + { 2, GetNativeHandle } + }; + + Flinger = new NvFlinger(); + } + + 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 = AMemoryHelper.ReadBytes(Context.Memory, DataPos, (int)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(); + + Context.Response.HandleDesc = IpcHandleDesc.MakeMove(0xbadcafe); + + return 0; + } + + public void Dispose() + { + Dispose(true); + } + + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + Flinger.Dispose(); + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/Vi/IManagerDisplayService.cs b/Ryujinx.Core/OsHle/Services/Vi/IManagerDisplayService.cs new file mode 100644 index 00000000..5adee78d --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/Vi/IManagerDisplayService.cs @@ -0,0 +1,33 @@ +using Ryujinx.Core.OsHle.Ipc; +using System.Collections.Generic; + +namespace Ryujinx.Core.OsHle.IpcServices.Vi +{ + class IManagerDisplayService : IIpcService + { + private Dictionary m_Commands; + + public IReadOnlyDictionary Commands => m_Commands; + + public IManagerDisplayService() + { + m_Commands = new Dictionary() + { + { 2010, CreateManagedLayer }, + { 6000, AddToLayerStack } + }; + } + + public static long CreateManagedLayer(ServiceCtx Context) + { + Context.ResponseData.Write(0L); //LayerId + + return 0; + } + + public static long AddToLayerStack(ServiceCtx Context) + { + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/Vi/ISystemDisplayService.cs b/Ryujinx.Core/OsHle/Services/Vi/ISystemDisplayService.cs new file mode 100644 index 00000000..d87fcbf6 --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/Vi/ISystemDisplayService.cs @@ -0,0 +1,25 @@ +using Ryujinx.Core.OsHle.Ipc; +using System.Collections.Generic; + +namespace Ryujinx.Core.OsHle.IpcServices.Vi +{ + class ISystemDisplayService : IIpcService + { + private Dictionary m_Commands; + + public IReadOnlyDictionary Commands => m_Commands; + + public ISystemDisplayService() + { + m_Commands = new Dictionary() + { + { 2205, SetLayerZ } + }; + } + + public static long SetLayerZ(ServiceCtx Context) + { + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/Vi/NvFlinger.cs b/Ryujinx.Core/OsHle/Services/Vi/NvFlinger.cs new file mode 100644 index 00000000..85a06cea --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/Vi/NvFlinger.cs @@ -0,0 +1,395 @@ +using ChocolArm64.Memory; +using Ryujinx.Core.OsHle.Handles; +using System; +using System.IO; +using System.Collections.Generic; +using System.Text; +using System.Threading; + +using static Ryujinx.Core.OsHle.IpcServices.Android.Parcel; + +namespace Ryujinx.Core.OsHle.IpcServices.Android +{ + class NvFlinger : IDisposable + { + private delegate long ServiceProcessParcel(ServiceCtx Context, BinaryReader ParcelReader); + + private Dictionary<(string, int), ServiceProcessParcel> Commands; + + 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 BufferEntry + { + public BufferState State; + + public HalTransform Transform; + + public GbpBuffer Data; + } + + private BufferEntry[] BufferQueue; + + private ManualResetEvent WaitBufferFree; + + private bool KeepRunning; + + public NvFlinger() + { + Commands = new Dictionary<(string, int), ServiceProcessParcel>() + { + { ("android.gui.IGraphicBufferProducer", 0x1), GbpRequestBuffer }, + { ("android.gui.IGraphicBufferProducer", 0x3), GbpDequeueBuffer }, + { ("android.gui.IGraphicBufferProducer", 0x7), GbpQueueBuffer }, + { ("android.gui.IGraphicBufferProducer", 0x8), GbpCancelBuffer }, + { ("android.gui.IGraphicBufferProducer", 0x9), GbpQuery }, + { ("android.gui.IGraphicBufferProducer", 0xa), GbpConnect }, + { ("android.gui.IGraphicBufferProducer", 0xe), GbpPreallocBuffer } + }; + + BufferQueue = new BufferEntry[0x40]; + + WaitBufferFree = new ManualResetEvent(false); + + KeepRunning = true; + } + + 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)) + { + Logging.Debug($"{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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + } + + private long GbpQueueBuffer(ServiceCtx Context, BinaryReader ParcelReader) + { + //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].State = BufferState.Queued; + + SendFrameBuffer(Context, Slot); + + return MakeReplyParcel(Context, 1280, 720, 0, 0, 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 GbpPreallocBuffer(ServiceCtx Context, BinaryReader ParcelReader) + { + int Slot = ParcelReader.ReadInt32(); + + int BufferCount = ParcelReader.ReadInt32(); + 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]); + + AMemoryHelper.WriteBytes(Context.Memory, ReplyPos, Reply); + + return 0; + } + + private unsafe void SendFrameBuffer(ServiceCtx Context, int Slot) + { + int FbWidth = BufferQueue[Slot].Data.Width; + int FbHeight = BufferQueue[Slot].Data.Height; + + int FbSize = FbWidth * FbHeight * 4; + + HNvMap NvMap = GetNvMap(Context, Slot); + + if (FbSize < 0 || NvMap.Address < 0 || NvMap.Address + FbSize > AMemoryMgr.AddrSize) + { + Logging.Error($"Frame buffer address {NvMap.Address:x16} is invalid!"); + + BufferQueue[Slot].State = BufferState.Free; + + WaitBufferFree.Set(); + + return; + } + + BufferQueue[Slot].State = BufferState.Acquired; + + float ScaleX = 1; + float ScaleY = 1; + float Rotate = 0; + + if (BufferQueue[Slot].Transform.HasFlag(HalTransform.FlipX)) + { + ScaleX = -1; + } + + if (BufferQueue[Slot].Transform.HasFlag(HalTransform.FlipY)) + { + ScaleY = -1; + } + + if (BufferQueue[Slot].Transform.HasFlag(HalTransform.Rotate90)) + { + Rotate = MathF.PI * 0.5f; + } + + byte* Fb = (byte*)Context.Ns.Ram + NvMap.Address; + + Context.Ns.Gpu.Renderer.QueueAction(delegate() + { + Context.Ns.Gpu.Renderer.SetFrameBuffer( + Fb, + FbWidth, + FbHeight, + ScaleX, + ScaleY, + Rotate); + + BufferQueue[Slot].State = BufferState.Free; + + lock (WaitBufferFree) + { + WaitBufferFree.Set(); + } + }); + } + + private HNvMap GetNvMap(ServiceCtx Context, int Slot) + { + int NvMapHandle = BitConverter.ToInt32(BufferQueue[Slot].Data.RawData, 0x4c); + + if (!BitConverter.IsLittleEndian) + { + byte[] RawValue = BitConverter.GetBytes(NvMapHandle); + + Array.Reverse(RawValue); + + NvMapHandle = BitConverter.ToInt32(RawValue, 0); + } + + return Context.Ns.Os.Handles.GetData(NvMapHandle); + } + + private int GetFreeSlotBlocking(int Width, int Height) + { + int Slot; + + do + { + lock (WaitBufferFree) + { + if ((Slot = GetFreeSlot(Width, Height)) != -1) + { + break; + } + + Logging.Debug("Waiting for a free BufferQueue slot..."); + + if (!KeepRunning) + { + break; + } + + WaitBufferFree.Reset(); + } + + WaitBufferFree.WaitOne(); + } + while (KeepRunning); + + Logging.Debug($"Found free BufferQueue slot {Slot}!"); + + 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) + { + lock (WaitBufferFree) + { + KeepRunning = false; + + WaitBufferFree.Set(); + } + + WaitBufferFree.Dispose(); + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/Vi/Parcel.cs b/Ryujinx.Core/OsHle/Services/Vi/Parcel.cs new file mode 100644 index 00000000..3404c227 --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/Vi/Parcel.cs @@ -0,0 +1,58 @@ +using System; +using System.IO; + +namespace Ryujinx.Core.OsHle.IpcServices.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.Core/OsHle/Services/Vi/ServiceVi.cs b/Ryujinx.Core/OsHle/Services/Vi/ServiceVi.cs new file mode 100644 index 00000000..2c3dd2a3 --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/Vi/ServiceVi.cs @@ -0,0 +1,31 @@ +using Ryujinx.Core.OsHle.Ipc; +using System.Collections.Generic; + +using static Ryujinx.Core.OsHle.IpcServices.ObjHelper; + +namespace Ryujinx.Core.OsHle.IpcServices.Vi +{ + class ServiceVi : IIpcService + { + private Dictionary m_Commands; + + public IReadOnlyDictionary Commands => m_Commands; + + public ServiceVi() + { + m_Commands = new Dictionary() + { + { 2, GetDisplayService } + }; + } + + public long GetDisplayService(ServiceCtx Context) + { + int Unknown = Context.RequestData.ReadInt32(); + + MakeObject(Context, new IApplicationDisplayService()); + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Svc/SvcHandler.cs b/Ryujinx.Core/OsHle/Svc/SvcHandler.cs index 60af1e11..c5b6da04 100644 --- a/Ryujinx.Core/OsHle/Svc/SvcHandler.cs +++ b/Ryujinx.Core/OsHle/Svc/SvcHandler.cs @@ -30,6 +30,8 @@ namespace Ryujinx.Core.OsHle.Svc { 0x09, SvcStartThread }, { 0x0b, SvcSleepThread }, { 0x0c, SvcGetThreadPriority }, + { 0x0d, SvcSetThreadPriority }, + { 0x0f, SvcSetThreadCoreMask }, { 0x13, SvcMapSharedMemory }, { 0x14, SvcUnmapSharedMemory }, { 0x15, SvcCreateTransferMemory }, @@ -44,6 +46,7 @@ namespace Ryujinx.Core.OsHle.Svc { 0x1f, SvcConnectToNamedPort }, { 0x21, SvcSendSyncRequest }, { 0x22, SvcSendSyncRequestWithUserBuffer }, + { 0x25, SvcGetThreadId }, { 0x26, SvcBreak }, { 0x27, SvcOutputDebugString }, { 0x29, SvcGetInfo } diff --git a/Ryujinx.Core/OsHle/Svc/SvcThread.cs b/Ryujinx.Core/OsHle/Svc/SvcThread.cs index a635edb1..cc0f980b 100644 --- a/Ryujinx.Core/OsHle/Svc/SvcThread.cs +++ b/Ryujinx.Core/OsHle/Svc/SvcThread.cs @@ -81,5 +81,44 @@ namespace Ryujinx.Core.OsHle.Svc //TODO: Error codes. } + + private void SvcSetThreadPriority(AThreadState ThreadState) + { + int Handle = (int)ThreadState.X1; + int Prio = (int)ThreadState.X0; + + HThread Thread = Ns.Os.Handles.GetData(Handle); + + if (Thread != null) + { + Thread.Priority = Prio; + + ThreadState.X0 = (int)SvcResult.Success; + } + + //TODO: Error codes. + } + + private void SvcSetThreadCoreMask(AThreadState ThreadState) + { + ThreadState.X0 = (int)SvcResult.Success; + + //TODO: Error codes. + } + + private void SvcGetThreadId(AThreadState ThreadState) + { + int Handle = (int)ThreadState.X0; + + HThread Thread = Ns.Os.Handles.GetData(Handle); + + if (Thread != null) + { + ThreadState.X1 = (ulong)Thread.ThreadId; + ThreadState.X0 = (int)SvcResult.Success; + } + + //TODO: Error codes. + } } } \ No newline at end of file diff --git a/Ryujinx/Ryujinx.conf b/Ryujinx/Ryujinx.conf index 7b9af87a..e8effac1 100644 --- a/Ryujinx/Ryujinx.conf +++ b/Ryujinx/Ryujinx.conf @@ -16,6 +16,9 @@ Logging_Enable_Error = true #Enabled print fatal logs Logging_Enable_Fatal = true +#Enabled print Ipc logs +Logging_Enable_Ipc = false + #Saved logs into Ryujinx.log Logging_Enable_LogFile = false -- cgit v1.2.3