apm/am: Refactoring/Unstub services (#1662)

* apm: Refactoring/Unstub service

This PR implement some IPC calls of apm service:
- nn::apm::IManager is fully implemented.
- nn::apm::ISession is fully implemented (close #1633).
- nn::apm::ISystemManager is partially implemented.

nn::appletAE::ICommonStateGetter have some calls which are just a layer of apm IPC calls. What we did in some calls was wrong, it's fixed now!

Everything is checked with RE.

* abstract Apm *Server as Thog requested

* abstract ISession and fix other classes

* Address gdkchan feedback

* Fix class

* Fix Logging
This commit is contained in:
Ac_K 2020-11-08 21:00:54 +01:00 committed by GitHub
parent 8d168574eb
commit eda6b78894
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 282 additions and 37 deletions

View file

@ -15,6 +15,7 @@ using Ryujinx.HLE.HOS.Kernel.Memory;
using Ryujinx.HLE.HOS.Kernel.Process;
using Ryujinx.HLE.HOS.Kernel.Threading;
using Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.SystemAppletProxy;
using Ryujinx.HLE.HOS.Services.Apm;
using Ryujinx.HLE.HOS.Services.Arp;
using Ryujinx.HLE.HOS.Services.Audio.AudioRenderer;
using Ryujinx.HLE.HOS.Services.Mii;
@ -53,6 +54,8 @@ namespace Ryujinx.HLE.HOS
public SystemStateMgr State { get; private set; }
internal PerformanceState PerformanceState { get; private set; }
internal AppletStateMgr AppletState { get; private set; }
internal KSharedMemory HidSharedMem { get; private set; }
@ -94,6 +97,8 @@ namespace Ryujinx.HLE.HOS
State = new SystemStateMgr();
PerformanceState = new PerformanceState();
// Note: This is not really correct, but with HLE of services, the only memory
// region used that is used is Application, so we can use the other ones for anything.
KMemoryRegionManager region = KernelContext.MemoryRegions[(int)MemoryRegion.NvServices];

View file

@ -10,7 +10,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService
// GetCommonStateGetter() -> object<nn::am::service::ICommonStateGetter>
public ResultCode GetCommonStateGetter(ServiceCtx context)
{
MakeObject(context, new ICommonStateGetter());
MakeObject(context, new ICommonStateGetter(context));
return ResultCode.Success;
}

View file

@ -2,17 +2,22 @@ using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS.Ipc;
using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Threading;
using Ryujinx.HLE.HOS.Services.Apm;
using System;
namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.SystemAppletProxy
{
class ICommonStateGetter : IpcService
{
private CpuBoostMode _cpuBoostMode = CpuBoostMode.Disabled;
private bool _vrModeEnabled = false;
private Apm.ManagerServer apmManagerServer;
private Apm.SystemManagerServer apmSystemManagerServer;
public ICommonStateGetter() { }
private bool _vrModeEnabled = false;
public ICommonStateGetter(ServiceCtx context)
{
apmManagerServer = new Apm.ManagerServer(context);
apmSystemManagerServer = new Apm.SystemManagerServer(context);
}
[Command(0)]
// GetEventHandle() -> handle<copy>
@ -58,16 +63,10 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
}
[Command(6)]
// GetPerformanceMode() -> u32
// GetPerformanceMode() -> nn::apm::PerformanceMode
public ResultCode GetPerformanceMode(ServiceCtx context)
{
PerformanceMode mode = context.Device.System.State.DockedMode
? PerformanceMode.Docked
: PerformanceMode.Handheld;
context.ResponseData.Write((int)mode);
return ResultCode.Success;
return (ResultCode)apmManagerServer.GetPerformanceMode(context);
}
[Command(8)]
@ -136,12 +135,18 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
return ResultCode.InvalidParameters;
}
_cpuBoostMode = (CpuBoostMode)cpuBoostMode;
apmSystemManagerServer.SetCpuBoostMode((Apm.CpuBoostMode)cpuBoostMode);
// NOTE: There is a condition variable after the assignment, probably waiting something with apm:sys service (SetCpuBoostMode call?).
// Since we will probably never support CPU boost things, it's not needed to implement more.
// TODO: It signals an internal event of ICommonStateGetter. We have to determine where this event is used.
return ResultCode.Success;
}
[Command(91)] // 7.0.0+
// GetCurrentPerformanceConfiguration() -> nn::apm::PerformanceConfiguration
public ResultCode GetCurrentPerformanceConfiguration(ServiceCtx context)
{
return (ResultCode)apmSystemManagerServer.GetCurrentPerformanceConfiguration(context);
}
}
}

