diff --git a/Ryujinx.HLE/HOS/Services/Time/Clock/EphemeralNetworkSystemClockCore.cs b/Ryujinx.HLE/HOS/Services/Time/Clock/EphemeralNetworkSystemClockCore.cs index 8e9073a40a..06a003ff75 100644 --- a/Ryujinx.HLE/HOS/Services/Time/Clock/EphemeralNetworkSystemClockCore.cs +++ b/Ryujinx.HLE/HOS/Services/Time/Clock/EphemeralNetworkSystemClockCore.cs @@ -19,7 +19,7 @@ public EphemeralNetworkSystemClockCore(SteadyClockCore steadyClockCore) : base(steadyClockCore) { } - public override ResultCode Flush(SystemClockContext context) + protected override ResultCode Flush(SystemClockContext context) { return ResultCode.Success; } diff --git a/Ryujinx.HLE/HOS/Services/Time/Clock/StandardLocalSystemClockCore.cs b/Ryujinx.HLE/HOS/Services/Time/Clock/StandardLocalSystemClockCore.cs index a172797608..6ca818af8d 100644 --- a/Ryujinx.HLE/HOS/Services/Time/Clock/StandardLocalSystemClockCore.cs +++ b/Ryujinx.HLE/HOS/Services/Time/Clock/StandardLocalSystemClockCore.cs @@ -19,7 +19,7 @@ public StandardLocalSystemClockCore(StandardSteadyClockCore steadyClockCore) : base(steadyClockCore) {} - public override ResultCode Flush(SystemClockContext context) + protected override ResultCode Flush(SystemClockContext context) { // TODO: set:sys SetUserSystemClockContext diff --git a/Ryujinx.HLE/HOS/Services/Time/Clock/StandardNetworkSystemClockCore.cs b/Ryujinx.HLE/HOS/Services/Time/Clock/StandardNetworkSystemClockCore.cs index cc21dd9a5f..9436d38f9e 100644 --- a/Ryujinx.HLE/HOS/Services/Time/Clock/StandardNetworkSystemClockCore.cs +++ b/Ryujinx.HLE/HOS/Services/Time/Clock/StandardNetworkSystemClockCore.cs @@ -26,7 +26,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock _standardNetworkClockSufficientAccuracy = new TimeSpanType(0); } - public override ResultCode Flush(SystemClockContext context) + protected override ResultCode Flush(SystemClockContext context) { // TODO: set:sys SetNetworkSystemClockContext @@ -40,7 +40,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock 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) { diff --git a/Ryujinx.HLE/HOS/Services/Time/Clock/StandardSteadyClockCore.cs b/Ryujinx.HLE/HOS/Services/Time/Clock/StandardSteadyClockCore.cs index 1bc5bee784..850dfeaae9 100644 --- a/Ryujinx.HLE/HOS/Services/Time/Clock/StandardSteadyClockCore.cs +++ b/Ryujinx.HLE/HOS/Services/Time/Clock/StandardSteadyClockCore.cs @@ -5,11 +5,12 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock { class StandardSteadyClockCore : SteadyClockCore { - private long _setupValue; - private ResultCode _setupResultCode; - private bool _isRtcResetDetected; + private TimeSpanType _setupValue; + // TODO: move this to glue when we will have psc fully done + //private ResultCode _setupResultCode; private TimeSpanType _testOffset; private TimeSpanType _internalOffset; + private TimeSpanType _cachedRawTimePoint; private static StandardSteadyClockCore _instance; @@ -28,22 +29,20 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock private StandardSteadyClockCore() { - _testOffset = new TimeSpanType(0); - _internalOffset = new TimeSpanType(0); + _setupValue = new TimeSpanType(0); + _testOffset = new TimeSpanType(0); + _internalOffset = new TimeSpanType(0); + _cachedRawTimePoint = new TimeSpanType(0); } public override SteadyClockTimePoint GetTimePoint(KThread thread) { SteadyClockTimePoint result = new SteadyClockTimePoint { - TimePoint = 0, + TimePoint = GetCurrentRawTimePoint(thread).ToSeconds(), ClockSourceId = GetClockSourceId() }; - TimeSpanType ticksTimeSpan = TimeSpanType.FromTicks(thread.Context.CntpctEl0, thread.Context.CntfrqEl0); - - result.TimePoint = _setupValue + ticksTimeSpan.ToSeconds(); - return result; } @@ -57,16 +56,6 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock _testOffset = testOffset; } - public override ResultCode GetRtcValue(out ulong rtcValue) - { - return (ResultCode)IRtcManager.GetExternalRtcValue(out rtcValue); - } - - public bool IsRtcResetDetected() - { - return _isRtcResetDetected; - } - public override TimeSpanType GetInternalOffset() { return _internalOffset; @@ -77,12 +66,24 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock _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; @@ -94,7 +95,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock if (result == ResultCode.Success) { - _setupValue = (long)rtcValue; + _setupValue = TimeSpanType.FromSeconds((long)rtcValue); break; } @@ -102,6 +103,6 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock } _setupResultCode = result; - } + }*/ } } diff --git a/Ryujinx.HLE/HOS/Services/Time/Clock/StandardUserSystemClockCore.cs b/Ryujinx.HLE/HOS/Services/Time/Clock/StandardUserSystemClockCore.cs index c98b0064b6..527b9ba049 100644 --- a/Ryujinx.HLE/HOS/Services/Time/Clock/StandardUserSystemClockCore.cs +++ b/Ryujinx.HLE/HOS/Services/Time/Clock/StandardUserSystemClockCore.cs @@ -30,12 +30,12 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock _autoCorrectionEnabled = false; } - public override ResultCode Flush(SystemClockContext context) + protected override ResultCode Flush(SystemClockContext context) { 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); @@ -43,13 +43,13 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock if (result == ResultCode.Success) { - return _localSystemClockCore.GetSystemClockContext(thread, out context); + return _localSystemClockCore.GetClockContext(thread, out context); } return result; } - public override ResultCode SetSystemClockContext(SystemClockContext context) + public override ResultCode SetClockContext(SystemClockContext context) { return ResultCode.NotImplemented; } @@ -60,11 +60,11 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock if (_autoCorrectionEnabled != autoCorrectionEnabled && _networkSystemClockCore.IsClockSetup(thread)) { - result = _networkSystemClockCore.GetSystemClockContext(thread, out SystemClockContext context); + result = _networkSystemClockCore.GetClockContext(thread, out SystemClockContext context); if (result == ResultCode.Success) { - _localSystemClockCore.SetSystemClockContext(context); + _localSystemClockCore.SetClockContext(context); } } diff --git a/Ryujinx.HLE/HOS/Services/Time/Clock/SteadyClockCore.cs b/Ryujinx.HLE/HOS/Services/Time/Clock/SteadyClockCore.cs index 54d9accf4f..2f54f96db1 100644 --- a/Ryujinx.HLE/HOS/Services/Time/Clock/SteadyClockCore.cs +++ b/Ryujinx.HLE/HOS/Services/Time/Clock/SteadyClockCore.cs @@ -7,10 +7,14 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock abstract class SteadyClockCore { private UInt128 _clockSourceId; + private bool _isRtcResetDetected; + private bool _isInitialized; public SteadyClockCore() { - _clockSourceId = new UInt128(Guid.NewGuid().ToByteArray()); + _clockSourceId = new UInt128(Guid.NewGuid().ToByteArray()); + _isRtcResetDetected = false; + _isInitialized = false; } public UInt128 GetClockSourceId() @@ -32,9 +36,14 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock 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() @@ -49,6 +58,13 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock throw new NotImplementedException(); } + public virtual TimeSpanType GetCurrentRawTimePoint(KThread thread) + { + SteadyClockTimePoint timePoint = GetTimePoint(thread); + + return TimeSpanType.FromSeconds(timePoint.TimePoint); + } + public SteadyClockTimePoint GetCurrentTimePoint(KThread thread) { SteadyClockTimePoint result = GetTimePoint(thread); @@ -58,5 +74,15 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock return result; } + + public bool IsInitialized() + { + return _isInitialized; + } + + public void MarkInitialized() + { + _isInitialized = true; + } } } diff --git a/Ryujinx.HLE/HOS/Services/Time/Clock/SystemClockCore.cs b/Ryujinx.HLE/HOS/Services/Time/Clock/SystemClockCore.cs index 52f3c9083c..39f5180bd7 100644 --- a/Ryujinx.HLE/HOS/Services/Time/Clock/SystemClockCore.cs +++ b/Ryujinx.HLE/HOS/Services/Time/Clock/SystemClockCore.cs @@ -6,11 +6,13 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock { private SteadyClockCore _steadyClockCore; private SystemClockContext _context; + private bool _isInitialized; public SystemClockCore(SteadyClockCore steadyClockCore) { _steadyClockCore = steadyClockCore; _context = new SystemClockContext(); + _isInitialized = false; _context.SteadyTimePoint.ClockSourceId = steadyClockCore.GetClockSourceId(); } @@ -20,31 +22,94 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock 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; return ResultCode.Success; } - public virtual ResultCode SetSystemClockContext(SystemClockContext context) + public virtual ResultCode SetClockContext(SystemClockContext context) { _context = context; 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) { - 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; } diff --git a/Ryujinx.HLE/HOS/Services/Time/IStaticService.cs b/Ryujinx.HLE/HOS/Services/Time/IStaticService.cs index e661db2745..b3dc60dd0c 100644 --- a/Ryujinx.HLE/HOS/Services/Time/IStaticService.cs +++ b/Ryujinx.HLE/HOS/Services/Time/IStaticService.cs @@ -12,10 +12,10 @@ using System.Runtime.InteropServices; namespace Ryujinx.HLE.HOS.Services.Time { - [Service("time:a", TimePermissions.Applet)] + //[Service("time:a", TimePermissions.Admin)] [Service("time:s", TimePermissions.System)] - [Service("time:u", TimePermissions.User)] - [Service("time:su", TimePermissions.System)] // 9.0.0+ - TODO: Fix the permission. + //[Service("time:u", TimePermissions.User)] + [Service("time:su", TimePermissions.System)] class IStaticService : IpcService { private TimePermissions _permissions; @@ -33,7 +33,7 @@ namespace Ryujinx.HLE.HOS.Services.Time // GetStandardUserSystemClock() -> object 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; } @@ -42,7 +42,7 @@ namespace Ryujinx.HLE.HOS.Services.Time // GetStandardNetworkSystemClock() -> object 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; } @@ -51,7 +51,7 @@ namespace Ryujinx.HLE.HOS.Services.Time // GetStandardSteadyClock() -> object 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; } @@ -69,7 +69,7 @@ namespace Ryujinx.HLE.HOS.Services.Time // GetStandardLocalSystemClock() -> object 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; } @@ -78,7 +78,7 @@ namespace Ryujinx.HLE.HOS.Services.Time // GetEphemeralNetworkSystemClock() -> object 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; } @@ -104,7 +104,14 @@ namespace Ryujinx.HLE.HOS.Services.Time // IsStandardUserSystemClockAutomaticCorrectionEnabled() -> bool 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; } @@ -113,6 +120,14 @@ namespace Ryujinx.HLE.HOS.Services.Time // SetStandardUserSystemClockAutomaticCorrectionEnabled(b8) 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) { return ResultCode.PermissionDenied; @@ -136,8 +151,15 @@ namespace Ryujinx.HLE.HOS.Services.Time // CalculateMonotonicSystemClockBaseTimePoint(nn::time::SystemClockContext) -> s64 public ResultCode CalculateMonotonicSystemClockBaseTimePoint(ServiceCtx context) { + SteadyClockCore steadyClock = StandardSteadyClockCore.Instance; + + if (!steadyClock.IsInitialized()) + { + return ResultCode.UninitializedClock; + } + SystemClockContext otherContext = context.RequestData.ReadStruct(); - SteadyClockTimePoint currentTimePoint = StandardSteadyClockCore.Instance.GetCurrentTimePoint(context.Thread); + SteadyClockTimePoint currentTimePoint = steadyClock.GetCurrentTimePoint(context.Thread); ResultCode result = ResultCode.TimeMismatch; @@ -160,11 +182,11 @@ namespace Ryujinx.HLE.HOS.Services.Time { 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) { - result = StandardNetworkSystemClockCore.Instance.GetSystemClockContext(context.Thread, out SystemClockContext networkContext); + result = StandardNetworkSystemClockCore.Instance.GetClockContext(context.Thread, out SystemClockContext networkContext); if (result == ResultCode.Success) { @@ -205,7 +227,6 @@ namespace Ryujinx.HLE.HOS.Services.Time // CalculateStandardUserSystemClockDifferenceByUser(buffer, buffer) -> nn::TimeSpanType public ResultCode CalculateStandardUserSystemClockDifferenceByUser(ServiceCtx context) { - ClockSnapshot clockSnapshotA = ReadClockSnapshotFromBuffer(context, context.Request.ExchangeBuff[0]); ClockSnapshot clockSnapshotB = ReadClockSnapshotFromBuffer(context, context.Request.ExchangeBuff[1]); TimeSpanType difference = TimeSpanType.FromSeconds(clockSnapshotB.UserContext.Offset - clockSnapshotA.UserContext.Offset); diff --git a/Ryujinx.HLE/HOS/Services/Time/ResultCode.cs b/Ryujinx.HLE/HOS/Services/Time/ResultCode.cs index ed7130f364..1ef895c258 100644 --- a/Ryujinx.HLE/HOS/Services/Time/ResultCode.cs +++ b/Ryujinx.HLE/HOS/Services/Time/ResultCode.cs @@ -9,6 +9,7 @@ PermissionDenied = (1 << ErrorCodeShift) | ModuleId, TimeMismatch = (102 << ErrorCodeShift) | ModuleId, + UninitializedClock = (103 << ErrorCodeShift) | ModuleId, TimeNotFound = (200 << ErrorCodeShift) | ModuleId, Overflow = (201 << ErrorCodeShift) | ModuleId, LocationNameTooLong = (801 << ErrorCodeShift) | ModuleId, diff --git a/Ryujinx.HLE/HOS/Services/Time/StaticService/ISteadyClock.cs b/Ryujinx.HLE/HOS/Services/Time/StaticService/ISteadyClock.cs index 02b7e27ab1..c830bb4b80 100644 --- a/Ryujinx.HLE/HOS/Services/Time/StaticService/ISteadyClock.cs +++ b/Ryujinx.HLE/HOS/Services/Time/StaticService/ISteadyClock.cs @@ -5,11 +5,27 @@ namespace Ryujinx.HLE.HOS.Services.Time.StaticService { 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)] // GetCurrentTimePoint() -> nn::time::SteadyClockTimePoint 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); @@ -20,7 +36,12 @@ namespace Ryujinx.HLE.HOS.Services.Time.StaticService // GetTestOffset() -> nn::TimeSpanType 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; } @@ -29,18 +50,33 @@ namespace Ryujinx.HLE.HOS.Services.Time.StaticService // SetTestOffset(nn::TimeSpanType) public ResultCode SetTestOffset(ServiceCtx context) { + if (!_writePermission) + { + return ResultCode.PermissionDenied; + } + + if (!_bypassUninitializedClock && !_steadyClock.IsInitialized()) + { + return ResultCode.UninitializedClock; + } + TimeSpanType testOffset = context.RequestData.ReadStruct(); - StandardSteadyClockCore.Instance.SetTestOffset(testOffset); + _steadyClock.SetTestOffset(testOffset); - return 0; + return ResultCode.Success; } [Command(100)] // 2.0.0+ // GetRtcValue() -> u64 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) { @@ -54,7 +90,12 @@ namespace Ryujinx.HLE.HOS.Services.Time.StaticService // IsRtcResetDetected() -> bool 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; } @@ -63,7 +104,12 @@ namespace Ryujinx.HLE.HOS.Services.Time.StaticService // GetSetupResultValue() -> u32 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; } @@ -72,7 +118,12 @@ namespace Ryujinx.HLE.HOS.Services.Time.StaticService // GetInternalOffset() -> nn::TimeSpanType 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; } @@ -81,9 +132,19 @@ namespace Ryujinx.HLE.HOS.Services.Time.StaticService // SetInternalOffset(nn::TimeSpanType) public ResultCode SetInternalOffset(ServiceCtx context) { + if (!_writePermission) + { + return ResultCode.PermissionDenied; + } + + if (!_bypassUninitializedClock && !_steadyClock.IsInitialized()) + { + return ResultCode.UninitializedClock; + } + TimeSpanType internalOffset = context.RequestData.ReadStruct(); - StandardSteadyClockCore.Instance.SetInternalOffset(internalOffset); + _steadyClock.SetInternalOffset(internalOffset); return ResultCode.Success; } diff --git a/Ryujinx.HLE/HOS/Services/Time/StaticService/ISystemClock.cs b/Ryujinx.HLE/HOS/Services/Time/StaticService/ISystemClock.cs index 0d86617759..5ab2717852 100644 --- a/Ryujinx.HLE/HOS/Services/Time/StaticService/ISystemClock.cs +++ b/Ryujinx.HLE/HOS/Services/Time/StaticService/ISystemClock.cs @@ -7,34 +7,29 @@ namespace Ryujinx.HLE.HOS.Services.Time.StaticService { private SystemClockCore _clockCore; private bool _writePermission; + private bool _bypassUninitializedClock; - public ISystemClock(SystemClockCore clockCore, bool writePermission) + public ISystemClock(SystemClockCore clockCore, bool writePermission, bool bypassUninitializedCloc) { - _clockCore = clockCore; - _writePermission = writePermission; + _clockCore = clockCore; + _writePermission = writePermission; + _bypassUninitializedClock = bypassUninitializedCloc; } [Command(0)] // GetCurrentTime() -> nn::time::PosixTime public ResultCode GetCurrentTime(ServiceCtx context) { - SteadyClockCore steadyClockCore = _clockCore.GetSteadyClockCore(); - SteadyClockTimePoint currentTimePoint = steadyClockCore.GetCurrentTimePoint(context.Thread); + if (!_bypassUninitializedClock && !_clockCore.IsInitialized()) + { + 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) { - result = ResultCode.TimeMismatch; - - if (currentTimePoint.ClockSourceId == clockContext.SteadyTimePoint.ClockSourceId) - { - long posixTime = clockContext.Offset + currentTimePoint.TimePoint; - - context.ResponseData.Write(posixTime); - - result = 0; - } + context.ResponseData.Write(posixTime); } return result; @@ -49,31 +44,26 @@ namespace Ryujinx.HLE.HOS.Services.Time.StaticService return ResultCode.PermissionDenied; } - long posixTime = context.RequestData.ReadInt64(); - SteadyClockCore steadyClockCore = _clockCore.GetSteadyClockCore(); - SteadyClockTimePoint currentTimePoint = steadyClockCore.GetCurrentTimePoint(context.Thread); - - SystemClockContext clockContext = new SystemClockContext() + if (!_bypassUninitializedClock && !_clockCore.IsInitialized()) { - Offset = posixTime - currentTimePoint.TimePoint, - SteadyTimePoint = currentTimePoint - }; - - ResultCode result = _clockCore.SetSystemClockContext(clockContext); - - if (result == ResultCode.Success) - { - result = _clockCore.Flush(clockContext); + return ResultCode.UninitializedClock; } - return result; + long posixTime = context.RequestData.ReadInt64(); + + return _clockCore.SetCurrentTime(context.Thread, posixTime); } [Command(2)] - // GetSystemClockContext() -> nn::time::SystemClockContext + // GetClockContext() -> nn::time::SystemClockContext 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) { @@ -84,7 +74,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.StaticService } [Command(3)] - // SetSystemClockContext(nn::time::SystemClockContext) + // SetClockContext(nn::time::SystemClockContext) public ResultCode SetSystemClockContext(ServiceCtx context) { if (!_writePermission) @@ -92,15 +82,15 @@ namespace Ryujinx.HLE.HOS.Services.Time.StaticService return ResultCode.PermissionDenied; } + if (!_bypassUninitializedClock && !_clockCore.IsInitialized()) + { + return ResultCode.UninitializedClock; + } + SystemClockContext clockContext = context.RequestData.ReadStruct(); ResultCode result = _clockCore.SetSystemClockContext(clockContext); - if (result == ResultCode.Success) - { - result = _clockCore.Flush(clockContext); - } - return result; } } diff --git a/Ryujinx.HLE/HOS/Services/Time/Types/TimePermissions.cs b/Ryujinx.HLE/HOS/Services/Time/Types/TimePermissions.cs index 823c828888..3fcd3a1444 100644 --- a/Ryujinx.HLE/HOS/Services/Time/Types/TimePermissions.cs +++ b/Ryujinx.HLE/HOS/Services/Time/Types/TimePermissions.cs @@ -8,10 +8,15 @@ namespace Ryujinx.HLE.HOS.Services.Time LocalSystemClockWritableMask = 0x1, UserSystemClockWritableMask = 0x2, NetworkSystemClockWritableMask = 0x4, - UnknownPermissionMask = 0x8, + TimeZoneWritableMask = 0x8, + SteadyClockWritableMask = 0x10, + BypassUninitialized = 0x20, - User = 0, - Applet = LocalSystemClockWritableMask | UserSystemClockWritableMask | UnknownPermissionMask, - System = NetworkSystemClockWritableMask + User = 0, + Admin = LocalSystemClockWritableMask | UserSystemClockWritableMask | TimeZoneWritableMask, + System = NetworkSystemClockWritableMask, + SystemUpdate = BypassUninitialized, + Repair = SteadyClockWritableMask, + Manufacture = LocalSystemClockWritableMask | UserSystemClockWritableMask | NetworkSystemClockWritableMask | TimeZoneWritableMask | SteadyClockWritableMask } }