diff options
| author | Thomas Guillemard <me@thog.eu> | 2019-07-14 22:50:11 +0200 |
|---|---|---|
| committer | Ac_K <Acoustik666@gmail.com> | 2019-07-14 22:50:11 +0200 |
| commit | 97d0c6242368f443c50395b2fa9d99a59f1df1e8 (patch) | |
| tree | 95fe1df8cc70f578f4c595feca6d2c253e4ad366 /Ryujinx.HLE/HOS/Services/Time/Clock | |
| parent | 4ad3936afd4ca393a05b330e3848958e9598e910 (diff) | |
Accurately implement steady & system clocks (#732)
* Improve SteadyClock implementation accuracy
* Rewrite system clocks to be accurate
* Implement IStaticService 100 & 101
* Add time:* permissions
* Address comments
* Realign TimePermissions definitions
* Address gdk's comments
* Fix after rebase
Diffstat (limited to 'Ryujinx.HLE/HOS/Services/Time/Clock')
6 files changed, 371 insertions, 0 deletions
diff --git a/Ryujinx.HLE/HOS/Services/Time/Clock/ClockTypes.cs b/Ryujinx.HLE/HOS/Services/Time/Clock/ClockTypes.cs new file mode 100644 index 00000000..1e527c00 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Time/Clock/ClockTypes.cs @@ -0,0 +1,40 @@ +using Ryujinx.HLE.Utilities; +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Time.Clock +{ + [StructLayout(LayoutKind.Sequential)] + struct TimeSpanType + { + public ulong NanoSeconds; + + public TimeSpanType(ulong nanoSeconds) + { + NanoSeconds = nanoSeconds; + } + + public ulong ToSeconds() + { + return NanoSeconds / 1000000000; + } + + public static TimeSpanType FromTicks(ulong ticks, ulong frequency) + { + return new TimeSpanType(ticks * 1000000000 / frequency); + } + } + + [StructLayout(LayoutKind.Sequential)] + struct SteadyClockTimePoint + { + public ulong TimePoint; + public UInt128 ClockSourceId; + } + + [StructLayout(LayoutKind.Sequential)] + struct SystemClockContext + { + public ulong Offset; + public SteadyClockTimePoint SteadyTimePoint; + } +} diff --git a/Ryujinx.HLE/HOS/Services/Time/Clock/StandardLocalSystemClockCore.cs b/Ryujinx.HLE/HOS/Services/Time/Clock/StandardLocalSystemClockCore.cs new file mode 100644 index 00000000..16550199 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Time/Clock/StandardLocalSystemClockCore.cs @@ -0,0 +1,59 @@ +using Ryujinx.HLE.HOS.Kernel.Threading; + +namespace Ryujinx.HLE.HOS.Services.Time.Clock +{ + class StandardLocalSystemClockCore : SystemClockCore + { + private SteadyClockCore _steadyClockCore; + private SystemClockContext _context; + + private static StandardLocalSystemClockCore instance; + + public static StandardLocalSystemClockCore Instance + { + get + { + if (instance == null) + { + instance = new StandardLocalSystemClockCore(SteadyClockCore.Instance); + } + + return instance; + } + } + + public StandardLocalSystemClockCore(SteadyClockCore steadyClockCore) + { + _steadyClockCore = steadyClockCore; + _context = new SystemClockContext(); + + _context.SteadyTimePoint.ClockSourceId = steadyClockCore.GetClockSourceId(); + } + + public override ResultCode Flush(SystemClockContext context) + { + // TODO: set:sys SetUserSystemClockContext + + return ResultCode.Success; + } + + public override SteadyClockCore GetSteadyClockCore() + { + return _steadyClockCore; + } + + public override ResultCode GetSystemClockContext(KThread thread, out SystemClockContext context) + { + context = _context; + + return ResultCode.Success; + } + + public override ResultCode SetSystemClockContext(SystemClockContext context) + { + _context = context; + + return ResultCode.Success; + } + } +} diff --git a/Ryujinx.HLE/HOS/Services/Time/Clock/StandardNetworkSystemClockCore.cs b/Ryujinx.HLE/HOS/Services/Time/Clock/StandardNetworkSystemClockCore.cs new file mode 100644 index 00000000..59bc822c --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Time/Clock/StandardNetworkSystemClockCore.cs @@ -0,0 +1,59 @@ +using Ryujinx.HLE.HOS.Kernel.Threading; + +namespace Ryujinx.HLE.HOS.Services.Time.Clock +{ + class StandardNetworkSystemClockCore : SystemClockCore + { + private SteadyClockCore _steadyClockCore; + private SystemClockContext _context; + + private static StandardNetworkSystemClockCore instance; + + public static StandardNetworkSystemClockCore Instance + { + get + { + if (instance == null) + { + instance = new StandardNetworkSystemClockCore(SteadyClockCore.Instance); + } + + return instance; + } + } + + public StandardNetworkSystemClockCore(SteadyClockCore steadyClockCore) + { + _steadyClockCore = steadyClockCore; + _context = new SystemClockContext(); + + _context.SteadyTimePoint.ClockSourceId = steadyClockCore.GetClockSourceId(); + } + + public override ResultCode Flush(SystemClockContext context) + { + // TODO: set:sys SetNetworkSystemClockContext + + return ResultCode.Success; + } + + public override SteadyClockCore GetSteadyClockCore() + { + return _steadyClockCore; + } + + public override ResultCode GetSystemClockContext(KThread thread, out SystemClockContext context) + { + context = _context; + + return ResultCode.Success; + } + + public override ResultCode SetSystemClockContext(SystemClockContext context) + { + _context = context; + + return ResultCode.Success; + } + } +} diff --git a/Ryujinx.HLE/HOS/Services/Time/Clock/StandardUserSystemClockCore.cs b/Ryujinx.HLE/HOS/Services/Time/Clock/StandardUserSystemClockCore.cs new file mode 100644 index 00000000..00f296ad --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Time/Clock/StandardUserSystemClockCore.cs @@ -0,0 +1,96 @@ +using Ryujinx.HLE.HOS.Kernel.Threading; + +namespace Ryujinx.HLE.HOS.Services.Time.Clock +{ + class StandardUserSystemClockCore : SystemClockCore + { + private StandardLocalSystemClockCore _localSystemClockCore; + private StandardNetworkSystemClockCore _networkSystemClockCore; + private bool _autoCorrectionEnabled; + + private static StandardUserSystemClockCore instance; + + public static StandardUserSystemClockCore Instance + { + get + { + if (instance == null) + { + instance = new StandardUserSystemClockCore(StandardLocalSystemClockCore.Instance, StandardNetworkSystemClockCore.Instance); + } + + return instance; + } + } + + public StandardUserSystemClockCore(StandardLocalSystemClockCore localSystemClockCore, StandardNetworkSystemClockCore networkSystemClockCore) + { + _localSystemClockCore = localSystemClockCore; + _networkSystemClockCore = networkSystemClockCore; + _autoCorrectionEnabled = false; + } + + public override ResultCode Flush(SystemClockContext context) + { + return ResultCode.NotImplemented; + } + + public override SteadyClockCore GetSteadyClockCore() + { + return _localSystemClockCore.GetSteadyClockCore(); + } + + public override ResultCode GetSystemClockContext(KThread thread, out SystemClockContext context) + { + ResultCode result = ApplyAutomaticCorrection(thread, false); + + context = new SystemClockContext(); + + if (result == ResultCode.Success) + { + return _localSystemClockCore.GetSystemClockContext(thread, out context); + } + + return result; + } + + public override ResultCode SetSystemClockContext(SystemClockContext context) + { + return ResultCode.NotImplemented; + } + + private ResultCode ApplyAutomaticCorrection(KThread thread, bool autoCorrectionEnabled) + { + ResultCode result = ResultCode.Success; + + if (_autoCorrectionEnabled != autoCorrectionEnabled && _networkSystemClockCore.IsClockSetup(thread)) + { + result = _networkSystemClockCore.GetSystemClockContext(thread, out SystemClockContext context); + + if (result == ResultCode.Success) + { + _localSystemClockCore.SetSystemClockContext(context); + } + } + + return result; + } + + public ResultCode SetAutomaticCorrectionEnabled(KThread thread, bool autoCorrectionEnabled) + { + ResultCode result = ApplyAutomaticCorrection(thread, autoCorrectionEnabled); + + if (result == ResultCode.Success) + { + _autoCorrectionEnabled = autoCorrectionEnabled; + } + + return result; + } + + public bool IsAutomaticCorrectionEnabled() + { + return _autoCorrectionEnabled; + } + } +} diff --git a/Ryujinx.HLE/HOS/Services/Time/Clock/SteadyClockCore.cs b/Ryujinx.HLE/HOS/Services/Time/Clock/SteadyClockCore.cs new file mode 100644 index 00000000..b69b7d3c --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Time/Clock/SteadyClockCore.cs @@ -0,0 +1,86 @@ +using Ryujinx.HLE.HOS.Kernel.Threading; +using Ryujinx.HLE.Utilities; +using System; + +namespace Ryujinx.HLE.HOS.Services.Time.Clock +{ + class SteadyClockCore + { + private TimeSpanType _testOffset; + private TimeSpanType _internalOffset; + private UInt128 _clockSourceId; + + private static SteadyClockCore instance; + + public static SteadyClockCore Instance + { + get + { + if (instance == null) + { + instance = new SteadyClockCore(); + } + + return instance; + } + } + + private SteadyClockCore() + { + _testOffset = new TimeSpanType(0); + _internalOffset = new TimeSpanType(0); + _clockSourceId = new UInt128(Guid.NewGuid().ToByteArray()); + } + + private SteadyClockTimePoint GetTimePoint(KThread thread) + { + SteadyClockTimePoint result = new SteadyClockTimePoint + { + TimePoint = 0, + ClockSourceId = _clockSourceId + }; + + TimeSpanType ticksTimeSpan = TimeSpanType.FromTicks(thread.Context.ThreadState.CntpctEl0, thread.Context.ThreadState.CntfrqEl0); + + result.TimePoint = _internalOffset.ToSeconds() + ticksTimeSpan.ToSeconds(); + + return result; + } + + public UInt128 GetClockSourceId() + { + return _clockSourceId; + } + + public SteadyClockTimePoint GetCurrentTimePoint(KThread thread) + { + SteadyClockTimePoint result = GetTimePoint(thread); + + result.TimePoint += _testOffset.ToSeconds(); + + return result; + } + + public TimeSpanType GetTestOffset() + { + return _testOffset; + } + + public void SetTestOffset(TimeSpanType testOffset) + { + _testOffset = testOffset; + } + + // TODO: check if this is accurate + public TimeSpanType GetInternalOffset() + { + return _internalOffset; + } + + // TODO: check if this is accurate + public void SetInternalOffset(TimeSpanType internalOffset) + { + _internalOffset = internalOffset; + } + } +} diff --git a/Ryujinx.HLE/HOS/Services/Time/Clock/SystemClockCore.cs b/Ryujinx.HLE/HOS/Services/Time/Clock/SystemClockCore.cs new file mode 100644 index 00000000..d3a056e4 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Time/Clock/SystemClockCore.cs @@ -0,0 +1,31 @@ +using Ryujinx.HLE.HOS.Kernel.Threading; + +namespace Ryujinx.HLE.HOS.Services.Time.Clock +{ + abstract class SystemClockCore + { + public abstract SteadyClockCore GetSteadyClockCore(); + + public abstract ResultCode GetSystemClockContext(KThread thread, out SystemClockContext context); + + public abstract ResultCode SetSystemClockContext(SystemClockContext context); + + public abstract ResultCode Flush(SystemClockContext context); + + public bool IsClockSetup(KThread thread) + { + ResultCode result = GetSystemClockContext(thread, out SystemClockContext context); + + if (result == ResultCode.Success) + { + SteadyClockCore steadyClockCore = GetSteadyClockCore(); + + SteadyClockTimePoint steadyClockTimePoint = steadyClockCore.GetCurrentTimePoint(thread); + + return steadyClockTimePoint.ClockSourceId == context.SteadyTimePoint.ClockSourceId; + } + + return false; + } + } +} |