View file

@ -11,7 +11,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService
// GetCommonStateGetter() -> object<nn::am::service::ICommonStateGetter>
public ResultCode GetCommonStateGetter(ServiceCtx context)
{
MakeObject(context, new ICommonStateGetter());
MakeObject(context, new ICommonStateGetter(context));
return ResultCode.Success;
}

View file

@ -1,15 +1,41 @@
namespace Ryujinx.HLE.HOS.Services.Apm
{
[Service("apm")] // 8.0.0+
class IManager : IpcService
abstract class IManager : IpcService
{
public IManager(ServiceCtx context) { }
protected abstract ResultCode OpenSession(out SessionServer sessionServer);
protected abstract PerformanceMode GetPerformanceMode();
protected abstract bool IsCpuOverclockEnabled();
[Command(0)]
// OpenSession() -> object<nn::apm::ISession>
public ResultCode OpenSession(ServiceCtx context)
{
MakeObject(context, new ISession());
ResultCode resultCode = OpenSession(out SessionServer sessionServer);
if (resultCode == ResultCode.Success)
{
MakeObject(context, sessionServer);
}
return resultCode;
}
[Command(1)]
// GetPerformanceMode() -> nn::apm::PerformanceMode
public ResultCode GetPerformanceMode(ServiceCtx context)
{
context.ResponseData.Write((uint)GetPerformanceMode());
return ResultCode.Success;
}
[Command(6)] // 7.0.0+
// IsCpuOverclockEnabled() -> bool
public ResultCode IsCpuOverclockEnabled(ServiceCtx context)
{
context.ResponseData.Write(IsCpuOverclockEnabled());
return ResultCode.Success;
}

View file

@ -1,30 +1,43 @@
using Ryujinx.Common.Logging;
namespace Ryujinx.HLE.HOS.Services.Apm
{
class ISession : IpcService
abstract class ISession : IpcService
{
public ISession() { }
public ISession(ServiceCtx context) { }
protected abstract ResultCode SetPerformanceConfiguration(PerformanceMode performanceMode, PerformanceConfiguration performanceConfiguration);
protected abstract ResultCode GetPerformanceConfiguration(PerformanceMode performanceMode, out PerformanceConfiguration performanceConfiguration);
protected abstract void SetCpuOverclockEnabled(bool enabled);
[Command(0)]
// SetPerformanceConfiguration(nn::apm::PerformanceMode, nn::apm::PerformanceConfiguration)
public ResultCode SetPerformanceConfiguration(ServiceCtx context)
{
PerformanceMode perfMode = (PerformanceMode)context.RequestData.ReadInt32();
PerformanceConfiguration perfConfig = (PerformanceConfiguration)context.RequestData.ReadInt32();
PerformanceMode performanceMode = (PerformanceMode)context.RequestData.ReadInt32();
PerformanceConfiguration performanceConfiguration = (PerformanceConfiguration)context.RequestData.ReadInt32();
return ResultCode.Success;
return SetPerformanceConfiguration(performanceMode, performanceConfiguration);
}
[Command(1)]
// GetPerformanceConfiguration(nn::apm::PerformanceMode) -> nn::apm::PerformanceConfiguration
public ResultCode GetPerformanceConfiguration(ServiceCtx context)
{
PerformanceMode perfMode = (PerformanceMode)context.RequestData.ReadInt32();
PerformanceMode performanceMode = (PerformanceMode)context.RequestData.ReadInt32();
context.ResponseData.Write((uint)PerformanceConfiguration.PerformanceConfiguration1);
ResultCode resultCode = GetPerformanceConfiguration(performanceMode, out PerformanceConfiguration performanceConfiguration);
Logger.Stub?.PrintStub(LogClass.ServiceApm);
context.ResponseData.Write((uint)performanceConfiguration);
return resultCode;
}
[Command(2)] // 8.0.0+
// SetCpuOverclockEnabled(bool)
public ResultCode SetCpuOverclockEnabled(ServiceCtx context)
{
bool enabled = context.RequestData.ReadBoolean();
SetCpuOverclockEnabled(enabled);
return ResultCode.Success;
}

View file

@ -0,0 +1,42 @@
namespace Ryujinx.HLE.HOS.Services.Apm
{
abstract class ISystemManager : IpcService
{
public ISystemManager(ServiceCtx context) { }
protected abstract void RequestPerformanceMode(PerformanceMode performanceMode);
internal abstract void SetCpuBoostMode(CpuBoostMode cpuBoostMode);
protected abstract PerformanceConfiguration GetCurrentPerformanceConfiguration();
[Command(0)]
// RequestPerformanceMode(nn::apm::PerformanceMode)
public ResultCode RequestPerformanceMode(ServiceCtx context)
{
RequestPerformanceMode((PerformanceMode)context.RequestData.ReadInt32());
// NOTE: This call seems to overclock the system related to the PerformanceMode, since we emulate it, it's fine to do nothing instead.
return ResultCode.Success;
}
[Command(6)] // 7.0.0+
// SetCpuBoostMode(nn::apm::CpuBootMode)
public ResultCode SetCpuBoostMode(ServiceCtx context)
{
SetCpuBoostMode((CpuBoostMode)context.RequestData.ReadUInt32());
// NOTE: This call seems to overclock the system related to the CpuBoostMode, since we emulate it, it's fine to do nothing instead.
return ResultCode.Success;
}
[Command(7)] // 7.0.0+
// GetCurrentPerformanceConfiguration() -> nn::apm::PerformanceConfiguration
public ResultCode GetCurrentPerformanceConfiguration(ServiceCtx context)
{
context.ResponseData.Write((uint)GetCurrentPerformanceConfiguration());
return ResultCode.Success;
}
}
}

View file

@ -0,0 +1,31 @@
namespace Ryujinx.HLE.HOS.Services.Apm
{
[Service("apm")]
[Service("apm:am")] // 8.0.0+
class ManagerServer : IManager
{
private readonly ServiceCtx _context;
public ManagerServer(ServiceCtx context) : base(context)
{
_context = context;
}
protected override ResultCode OpenSession(out SessionServer sessionServer)
{
sessionServer = new SessionServer(_context);
return ResultCode.Success;
}
protected override PerformanceMode GetPerformanceMode()
{
return _context.Device.System.PerformanceState.PerformanceMode;
}
protected override bool IsCpuOverclockEnabled()
{
return _context.Device.System.PerformanceState.CpuOverclockEnabled;
}
}
}

View file

@ -0,0 +1,25 @@
namespace Ryujinx.HLE.HOS.Services.Apm
{
class PerformanceState
{
public PerformanceState() { }
public bool CpuOverclockEnabled = false;
public PerformanceMode PerformanceMode = PerformanceMode.Default;
public CpuBoostMode CpuBoostMode = CpuBoostMode.Disabled;
public PerformanceConfiguration DefaultPerformanceConfiguration = PerformanceConfiguration.PerformanceConfiguration7;
public PerformanceConfiguration BoostPerformanceConfiguration = PerformanceConfiguration.PerformanceConfiguration8;
public PerformanceConfiguration GetCurrentPerformanceConfiguration(PerformanceMode performanceMode)
{
return performanceMode switch
{
PerformanceMode.Default => DefaultPerformanceConfiguration,
PerformanceMode.Boost => BoostPerformanceConfiguration,
_ => PerformanceConfiguration.PerformanceConfiguration7
};
}
}
}

View file

@ -0,0 +1,12 @@
namespace Ryujinx.HLE.HOS.Services.Apm
{
enum ResultCode
{
ModuleId = 148,
ErrorCodeShift = 9,
Success = 0,
InvalidParameters = (1 << ErrorCodeShift) | ModuleId
}
}

View file

@ -0,0 +1,58 @@
using Ryujinx.Common.Logging;
namespace Ryujinx.HLE.HOS.Services.Apm
{
class SessionServer : ISession
{
private readonly ServiceCtx _context;
public SessionServer(ServiceCtx context) : base(context)
{
_context = context;
}
protected override ResultCode SetPerformanceConfiguration(PerformanceMode performanceMode, PerformanceConfiguration performanceConfiguration)
{
if (performanceMode > PerformanceMode.Boost)
{
return ResultCode.InvalidParameters;
}
switch (performanceMode)
{
case PerformanceMode.Default:
_context.Device.System.PerformanceState.DefaultPerformanceConfiguration = performanceConfiguration;
break;
case PerformanceMode.Boost:
_context.Device.System.PerformanceState.BoostPerformanceConfiguration = performanceConfiguration;
break;
default:
Logger.Error?.Print(LogClass.ServiceApm, $"PerformanceMode isn't supported: {performanceMode}");
break;
}
return ResultCode.Success;
}
protected override ResultCode GetPerformanceConfiguration(PerformanceMode performanceMode, out PerformanceConfiguration performanceConfiguration)
{
if (performanceMode > PerformanceMode.Boost)
{
performanceConfiguration = 0;
return ResultCode.InvalidParameters;
}
performanceConfiguration = _context.Device.System.PerformanceState.GetCurrentPerformanceConfiguration(performanceMode);
return ResultCode.Success;
}
protected override void SetCpuOverclockEnabled(bool enabled)
{
_context.Device.System.PerformanceState.CpuOverclockEnabled = enabled;
// NOTE: This call seems to overclock the system, since we emulate it, it's fine to do nothing instead.
}
}
}

View file

@ -0,0 +1,28 @@
namespace Ryujinx.HLE.HOS.Services.Apm
{
[Service("apm:sys")]
class SystemManagerServer : ISystemManager
{
private readonly ServiceCtx _context;
public SystemManagerServer(ServiceCtx context) : base(context)
{
_context = context;
}
protected override void RequestPerformanceMode(PerformanceMode performanceMode)
{
_context.Device.System.PerformanceState.PerformanceMode = performanceMode;
}
internal override void SetCpuBoostMode(CpuBoostMode cpuBoostMode)
{
_context.Device.System.PerformanceState.CpuBoostMode = cpuBoostMode;
}
protected override PerformanceConfiguration GetCurrentPerformanceConfiguration()
{
return _context.Device.System.PerformanceState.GetCurrentPerformanceConfiguration(_context.Device.System.PerformanceState.PerformanceMode);
}
}
}

View file

@ -2,8 +2,8 @@
{
enum CpuBoostMode
{
Disabled = 0,
Mode1 = 1, // Use PerformanceConfiguration13 and PerformanceConfiguration14, or PerformanceConfiguration15 and PerformanceConfiguration16
Mode2 = 2 // Use PerformanceConfiguration15 and PerformanceConfiguration16.
Disabled = 0,
BoostCPU = 1, // Uses PerformanceConfiguration13 and PerformanceConfiguration14, or PerformanceConfiguration15 and PerformanceConfiguration16
ConservePower = 2 // Uses PerformanceConfiguration15 and PerformanceConfiguration16.
}
}

View file

@ -1,6 +1,6 @@
namespace Ryujinx.HLE.HOS.Services.Apm
{
enum PerformanceConfiguration : uint // Clocks are all in MHz.
enum PerformanceConfiguration : uint // Clocks are all in MHz.
{ // CPU | GPU | RAM | NOTE
PerformanceConfiguration1 = 0x00010000, // 1020 | 384 | 1600 | Only available while docked.
PerformanceConfiguration2 = 0x00010001, // 1020 | 768 | 1600 | Only available while docked.

View file

@ -1,8 +1,8 @@
namespace Ryujinx.HLE.HOS.Services.Apm
{
enum PerformanceMode
enum PerformanceMode : uint
{
Handheld = 0,
Docked = 1
Default = 0,
Boost = 1
}
}