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
This commit is contained in:
Ac_K
2023-08-17 14:59:05 +02:00
committed by GitHub
parent 6ed613a6e6
commit b0b7843d5c
10 changed files with 280 additions and 230 deletions

View File

@ -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<Session> _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;
}
}
}
}

View File

@ -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();
}
}
}

View File

@ -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();
}
}
}

View File

@ -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);
}
}

View File

@ -0,0 +1,15 @@
namespace Ryujinx.Horizon.Sdk.MmNv
{
enum Module : uint
{
Cpu,
Gpu,
Emc,
SysBus,
MSelect,
NvDec,
NvEnc,
NvJpg,
Test,
}
}

View File

@ -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;
}
}
}

View File

@ -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<LmMain>();
RegisterService<PrepoMain>();
RegisterService<BcatMain>();
RegisterService<MmNvMain>();
_totalServices = entries.Count;