Update ClockCore logics to 9.0.0

Also apply 9.0.0 permissions and comment time:u, and time:a (as those
are going to be moved)
This commit is contained in:
Thog 2019-09-28 21:43:52 +02:00
commit 26b4aad831
No known key found for this signature in database
GPG key ID: 0CD291558FAFDBC6
12 changed files with 280 additions and 110 deletions

View file

@ -19,7 +19,7 @@
public EphemeralNetworkSystemClockCore(SteadyClockCore steadyClockCore) : base(steadyClockCore) { } public EphemeralNetworkSystemClockCore(SteadyClockCore steadyClockCore) : base(steadyClockCore) { }
public override ResultCode Flush(SystemClockContext context) protected override ResultCode Flush(SystemClockContext context)
{ {
return ResultCode.Success; return ResultCode.Success;
} }

View file

@ -19,7 +19,7 @@
public StandardLocalSystemClockCore(StandardSteadyClockCore steadyClockCore) : base(steadyClockCore) {} public StandardLocalSystemClockCore(StandardSteadyClockCore steadyClockCore) : base(steadyClockCore) {}
public override ResultCode Flush(SystemClockContext context) protected override ResultCode Flush(SystemClockContext context)
{ {
// TODO: set:sys SetUserSystemClockContext // TODO: set:sys SetUserSystemClockContext

View file

@ -26,7 +26,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
_standardNetworkClockSufficientAccuracy = new TimeSpanType(0); _standardNetworkClockSufficientAccuracy = new TimeSpanType(0);
} }
public override ResultCode Flush(SystemClockContext context) protected override ResultCode Flush(SystemClockContext context)
{ {
// TODO: set:sys SetNetworkSystemClockContext // TODO: set:sys SetNetworkSystemClockContext
@ -40,7 +40,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
bool isStandardNetworkClockSufficientAccuracy = false; bool isStandardNetworkClockSufficientAccuracy = false;
ResultCode result = GetSystemClockContext(thread, out SystemClockContext context); ResultCode result = GetClockContext(thread, out SystemClockContext context);
if (result == ResultCode.Success && context.SteadyTimePoint.GetSpanBetween(currentTimePoint, out long outSpan) == ResultCode.Success) if (result == ResultCode.Success && context.SteadyTimePoint.GetSpanBetween(currentTimePoint, out long outSpan) == ResultCode.Success)
{ {

View file

@ -5,11 +5,12 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
{ {
class StandardSteadyClockCore : SteadyClockCore class StandardSteadyClockCore : SteadyClockCore
{ {
private long _setupValue; private TimeSpanType _setupValue;
private ResultCode _setupResultCode; // TODO: move this to glue when we will have psc fully done
private bool _isRtcResetDetected; //private ResultCode _setupResultCode;
private TimeSpanType _testOffset; private TimeSpanType _testOffset;
private TimeSpanType _internalOffset; private TimeSpanType _internalOffset;
private TimeSpanType _cachedRawTimePoint;
private static StandardSteadyClockCore _instance; private static StandardSteadyClockCore _instance;
@ -28,22 +29,20 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
private StandardSteadyClockCore() private StandardSteadyClockCore()
{ {
_testOffset = new TimeSpanType(0); _setupValue = new TimeSpanType(0);
_internalOffset = new TimeSpanType(0); _testOffset = new TimeSpanType(0);
_internalOffset = new TimeSpanType(0);
_cachedRawTimePoint = new TimeSpanType(0);
} }
public override SteadyClockTimePoint GetTimePoint(KThread thread) public override SteadyClockTimePoint GetTimePoint(KThread thread)
{ {
SteadyClockTimePoint result = new SteadyClockTimePoint SteadyClockTimePoint result = new SteadyClockTimePoint
{ {
TimePoint = 0, TimePoint = GetCurrentRawTimePoint(thread).ToSeconds(),
ClockSourceId = GetClockSourceId() ClockSourceId = GetClockSourceId()
}; };
TimeSpanType ticksTimeSpan = TimeSpanType.FromTicks(thread.Context.CntpctEl0, thread.Context.CntfrqEl0);
result.TimePoint = _setupValue + ticksTimeSpan.ToSeconds();
return result; return result;
} }
@ -57,16 +56,6 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
_testOffset = testOffset; _testOffset = testOffset;
} }
public override ResultCode GetRtcValue(out ulong rtcValue)
{
return (ResultCode)IRtcManager.GetExternalRtcValue(out rtcValue);
}
public bool IsRtcResetDetected()
{
return _isRtcResetDetected;
}
public override TimeSpanType GetInternalOffset() public override TimeSpanType GetInternalOffset()
{ {
return _internalOffset; return _internalOffset;
@ -77,12 +66,24 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
_internalOffset = internalOffset; _internalOffset = internalOffset;
} }
public override ResultCode GetSetupResultValue() public override TimeSpanType GetCurrentRawTimePoint(KThread thread)
{ {
return _setupResultCode; TimeSpanType ticksTimeSpan = TimeSpanType.FromTicks(thread.Context.CntpctEl0, thread.Context.CntfrqEl0);
TimeSpanType rawTimePoint = new TimeSpanType(_setupValue.NanoSeconds + ticksTimeSpan.NanoSeconds);
if (rawTimePoint.NanoSeconds < _cachedRawTimePoint.NanoSeconds)
{
rawTimePoint.NanoSeconds = _cachedRawTimePoint.NanoSeconds;
}
_cachedRawTimePoint = rawTimePoint;
return rawTimePoint;
} }
public void ConfigureSetupValue() // TODO: move this to glue when we will have psc fully done
/*public void ConfigureSetupValue()
{ {
int retry = 0; int retry = 0;
@ -94,7 +95,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
if (result == ResultCode.Success) if (result == ResultCode.Success)
{ {
_setupValue = (long)rtcValue; _setupValue = TimeSpanType.FromSeconds((long)rtcValue);
break; break;
} }
@ -102,6 +103,6 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
} }
_setupResultCode = result; _setupResultCode = result;
} }*/
} }
} }

View file

@ -30,12 +30,12 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
_autoCorrectionEnabled = false; _autoCorrectionEnabled = false;
} }
public override ResultCode Flush(SystemClockContext context) protected override ResultCode Flush(SystemClockContext context)
{ {
return ResultCode.NotImplemented; return ResultCode.NotImplemented;
} }
public override ResultCode GetSystemClockContext(KThread thread, out SystemClockContext context) public override ResultCode GetClockContext(KThread thread, out SystemClockContext context)
{ {
ResultCode result = ApplyAutomaticCorrection(thread, false); ResultCode result = ApplyAutomaticCorrection(thread, false);
@ -43,13 +43,13 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
if (result == ResultCode.Success) if (result == ResultCode.Success)
{ {
return _localSystemClockCore.GetSystemClockContext(thread, out context); return _localSystemClockCore.GetClockContext(thread, out context);
} }
return result; return result;
} }
public override ResultCode SetSystemClockContext(SystemClockContext context) public override ResultCode SetClockContext(SystemClockContext context)
{ {
return ResultCode.NotImplemented; return ResultCode.NotImplemented;
} }
@ -60,11 +60,11 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
if (_autoCorrectionEnabled != autoCorrectionEnabled && _networkSystemClockCore.IsClockSetup(thread)) if (_autoCorrectionEnabled != autoCorrectionEnabled && _networkSystemClockCore.IsClockSetup(thread))
{ {
result = _networkSystemClockCore.GetSystemClockContext(thread, out SystemClockContext context); result = _networkSystemClockCore.GetClockContext(thread, out SystemClockContext context);
if (result == ResultCode.Success) if (result == ResultCode.Success)
{ {
_localSystemClockCore.SetSystemClockContext(context); _localSystemClockCore.SetClockContext(context);
} }
} }

