From b0b7843d5c7372db60211255be0edfcb97dcb56d Mon Sep 17 00:00:00 2001 From: Ac_K Date: Thu, 17 Aug 2023 14:59:05 +0200 Subject: [PATCH] mm: Migrate service in Horizon project (#5580) * mm: Migrate service in Horizon project This PR migrate the `mm:u` service to the Horizon project, things were checked by some RE aswell, that's why some vars are renamed, the logic should be the same as before. Tests are welcome. * Lock _sessionList instead * Fix comment * Fix Session fields order --- src/Ryujinx.HLE/HOS/Services/Mm/IRequest.cs | 196 ------------------ .../Mm/Types/MultiMediaOperationType.cs | 10 - .../Services/Mm/Types/MultiMediaSession.cs | 24 --- src/Ryujinx.Horizon/MmNv/Ipc/Request.cs | 160 ++++++++++++++ src/Ryujinx.Horizon/MmNv/MmNvIpcServer.cs | 43 ++++ src/Ryujinx.Horizon/MmNv/MmNvMain.cs | 17 ++ src/Ryujinx.Horizon/Sdk/MmNv/IRequest.cs | 17 ++ src/Ryujinx.Horizon/Sdk/MmNv/Module.cs | 15 ++ src/Ryujinx.Horizon/Sdk/MmNv/Session.cs | 26 +++ src/Ryujinx.Horizon/ServiceTable.cs | 2 + 10 files changed, 280 insertions(+), 230 deletions(-) delete mode 100644 src/Ryujinx.HLE/HOS/Services/Mm/IRequest.cs delete mode 100644 src/Ryujinx.HLE/HOS/Services/Mm/Types/MultiMediaOperationType.cs delete mode 100644 src/Ryujinx.HLE/HOS/Services/Mm/Types/MultiMediaSession.cs create mode 100644 src/Ryujinx.Horizon/MmNv/Ipc/Request.cs create mode 100644 src/Ryujinx.Horizon/MmNv/MmNvIpcServer.cs create mode 100644 src/Ryujinx.Horizon/MmNv/MmNvMain.cs create mode 100644 src/Ryujinx.Horizon/Sdk/MmNv/IRequest.cs create mode 100644 src/Ryujinx.Horizon/Sdk/MmNv/Module.cs create mode 100644 src/Ryujinx.Horizon/Sdk/MmNv/Session.cs diff --git a/src/Ryujinx.HLE/HOS/Services/Mm/IRequest.cs b/src/Ryujinx.HLE/HOS/Services/Mm/IRequest.cs deleted file mode 100644 index 31d325a9..00000000 --- a/src/Ryujinx.HLE/HOS/Services/Mm/IRequest.cs +++ /dev/null @@ -1,196 +0,0 @@ -using Ryujinx.Common.Logging; -using Ryujinx.HLE.HOS.Services.Mm.Types; -using System.Collections.Generic; - -namespace Ryujinx.HLE.HOS.Services.Mm -{ - [Service("mm:u")] - class IRequest : IpcService - { - private readonly object _sessionListLock = new(); - private readonly List _sessionList = new(); - - private uint _uniqueId = 1; - - public IRequest(ServiceCtx context) { } - - [CommandCmif(0)] - // InitializeOld(u32, u32, u32) - public ResultCode InitializeOld(ServiceCtx context) - { - MultiMediaOperationType operationType = (MultiMediaOperationType)context.RequestData.ReadUInt32(); - int fgmId = context.RequestData.ReadInt32(); - bool isAutoClearEvent = context.RequestData.ReadInt32() != 0; - - Logger.Stub?.PrintStub(LogClass.ServiceMm, new { operationType, fgmId, isAutoClearEvent }); - - Register(operationType, fgmId, isAutoClearEvent); - - return ResultCode.Success; - } - - [CommandCmif(1)] - // FinalizeOld(u32) - public ResultCode FinalizeOld(ServiceCtx context) - { - MultiMediaOperationType operationType = (MultiMediaOperationType)context.RequestData.ReadUInt32(); - - Logger.Stub?.PrintStub(LogClass.ServiceMm, new { operationType }); - - lock (_sessionListLock) - { - _sessionList.Remove(GetSessionByType(operationType)); - } - - return ResultCode.Success; - } - - [CommandCmif(2)] - // SetAndWaitOld(u32, u32, u32) - public ResultCode SetAndWaitOld(ServiceCtx context) - { - MultiMediaOperationType operationType = (MultiMediaOperationType)context.RequestData.ReadUInt32(); - uint frequenceHz = context.RequestData.ReadUInt32(); - int timeout = context.RequestData.ReadInt32(); - - Logger.Stub?.PrintStub(LogClass.ServiceMm, new { operationType, frequenceHz, timeout }); - - lock (_sessionListLock) - { - GetSessionByType(operationType)?.SetAndWait(frequenceHz, timeout); - } - - return ResultCode.Success; - } - - [CommandCmif(3)] - // GetOld(u32) -> u32 - public ResultCode GetOld(ServiceCtx context) - { - MultiMediaOperationType operationType = (MultiMediaOperationType)context.RequestData.ReadUInt32(); - - Logger.Stub?.PrintStub(LogClass.ServiceMm, new { operationType }); - - lock (_sessionListLock) - { - MultiMediaSession session = GetSessionByType(operationType); - - uint currentValue = session == null ? 0 : session.CurrentValue; - - context.ResponseData.Write(currentValue); - } - - return ResultCode.Success; - } - - [CommandCmif(4)] - // Initialize(u32, u32, u32) -> u32 - public ResultCode Initialize(ServiceCtx context) - { - MultiMediaOperationType operationType = (MultiMediaOperationType)context.RequestData.ReadUInt32(); - int fgmId = context.RequestData.ReadInt32(); - bool isAutoClearEvent = context.RequestData.ReadInt32() != 0; - - Logger.Stub?.PrintStub(LogClass.ServiceMm, new { operationType, fgmId, isAutoClearEvent }); - - uint id = Register(operationType, fgmId, isAutoClearEvent); - - context.ResponseData.Write(id); - - return ResultCode.Success; - } - - [CommandCmif(5)] - // Finalize(u32) - public ResultCode Finalize(ServiceCtx context) - { - uint id = context.RequestData.ReadUInt32(); - - Logger.Stub?.PrintStub(LogClass.ServiceMm, new { id }); - - lock (_sessionListLock) - { - _sessionList.Remove(GetSessionById(id)); - } - - return ResultCode.Success; - } - - [CommandCmif(6)] - // SetAndWait(u32, u32, u32) - public ResultCode SetAndWait(ServiceCtx context) - { - uint id = context.RequestData.ReadUInt32(); - uint frequenceHz = context.RequestData.ReadUInt32(); - int timeout = context.RequestData.ReadInt32(); - - Logger.Stub?.PrintStub(LogClass.ServiceMm, new { id, frequenceHz, timeout }); - - lock (_sessionListLock) - { - GetSessionById(id)?.SetAndWait(frequenceHz, timeout); - } - - return ResultCode.Success; - } - - [CommandCmif(7)] - // Get(u32) -> u32 - public ResultCode Get(ServiceCtx context) - { - uint id = context.RequestData.ReadUInt32(); - - Logger.Stub?.PrintStub(LogClass.ServiceMm, new { id }); - - lock (_sessionListLock) - { - MultiMediaSession session = GetSessionById(id); - - uint currentValue = session == null ? 0 : session.CurrentValue; - - context.ResponseData.Write(currentValue); - } - - return ResultCode.Success; - } - - private MultiMediaSession GetSessionById(uint id) - { - foreach (MultiMediaSession session in _sessionList) - { - if (session.Id == id) - { - return session; - } - } - - return null; - } - - private MultiMediaSession GetSessionByType(MultiMediaOperationType type) - { - foreach (MultiMediaSession session in _sessionList) - { - if (session.Type == type) - { - return session; - } - } - - return null; - } - - private uint Register(MultiMediaOperationType type, int fgmId, bool isAutoClearEvent) - { - lock (_sessionListLock) - { - // Nintendo ignore the fgm id as the other interfaces were deprecated. - MultiMediaSession session = new(_uniqueId++, type, isAutoClearEvent); - - _sessionList.Add(session); - - return session.Id; - } - } - } -} diff --git a/src/Ryujinx.HLE/HOS/Services/Mm/Types/MultiMediaOperationType.cs b/src/Ryujinx.HLE/HOS/Services/Mm/Types/MultiMediaOperationType.cs deleted file mode 100644 index 095dbfc3..00000000 --- a/src/Ryujinx.HLE/HOS/Services/Mm/Types/MultiMediaOperationType.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Mm.Types -{ - enum MultiMediaOperationType : uint - { - Ram = 2, - NvEnc = 5, - NvDec = 6, - NvJpg = 7, - } -} diff --git a/src/Ryujinx.HLE/HOS/Services/Mm/Types/MultiMediaSession.cs b/src/Ryujinx.HLE/HOS/Services/Mm/Types/MultiMediaSession.cs deleted file mode 100644 index 32b52ca5..00000000 --- a/src/Ryujinx.HLE/HOS/Services/Mm/Types/MultiMediaSession.cs +++ /dev/null @@ -1,24 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Mm.Types -{ - class MultiMediaSession - { - public MultiMediaOperationType Type { get; } - - public bool IsAutoClearEvent { get; } - public uint Id { get; } - public uint CurrentValue { get; private set; } - - public MultiMediaSession(uint id, MultiMediaOperationType type, bool isAutoClearEvent) - { - Type = type; - Id = id; - IsAutoClearEvent = isAutoClearEvent; - CurrentValue = 0; - } - - public void SetAndWait(uint value, int timeout) - { - CurrentValue = value; - } - } -} diff --git a/src/Ryujinx.Horizon/MmNv/Ipc/Request.cs b/src/Ryujinx.Horizon/MmNv/Ipc/Request.cs new file mode 100644 index 00000000..9a24c75e --- /dev/null +++ b/src/Ryujinx.Horizon/MmNv/Ipc/Request.cs @@ -0,0 +1,160 @@ +using Ryujinx.Common.Logging; +using Ryujinx.Horizon.Common; +using Ryujinx.Horizon.Sdk.MmNv; +using Ryujinx.Horizon.Sdk.Sf; +using System.Collections.Generic; + +namespace Ryujinx.Horizon.MmNv.Ipc +{ + partial class Request : IRequest + { + private readonly List _sessionList = new(); + + private uint _uniqueId = 1; + + [CmifCommand(0)] + public Result InitializeOld(Module module, uint fgmPriority, uint autoClearEvent) + { + bool isAutoClearEvent = autoClearEvent != 0; + + Logger.Stub?.PrintStub(LogClass.ServiceMm, new { module, fgmPriority, isAutoClearEvent }); + + Register(module, fgmPriority, isAutoClearEvent); + + return Result.Success; + } + + [CmifCommand(1)] + public Result FinalizeOld(Module module) + { + Logger.Stub?.PrintStub(LogClass.ServiceMm, new { module }); + + lock (_sessionList) + { + _sessionList.Remove(GetSessionByModule(module)); + } + + return Result.Success; + } + + [CmifCommand(2)] + public Result SetAndWaitOld(Module module, uint clockRateMin, int clockRateMax) + { + Logger.Stub?.PrintStub(LogClass.ServiceMm, new { module, clockRateMin, clockRateMax }); + + lock (_sessionList) + { + GetSessionByModule(module)?.SetAndWait(clockRateMin, clockRateMax); + } + + return Result.Success; + } + + [CmifCommand(3)] + public Result GetOld(out uint clockRateActual, Module module) + { + Logger.Stub?.PrintStub(LogClass.ServiceMm, new { module }); + + lock (_sessionList) + { + Session session = GetSessionByModule(module); + + clockRateActual = session == null ? 0 : session.ClockRateMin; + } + + return Result.Success; + } + + [CmifCommand(4)] + public Result Initialize(out uint requestId, Module module, uint fgmPriority, uint autoClearEvent) + { + bool isAutoClearEvent = autoClearEvent != 0; + + Logger.Stub?.PrintStub(LogClass.ServiceMm, new { module, fgmPriority, isAutoClearEvent }); + + requestId = Register(module, fgmPriority, isAutoClearEvent); + + return Result.Success; + } + + [CmifCommand(5)] + public Result Finalize(uint requestId) + { + Logger.Stub?.PrintStub(LogClass.ServiceMm, new { requestId }); + + lock (_sessionList) + { + _sessionList.Remove(GetSessionById(requestId)); + } + + return Result.Success; + } + + [CmifCommand(6)] + public Result SetAndWait(uint requestId, uint clockRateMin, int clockRateMax) + { + Logger.Stub?.PrintStub(LogClass.ServiceMm, new { requestId, clockRateMin, clockRateMax }); + + lock (_sessionList) + { + GetSessionById(requestId)?.SetAndWait(clockRateMin, clockRateMax); + } + + return Result.Success; + } + + [CmifCommand(7)] + public Result Get(out uint clockRateActual, uint requestId) + { + Logger.Stub?.PrintStub(LogClass.ServiceMm, new { requestId }); + + lock (_sessionList) + { + Session session = GetSessionById(requestId); + + clockRateActual = session == null ? 0 : session.ClockRateMin; + } + + return Result.Success; + } + + private Session GetSessionById(uint id) + { + foreach (Session session in _sessionList) + { + if (session.Id == id) + { + return session; + } + } + + return null; + } + + private Session GetSessionByModule(Module module) + { + foreach (Session session in _sessionList) + { + if (session.Module == module) + { + return session; + } + } + + return null; + } + + private uint Register(Module module, uint fgmPriority, bool isAutoClearEvent) + { + lock (_sessionList) + { + // Nintendo ignores the fgm priority as the other services were deprecated. + Session session = new(_uniqueId++, module, isAutoClearEvent); + + _sessionList.Add(session); + + return session.Id; + } + } + } +} diff --git a/src/Ryujinx.Horizon/MmNv/MmNvIpcServer.cs b/src/Ryujinx.Horizon/MmNv/MmNvIpcServer.cs new file mode 100644 index 00000000..e60b2558 --- /dev/null +++ b/src/Ryujinx.Horizon/MmNv/MmNvIpcServer.cs @@ -0,0 +1,43 @@ +using Ryujinx.Horizon.MmNv.Ipc; +using Ryujinx.Horizon.Sdk.Sf.Hipc; +using Ryujinx.Horizon.Sdk.Sm; + +namespace Ryujinx.Horizon.MmNv +{ + class MmNvIpcServer + { + private const int MmNvMaxSessionsCount = 9; + + private const int PointerBufferSize = 0; + private const int MaxDomains = 0; + private const int MaxDomainObjects = 0; + private const int MaxPortsCount = 1; + + private static readonly ManagerOptions _mmNvOptions = new(PointerBufferSize, MaxDomains, MaxDomainObjects, false); + + private SmApi _sm; + private ServerManager _serverManager; + + public void Initialize() + { + HeapAllocator allocator = new(); + + _sm = new SmApi(); + _sm.Initialize().AbortOnFailure(); + + _serverManager = new ServerManager(allocator, _sm, MaxPortsCount, _mmNvOptions, MmNvMaxSessionsCount); + + _serverManager.RegisterObjectForServer(new Request(), ServiceName.Encode("mm:u"), MmNvMaxSessionsCount); + } + + public void ServiceRequests() + { + _serverManager.ServiceRequests(); + } + + public void Shutdown() + { + _serverManager.Dispose(); + } + } +} diff --git a/src/Ryujinx.Horizon/MmNv/MmNvMain.cs b/src/Ryujinx.Horizon/MmNv/MmNvMain.cs new file mode 100644 index 00000000..ac5eff1a --- /dev/null +++ b/src/Ryujinx.Horizon/MmNv/MmNvMain.cs @@ -0,0 +1,17 @@ +namespace Ryujinx.Horizon.MmNv +{ + class MmNvMain : IService + { + public static void Main(ServiceTable serviceTable) + { + MmNvIpcServer ipcServer = new(); + + ipcServer.Initialize(); + + serviceTable.SignalServiceReady(); + + ipcServer.ServiceRequests(); + ipcServer.Shutdown(); + } + } +} diff --git a/src/Ryujinx.Horizon/Sdk/MmNv/IRequest.cs b/src/Ryujinx.Horizon/Sdk/MmNv/IRequest.cs new file mode 100644 index 00000000..300b957f --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/MmNv/IRequest.cs @@ -0,0 +1,17 @@ +using Ryujinx.Horizon.Common; +using Ryujinx.Horizon.Sdk.Sf; + +namespace Ryujinx.Horizon.Sdk.MmNv +{ + interface IRequest : IServiceObject + { + Result InitializeOld(Module module, uint fgmPriority, uint autoClearEvent); + Result FinalizeOld(Module module); + Result SetAndWaitOld(Module module, uint clockRateMin, int clockRateMax); + Result GetOld(out uint clockRateActual, Module module); + Result Initialize(out uint requestId, Module module, uint fgmPriority, uint autoClearEvent); + Result Finalize(uint requestId); + Result SetAndWait(uint requestId, uint clockRateMin, int clockRateMax); + Result Get(out uint clockRateActual, uint requestId); + } +} diff --git a/src/Ryujinx.Horizon/Sdk/MmNv/Module.cs b/src/Ryujinx.Horizon/Sdk/MmNv/Module.cs new file mode 100644 index 00000000..e029d037 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/MmNv/Module.cs @@ -0,0 +1,15 @@ +namespace Ryujinx.Horizon.Sdk.MmNv +{ + enum Module : uint + { + Cpu, + Gpu, + Emc, + SysBus, + MSelect, + NvDec, + NvEnc, + NvJpg, + Test, + } +} diff --git a/src/Ryujinx.Horizon/Sdk/MmNv/Session.cs b/src/Ryujinx.Horizon/Sdk/MmNv/Session.cs new file mode 100644 index 00000000..b9158569 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/MmNv/Session.cs @@ -0,0 +1,26 @@ +namespace Ryujinx.Horizon.Sdk.MmNv +{ + class Session + { + public Module Module { get; } + public uint Id { get; } + public bool IsAutoClearEvent { get; } + public uint ClockRateMin { get; private set; } + public int ClockRateMax { get; private set; } + + public Session(uint id, Module module, bool isAutoClearEvent) + { + Module = module; + Id = id; + IsAutoClearEvent = isAutoClearEvent; + ClockRateMin = 0; + ClockRateMax = -1; + } + + public void SetAndWait(uint clockRateMin, int clockRateMax) + { + ClockRateMin = clockRateMin; + ClockRateMax = clockRateMax; + } + } +} diff --git a/src/Ryujinx.Horizon/ServiceTable.cs b/src/Ryujinx.Horizon/ServiceTable.cs index d47f91bf..8dfacbeb 100644 --- a/src/Ryujinx.Horizon/ServiceTable.cs +++ b/src/Ryujinx.Horizon/ServiceTable.cs @@ -1,5 +1,6 @@ using Ryujinx.Horizon.Bcat; using Ryujinx.Horizon.LogManager; +using Ryujinx.Horizon.MmNv; using Ryujinx.Horizon.Prepo; using System.Collections.Generic; using System.Threading; @@ -25,6 +26,7 @@ namespace Ryujinx.Horizon RegisterService(); RegisterService(); RegisterService(); + RegisterService(); _totalServices = entries.Count;