View file

@ -7,10 +7,14 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
abstract class SteadyClockCore abstract class SteadyClockCore
{ {
private UInt128 _clockSourceId; private UInt128 _clockSourceId;
private bool _isRtcResetDetected;
private bool _isInitialized;
public SteadyClockCore() public SteadyClockCore()
{ {
_clockSourceId = new UInt128(Guid.NewGuid().ToByteArray()); _clockSourceId = new UInt128(Guid.NewGuid().ToByteArray());
_isRtcResetDetected = false;
_isInitialized = false;
} }
public UInt128 GetClockSourceId() public UInt128 GetClockSourceId()
@ -32,9 +36,14 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
return ResultCode.NotImplemented; return ResultCode.NotImplemented;
} }
public virtual ResultCode GetSetupResultValue() public bool IsRtcResetDetected()
{ {
return ResultCode.NotImplemented; return _isRtcResetDetected;
}
public ResultCode GetSetupResultValue()
{
return ResultCode.Success;
} }
public virtual TimeSpanType GetInternalOffset() public virtual TimeSpanType GetInternalOffset()
@ -49,6 +58,13 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
throw new NotImplementedException(); throw new NotImplementedException();
} }
public virtual TimeSpanType GetCurrentRawTimePoint(KThread thread)
{
SteadyClockTimePoint timePoint = GetTimePoint(thread);
return TimeSpanType.FromSeconds(timePoint.TimePoint);
}
public SteadyClockTimePoint GetCurrentTimePoint(KThread thread) public SteadyClockTimePoint GetCurrentTimePoint(KThread thread)
{ {
SteadyClockTimePoint result = GetTimePoint(thread); SteadyClockTimePoint result = GetTimePoint(thread);
@ -58,5 +74,15 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
return result; return result;
} }
public bool IsInitialized()
{
return _isInitialized;
}
public void MarkInitialized()
{
_isInitialized = true;
}
} }
} }

View file

@ -6,11 +6,13 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
{ {
private SteadyClockCore _steadyClockCore; private SteadyClockCore _steadyClockCore;
private SystemClockContext _context; private SystemClockContext _context;
private bool _isInitialized;
public SystemClockCore(SteadyClockCore steadyClockCore) public SystemClockCore(SteadyClockCore steadyClockCore)
{ {
_steadyClockCore = steadyClockCore; _steadyClockCore = steadyClockCore;
_context = new SystemClockContext(); _context = new SystemClockContext();
_isInitialized = false;
_context.SteadyTimePoint.ClockSourceId = steadyClockCore.GetClockSourceId(); _context.SteadyTimePoint.ClockSourceId = steadyClockCore.GetClockSourceId();
} }
@ -20,31 +22,94 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
return _steadyClockCore; return _steadyClockCore;
} }
public virtual ResultCode GetSystemClockContext(KThread thread, out SystemClockContext context) public ResultCode GetCurrentTime(KThread thread, out long posixTime)
{
posixTime = 0;
SteadyClockTimePoint currentTimePoint = _steadyClockCore.GetCurrentTimePoint(thread);
ResultCode result = GetClockContext(thread, out SystemClockContext clockContext);
if (result == ResultCode.Success)
{
result = ResultCode.TimeMismatch;
if (currentTimePoint.ClockSourceId == clockContext.SteadyTimePoint.ClockSourceId)
{
posixTime = clockContext.Offset + currentTimePoint.TimePoint;
result = 0;
}
}
return result;
}
public ResultCode SetCurrentTime(KThread thread, long posixTime)
{
SteadyClockTimePoint currentTimePoint = _steadyClockCore.GetCurrentTimePoint(thread);
SystemClockContext clockContext = new SystemClockContext()
{
Offset = posixTime - currentTimePoint.TimePoint,
SteadyTimePoint = currentTimePoint
};
ResultCode result = SetClockContext(clockContext);
if (result == ResultCode.Success)
{
result = Flush(clockContext);
}
return result;
}
public virtual ResultCode GetClockContext(KThread thread, out SystemClockContext context)
{ {
context = _context; context = _context;
return ResultCode.Success; return ResultCode.Success;
} }
public virtual ResultCode SetSystemClockContext(SystemClockContext context) public virtual ResultCode SetClockContext(SystemClockContext context)
{ {
_context = context; _context = context;
return ResultCode.Success; return ResultCode.Success;
} }
public abstract ResultCode Flush(SystemClockContext context); protected abstract ResultCode Flush(SystemClockContext context);
public bool IsClockSetup(KThread thread) public ResultCode SetSystemClockContext(SystemClockContext context)
{ {
ResultCode result = GetSystemClockContext(thread, out SystemClockContext context); ResultCode result = SetClockContext(context);
if (result == ResultCode.Success) if (result == ResultCode.Success)
{ {
SteadyClockCore steadyClockCore = GetSteadyClockCore(); result = Flush(context);
}
SteadyClockTimePoint steadyClockTimePoint = steadyClockCore.GetCurrentTimePoint(thread); return result;
}
public bool IsInitialized()
{
return _isInitialized;
}
public void MarkInitialized()
{
_isInitialized = true;
}
public bool IsClockSetup(KThread thread)
{
ResultCode result = GetClockContext(thread, out SystemClockContext context);
if (result == ResultCode.Success)
{
SteadyClockTimePoint steadyClockTimePoint = _steadyClockCore.GetCurrentTimePoint(thread);
return steadyClockTimePoint.ClockSourceId == context.SteadyTimePoint.ClockSourceId; return steadyClockTimePoint.ClockSourceId == context.SteadyTimePoint.ClockSourceId;
} }

View file

@ -12,10 +12,10 @@ using System.Runtime.InteropServices;
namespace Ryujinx.HLE.HOS.Services.Time namespace Ryujinx.HLE.HOS.Services.Time
{ {
[Service("time:a", TimePermissions.Applet)] //[Service("time:a", TimePermissions.Admin)]
[Service("time:s", TimePermissions.System)] [Service("time:s", TimePermissions.System)]
[Service("time:u", TimePermissions.User)] //[Service("time:u", TimePermissions.User)]
[Service("time:su", TimePermissions.System)] // 9.0.0+ - TODO: Fix the permission. [Service("time:su", TimePermissions.System)]
class IStaticService : IpcService class IStaticService : IpcService
{ {
private TimePermissions _permissions; private TimePermissions _permissions;
@ -33,7 +33,7 @@ namespace Ryujinx.HLE.HOS.Services.Time
// GetStandardUserSystemClock() -> object<nn::timesrv::detail::service::ISystemClock> // GetStandardUserSystemClock() -> object<nn::timesrv::detail::service::ISystemClock>
public ResultCode GetStandardUserSystemClock(ServiceCtx context) public ResultCode GetStandardUserSystemClock(ServiceCtx context)
{ {
MakeObject(context, new ISystemClock(StandardUserSystemClockCore.Instance, (_permissions & TimePermissions.UserSystemClockWritableMask) != 0)); MakeObject(context, new ISystemClock(StandardUserSystemClockCore.Instance, (_permissions & TimePermissions.UserSystemClockWritableMask) != 0, (_permissions & TimePermissions.BypassUninitialized) != 0));
return ResultCode.Success; return ResultCode.Success;
} }
@ -42,7 +42,7 @@ namespace Ryujinx.HLE.HOS.Services.Time
// GetStandardNetworkSystemClock() -> object<nn::timesrv::detail::service::ISystemClock> // GetStandardNetworkSystemClock() -> object<nn::timesrv::detail::service::ISystemClock>
public ResultCode GetStandardNetworkSystemClock(ServiceCtx context) public ResultCode GetStandardNetworkSystemClock(ServiceCtx context)
{ {
MakeObject(context, new ISystemClock(StandardNetworkSystemClockCore.Instance, (_permissions & TimePermissions.NetworkSystemClockWritableMask) != 0)); MakeObject(context, new ISystemClock(StandardNetworkSystemClockCore.Instance, (_permissions & TimePermissions.NetworkSystemClockWritableMask) != 0, (_permissions & TimePermissions.BypassUninitialized) != 0));
return ResultCode.Success; return ResultCode.Success;
} }
@ -51,7 +51,7 @@ namespace Ryujinx.HLE.HOS.Services.Time
// GetStandardSteadyClock() -> object<nn::timesrv::detail::service::ISteadyClock> // GetStandardSteadyClock() -> object<nn::timesrv::detail::service::ISteadyClock>
public ResultCode GetStandardSteadyClock(ServiceCtx context) public ResultCode GetStandardSteadyClock(ServiceCtx context)
{ {
MakeObject(context, new ISteadyClock()); MakeObject(context, new ISteadyClock(StandardSteadyClockCore.Instance, (_permissions & TimePermissions.SteadyClockWritableMask) != 0, (_permissions & TimePermissions.BypassUninitialized) != 0));
return ResultCode.Success; return ResultCode.Success;
} }
@ -69,7 +69,7 @@ namespace Ryujinx.HLE.HOS.Services.Time
// GetStandardLocalSystemClock() -> object<nn::timesrv::detail::service::ISystemClock> // GetStandardLocalSystemClock() -> object<nn::timesrv::detail::service::ISystemClock>
public ResultCode GetStandardLocalSystemClock(ServiceCtx context) public ResultCode GetStandardLocalSystemClock(ServiceCtx context)
{ {
MakeObject(context, new ISystemClock(StandardLocalSystemClockCore.Instance, (_permissions & TimePermissions.LocalSystemClockWritableMask) != 0)); MakeObject(context, new ISystemClock(StandardLocalSystemClockCore.Instance, (_permissions & TimePermissions.LocalSystemClockWritableMask) != 0, (_permissions & TimePermissions.BypassUninitialized) != 0));
return ResultCode.Success; return ResultCode.Success;
} }
@ -78,7 +78,7 @@ namespace Ryujinx.HLE.HOS.Services.Time
// GetEphemeralNetworkSystemClock() -> object<nn::timesrv::detail::service::ISystemClock> // GetEphemeralNetworkSystemClock() -> object<nn::timesrv::detail::service::ISystemClock>
public ResultCode GetEphemeralNetworkSystemClock(ServiceCtx context) public ResultCode GetEphemeralNetworkSystemClock(ServiceCtx context)
{ {
MakeObject(context, new ISystemClock(StandardNetworkSystemClockCore.Instance, false)); MakeObject(context, new ISystemClock(StandardNetworkSystemClockCore.Instance, (_permissions & TimePermissions.NetworkSystemClockWritableMask) != 0, (_permissions & TimePermissions.BypassUninitialized) != 0));
return ResultCode.Success; return ResultCode.Success;
} }
@ -104,7 +104,14 @@ namespace Ryujinx.HLE.HOS.Services.Time
// IsStandardUserSystemClockAutomaticCorrectionEnabled() -> bool // IsStandardUserSystemClockAutomaticCorrectionEnabled() -> bool
public ResultCode IsStandardUserSystemClockAutomaticCorrectionEnabled(ServiceCtx context) public ResultCode IsStandardUserSystemClockAutomaticCorrectionEnabled(ServiceCtx context)
{ {
context.ResponseData.Write(StandardUserSystemClockCore.Instance.IsAutomaticCorrectionEnabled()); StandardUserSystemClockCore userClock = StandardUserSystemClockCore.Instance;
if (!userClock.IsInitialized())
{
return ResultCode.UninitializedClock;
}
context.ResponseData.Write(userClock.IsAutomaticCorrectionEnabled());
return ResultCode.Success; return ResultCode.Success;
} }
@ -113,6 +120,14 @@ namespace Ryujinx.HLE.HOS.Services.Time
// SetStandardUserSystemClockAutomaticCorrectionEnabled(b8) // SetStandardUserSystemClockAutomaticCorrectionEnabled(b8)
public ResultCode SetStandardUserSystemClockAutomaticCorrectionEnabled(ServiceCtx context) public ResultCode SetStandardUserSystemClockAutomaticCorrectionEnabled(ServiceCtx context)
{ {
SteadyClockCore steadyClock = StandardSteadyClockCore.Instance;
StandardUserSystemClockCore userClock = StandardUserSystemClockCore.Instance;
if (!userClock.IsInitialized() || !steadyClock.IsInitialized())
{
return ResultCode.UninitializedClock;
}
if ((_permissions & TimePermissions.UserSystemClockWritableMask) == 0) if ((_permissions & TimePermissions.UserSystemClockWritableMask) == 0)
{ {
return ResultCode.PermissionDenied; return ResultCode.PermissionDenied;
@ -136,8 +151,15 @@ namespace Ryujinx.HLE.HOS.Services.Time
// CalculateMonotonicSystemClockBaseTimePoint(nn::time::SystemClockContext) -> s64 // CalculateMonotonicSystemClockBaseTimePoint(nn::time::SystemClockContext) -> s64
public ResultCode CalculateMonotonicSystemClockBaseTimePoint(ServiceCtx context) public ResultCode CalculateMonotonicSystemClockBaseTimePoint(ServiceCtx context)
{ {
SteadyClockCore steadyClock = StandardSteadyClockCore.Instance;
if (!steadyClock.IsInitialized())
{
return ResultCode.UninitializedClock;
}
SystemClockContext otherContext = context.RequestData.ReadStruct<SystemClockContext>(); SystemClockContext otherContext = context.RequestData.ReadStruct<SystemClockContext>();
SteadyClockTimePoint currentTimePoint = StandardSteadyClockCore.Instance.GetCurrentTimePoint(context.Thread); SteadyClockTimePoint currentTimePoint = steadyClock.GetCurrentTimePoint(context.Thread);
ResultCode result = ResultCode.TimeMismatch; ResultCode result = ResultCode.TimeMismatch;
@ -160,11 +182,11 @@ namespace Ryujinx.HLE.HOS.Services.Time
{ {
byte type = context.RequestData.ReadByte(); byte type = context.RequestData.ReadByte();
ResultCode result = StandardUserSystemClockCore.Instance.GetSystemClockContext(context.Thread, out SystemClockContext userContext); ResultCode result = StandardUserSystemClockCore.Instance.GetClockContext(context.Thread, out SystemClockContext userContext);
if (result == ResultCode.Success) if (result == ResultCode.Success)
{ {
result = StandardNetworkSystemClockCore.Instance.GetSystemClockContext(context.Thread, out SystemClockContext networkContext); result = StandardNetworkSystemClockCore.Instance.GetClockContext(context.Thread, out SystemClockContext networkContext);
if (result == ResultCode.Success) if (result == ResultCode.Success)
{ {
@ -205,7 +227,6 @@ namespace Ryujinx.HLE.HOS.Services.Time
// CalculateStandardUserSystemClockDifferenceByUser(buffer<nn::time::sf::ClockSnapshot, 0x19>, buffer<nn::time::sf::ClockSnapshot, 0x19>) -> nn::TimeSpanType // CalculateStandardUserSystemClockDifferenceByUser(buffer<nn::time::sf::ClockSnapshot, 0x19>, buffer<nn::time::sf::ClockSnapshot, 0x19>) -> nn::TimeSpanType
public ResultCode CalculateStandardUserSystemClockDifferenceByUser(ServiceCtx context) public ResultCode CalculateStandardUserSystemClockDifferenceByUser(ServiceCtx context)
{ {
ClockSnapshot clockSnapshotA = ReadClockSnapshotFromBuffer(context, context.Request.ExchangeBuff[0]); ClockSnapshot clockSnapshotA = ReadClockSnapshotFromBuffer(context, context.Request.ExchangeBuff[0]);
ClockSnapshot clockSnapshotB = ReadClockSnapshotFromBuffer(context, context.Request.ExchangeBuff[1]); ClockSnapshot clockSnapshotB = ReadClockSnapshotFromBuffer(context, context.Request.ExchangeBuff[1]);
TimeSpanType difference = TimeSpanType.FromSeconds(clockSnapshotB.UserContext.Offset - clockSnapshotA.UserContext.Offset); TimeSpanType difference = TimeSpanType.FromSeconds(clockSnapshotB.UserContext.Offset - clockSnapshotA.UserContext.Offset);

View file

@ -9,6 +9,7 @@
PermissionDenied = (1 << ErrorCodeShift) | ModuleId, PermissionDenied = (1 << ErrorCodeShift) | ModuleId,
TimeMismatch = (102 << ErrorCodeShift) | ModuleId, TimeMismatch = (102 << ErrorCodeShift) | ModuleId,
UninitializedClock = (103 << ErrorCodeShift) | ModuleId,
TimeNotFound = (200 << ErrorCodeShift) | ModuleId, TimeNotFound = (200 << ErrorCodeShift) | ModuleId,
Overflow = (201 << ErrorCodeShift) | ModuleId, Overflow = (201 << ErrorCodeShift) | ModuleId,
LocationNameTooLong = (801 << ErrorCodeShift) | ModuleId, LocationNameTooLong = (801 << ErrorCodeShift) | ModuleId,

View file

@ -5,11 +5,27 @@ namespace Ryujinx.HLE.HOS.Services.Time.StaticService
{ {
class ISteadyClock : IpcService class ISteadyClock : IpcService
{ {
private SteadyClockCore _steadyClock;
private bool _writePermission;
private bool _bypassUninitializedClock;
public ISteadyClock(SteadyClockCore steadyClock, bool writePermission, bool bypassUninitializedClock)
{
_steadyClock = steadyClock;
_writePermission = writePermission;
_bypassUninitializedClock = bypassUninitializedClock;
}
[Command(0)] [Command(0)]
// GetCurrentTimePoint() -> nn::time::SteadyClockTimePoint // GetCurrentTimePoint() -> nn::time::SteadyClockTimePoint
public ResultCode GetCurrentTimePoint(ServiceCtx context) public ResultCode GetCurrentTimePoint(ServiceCtx context)
{ {
SteadyClockTimePoint currentTimePoint = StandardSteadyClockCore.Instance.GetCurrentTimePoint(context.Thread); if (!_bypassUninitializedClock && !_steadyClock.IsInitialized())
{
return ResultCode.UninitializedClock;
}
SteadyClockTimePoint currentTimePoint = _steadyClock.GetCurrentTimePoint(context.Thread);
context.ResponseData.WriteStruct(currentTimePoint); context.ResponseData.WriteStruct(currentTimePoint);
@ -20,7 +36,12 @@ namespace Ryujinx.HLE.HOS.Services.Time.StaticService
// GetTestOffset() -> nn::TimeSpanType // GetTestOffset() -> nn::TimeSpanType
public ResultCode GetTestOffset(ServiceCtx context) public ResultCode GetTestOffset(ServiceCtx context)
{ {
context.ResponseData.WriteStruct(StandardSteadyClockCore.Instance.GetTestOffset()); if (!_bypassUninitializedClock && !_steadyClock.IsInitialized())
{
return ResultCode.UninitializedClock;
}
context.ResponseData.WriteStruct(_steadyClock.GetTestOffset());
return ResultCode.Success; return ResultCode.Success;
} }
@ -29,18 +50,33 @@ namespace Ryujinx.HLE.HOS.Services.Time.StaticService
// SetTestOffset(nn::TimeSpanType) // SetTestOffset(nn::TimeSpanType)
public ResultCode SetTestOffset(ServiceCtx context) public ResultCode SetTestOffset(ServiceCtx context)
{ {
if (!_writePermission)
{
return ResultCode.PermissionDenied;
}
if (!_bypassUninitializedClock && !_steadyClock.IsInitialized())
{
return ResultCode.UninitializedClock;
}
TimeSpanType testOffset = context.RequestData.ReadStruct<TimeSpanType>(); TimeSpanType testOffset = context.RequestData.ReadStruct<TimeSpanType>();
StandardSteadyClockCore.Instance.SetTestOffset(testOffset); _steadyClock.SetTestOffset(testOffset);
return 0; return ResultCode.Success;
} }
[Command(100)] // 2.0.0+ [Command(100)] // 2.0.0+
// GetRtcValue() -> u64 // GetRtcValue() -> u64
public ResultCode GetRtcValue(ServiceCtx context) public ResultCode GetRtcValue(ServiceCtx context)
{ {
ResultCode result = StandardSteadyClockCore.Instance.GetRtcValue(out ulong rtcValue); if (!_bypassUninitializedClock && !_steadyClock.IsInitialized())
{
return ResultCode.UninitializedClock;
}
ResultCode result = _steadyClock.GetRtcValue(out ulong rtcValue);
if (result == ResultCode.Success) if (result == ResultCode.Success)
{ {
@ -54,7 +90,12 @@ namespace Ryujinx.HLE.HOS.Services.Time.StaticService
// IsRtcResetDetected() -> bool // IsRtcResetDetected() -> bool
public ResultCode IsRtcResetDetected(ServiceCtx context) public ResultCode IsRtcResetDetected(ServiceCtx context)
{ {
context.ResponseData.Write(StandardSteadyClockCore.Instance.IsRtcResetDetected()); if (!_bypassUninitializedClock && !_steadyClock.IsInitialized())
{
return ResultCode.UninitializedClock;
}
context.ResponseData.Write(_steadyClock.IsRtcResetDetected());
return ResultCode.Success; return ResultCode.Success;
} }
@ -63,7 +104,12 @@ namespace Ryujinx.HLE.HOS.Services.Time.StaticService
// GetSetupResultValue() -> u32 // GetSetupResultValue() -> u32
public ResultCode GetSetupResultValue(ServiceCtx context) public ResultCode GetSetupResultValue(ServiceCtx context)
{ {
context.ResponseData.Write((uint)StandardSteadyClockCore.Instance.GetSetupResultValue()); if (!_bypassUninitializedClock && !_steadyClock.IsInitialized())
{
return ResultCode.UninitializedClock;
}
context.ResponseData.Write((uint)_steadyClock.GetSetupResultValue());
return ResultCode.Success; return ResultCode.Success;
} }
@ -72,7 +118,12 @@ namespace Ryujinx.HLE.HOS.Services.Time.StaticService
// GetInternalOffset() -> nn::TimeSpanType // GetInternalOffset() -> nn::TimeSpanType
public ResultCode GetInternalOffset(ServiceCtx context) public ResultCode GetInternalOffset(ServiceCtx context)
{ {
context.ResponseData.WriteStruct(StandardSteadyClockCore.Instance.GetInternalOffset()); if (!_bypassUninitializedClock && !_steadyClock.IsInitialized())
{
return ResultCode.UninitializedClock;
}
context.ResponseData.WriteStruct(_steadyClock.GetInternalOffset());
return ResultCode.Success; return ResultCode.Success;
} }
@ -81,9 +132,19 @@ namespace Ryujinx.HLE.HOS.Services.Time.StaticService
// SetInternalOffset(nn::TimeSpanType) // SetInternalOffset(nn::TimeSpanType)
public ResultCode SetInternalOffset(ServiceCtx context) public ResultCode SetInternalOffset(ServiceCtx context)
{ {
if (!_writePermission)
{
return ResultCode.PermissionDenied;
}
if (!_bypassUninitializedClock && !_steadyClock.IsInitialized())
{
return ResultCode.UninitializedClock;
}
TimeSpanType internalOffset = context.RequestData.ReadStruct<TimeSpanType>(); TimeSpanType internalOffset = context.RequestData.ReadStruct<TimeSpanType>();
StandardSteadyClockCore.Instance.SetInternalOffset(internalOffset); _steadyClock.SetInternalOffset(internalOffset);
return ResultCode.Success; return ResultCode.Success;
} }

View file

@ -7,34 +7,29 @@ namespace Ryujinx.HLE.HOS.Services.Time.StaticService
{ {
private SystemClockCore _clockCore; private SystemClockCore _clockCore;
private bool _writePermission; private bool _writePermission;
private bool _bypassUninitializedClock;
public ISystemClock(SystemClockCore clockCore, bool writePermission) public ISystemClock(SystemClockCore clockCore, bool writePermission, bool bypassUninitializedCloc)
{ {
_clockCore = clockCore; _clockCore = clockCore;
_writePermission = writePermission; _writePermission = writePermission;
_bypassUninitializedClock = bypassUninitializedCloc;
} }
[Command(0)] [Command(0)]
// GetCurrentTime() -> nn::time::PosixTime // GetCurrentTime() -> nn::time::PosixTime
public ResultCode GetCurrentTime(ServiceCtx context) public ResultCode GetCurrentTime(ServiceCtx context)
{ {
SteadyClockCore steadyClockCore = _clockCore.GetSteadyClockCore(); if (!_bypassUninitializedClock && !_clockCore.IsInitialized())
SteadyClockTimePoint currentTimePoint = steadyClockCore.GetCurrentTimePoint(context.Thread); {
return ResultCode.UninitializedClock;
}
ResultCode result = _clockCore.GetSystemClockContext(context.Thread, out SystemClockContext clockContext); ResultCode result = _clockCore.GetCurrentTime(context.Thread, out long posixTime);
if (result == ResultCode.Success) if (result == ResultCode.Success)
{ {
result = ResultCode.TimeMismatch; context.ResponseData.Write(posixTime);
if (currentTimePoint.ClockSourceId == clockContext.SteadyTimePoint.ClockSourceId)
{
long posixTime = clockContext.Offset + currentTimePoint.TimePoint;
context.ResponseData.Write(posixTime);
result = 0;
}
} }
return result; return result;
@ -49,31 +44,26 @@ namespace Ryujinx.HLE.HOS.Services.Time.StaticService
return ResultCode.PermissionDenied; return ResultCode.PermissionDenied;
} }
long posixTime = context.RequestData.ReadInt64(); if (!_bypassUninitializedClock && !_clockCore.IsInitialized())
SteadyClockCore steadyClockCore = _clockCore.GetSteadyClockCore();
SteadyClockTimePoint currentTimePoint = steadyClockCore.GetCurrentTimePoint(context.Thread);
SystemClockContext clockContext = new SystemClockContext()
{ {
Offset = posixTime - currentTimePoint.TimePoint, return ResultCode.UninitializedClock;
SteadyTimePoint = currentTimePoint
};
ResultCode result = _clockCore.SetSystemClockContext(clockContext);
if (result == ResultCode.Success)
{
result = _clockCore.Flush(clockContext);
} }
return result; long posixTime = context.RequestData.ReadInt64();
return _clockCore.SetCurrentTime(context.Thread, posixTime);
} }
[Command(2)] [Command(2)]
// GetSystemClockContext() -> nn::time::SystemClockContext // GetClockContext() -> nn::time::SystemClockContext
public ResultCode GetSystemClockContext(ServiceCtx context) public ResultCode GetSystemClockContext(ServiceCtx context)
{ {
ResultCode result = _clockCore.GetSystemClockContext(context.Thread, out SystemClockContext clockContext); if (!_bypassUninitializedClock && !_clockCore.IsInitialized())
{
return ResultCode.UninitializedClock;
}
ResultCode result = _clockCore.GetClockContext(context.Thread, out SystemClockContext clockContext);
if (result == ResultCode.Success) if (result == ResultCode.Success)
{ {
@ -84,7 +74,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.StaticService
} }
[Command(3)] [Command(3)]
// SetSystemClockContext(nn::time::SystemClockContext) // SetClockContext(nn::time::SystemClockContext)
public ResultCode SetSystemClockContext(ServiceCtx context) public ResultCode SetSystemClockContext(ServiceCtx context)
{ {
if (!_writePermission) if (!_writePermission)
@ -92,15 +82,15 @@ namespace Ryujinx.HLE.HOS.Services.Time.StaticService
return ResultCode.PermissionDenied; return ResultCode.PermissionDenied;
} }
if (!_bypassUninitializedClock && !_clockCore.IsInitialized())
{
return ResultCode.UninitializedClock;
}
SystemClockContext clockContext = context.RequestData.ReadStruct<SystemClockContext>(); SystemClockContext clockContext = context.RequestData.ReadStruct<SystemClockContext>();
ResultCode result = _clockCore.SetSystemClockContext(clockContext); ResultCode result = _clockCore.SetSystemClockContext(clockContext);
if (result == ResultCode.Success)
{
result = _clockCore.Flush(clockContext);
}
return result; return result;
} }
} }

View file

@ -8,10 +8,15 @@ namespace Ryujinx.HLE.HOS.Services.Time
LocalSystemClockWritableMask = 0x1, LocalSystemClockWritableMask = 0x1,
UserSystemClockWritableMask = 0x2, UserSystemClockWritableMask = 0x2,
NetworkSystemClockWritableMask = 0x4, NetworkSystemClockWritableMask = 0x4,
UnknownPermissionMask = 0x8, TimeZoneWritableMask = 0x8,
SteadyClockWritableMask = 0x10,
BypassUninitialized = 0x20,
User = 0, User = 0,
Applet = LocalSystemClockWritableMask | UserSystemClockWritableMask | UnknownPermissionMask, Admin = LocalSystemClockWritableMask | UserSystemClockWritableMask | TimeZoneWritableMask,
System = NetworkSystemClockWritableMask System = NetworkSystemClockWritableMask,
SystemUpdate = BypassUninitialized,
Repair = SteadyClockWritableMask,
Manufacture = LocalSystemClockWritableMask | UserSystemClockWritableMask | NetworkSystemClockWritableMask | TimeZoneWritableMask | SteadyClockWritableMask
} }
} }