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
This commit is contained in:
Thomas Guillemard 2019-07-14 22:50:11 +02:00 committed by Ac_K
parent 4ad3936afd
commit 97d0c62423
13 changed files with 522 additions and 82 deletions

View file

@ -1,97 +1,107 @@
using System;
using Ryujinx.Common;
using Ryujinx.HLE.HOS.Services.Time.Clock;
namespace Ryujinx.HLE.HOS.Services.Time
{
class ISystemClock : IpcService
{
private static readonly DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
private SystemClockCore _clockCore;
private bool _writePermission;
private SystemClockType _clockType;
private DateTime _systemClockContextEpoch;
private long _systemClockTimePoint;
private byte[] _systemClockContextEnding;
private long _timeOffset;
public ISystemClock(SystemClockType clockType)
public ISystemClock(SystemClockCore clockCore, bool writePermission)
{
_clockType = clockType;
_systemClockContextEpoch = System.Diagnostics.Process.GetCurrentProcess().StartTime;
_systemClockContextEnding = new byte[0x10];
_timeOffset = 0;
if (clockType == SystemClockType.User ||
clockType == SystemClockType.Network)
{
_systemClockContextEpoch = _systemClockContextEpoch.ToUniversalTime();
}
_systemClockTimePoint = (long)(_systemClockContextEpoch - Epoch).TotalSeconds;
_clockCore = clockCore;
_writePermission = writePermission;
}
[Command(0)]
// GetCurrentTime() -> nn::time::PosixTime
public ResultCode GetCurrentTime(ServiceCtx context)
{
DateTime currentTime = DateTime.Now;
SteadyClockCore steadyClockCore = _clockCore.GetSteadyClockCore();
SteadyClockTimePoint currentTimePoint = steadyClockCore.GetCurrentTimePoint(context.Thread);
if (_clockType == SystemClockType.User ||
_clockType == SystemClockType.Network)
ResultCode result = _clockCore.GetSystemClockContext(context.Thread, out SystemClockContext clockContext);
if (result == ResultCode.Success)
{
currentTime = currentTime.ToUniversalTime();
result = ResultCode.TimeMismatch;
if (currentTimePoint.ClockSourceId == clockContext.SteadyTimePoint.ClockSourceId)
{
ulong posixTime = clockContext.Offset + currentTimePoint.TimePoint;
context.ResponseData.Write(posixTime);
result = 0;
}
}
context.ResponseData.Write((long)((currentTime - Epoch).TotalSeconds) + _timeOffset);
return ResultCode.Success;
return result;
}
[Command(1)]
// SetCurrentTime(nn::time::PosixTime)
public ResultCode SetCurrentTime(ServiceCtx context)
{
DateTime currentTime = DateTime.Now;
if (_clockType == SystemClockType.User ||
_clockType == SystemClockType.Network)
if (!_writePermission)
{
currentTime = currentTime.ToUniversalTime();
return ResultCode.PermissionDenied;
}
_timeOffset = (context.RequestData.ReadInt64() - (long)(currentTime - Epoch).TotalSeconds);
ulong posixTime = context.RequestData.ReadUInt64();
SteadyClockCore steadyClockCore = _clockCore.GetSteadyClockCore();
SteadyClockTimePoint currentTimePoint = steadyClockCore.GetCurrentTimePoint(context.Thread);
return ResultCode.Success;
SystemClockContext clockContext = new SystemClockContext()
{
Offset = posixTime - currentTimePoint.TimePoint,
SteadyTimePoint = currentTimePoint
};
ResultCode result = _clockCore.SetSystemClockContext(clockContext);
if (result == ResultCode.Success)
{
result = _clockCore.Flush(clockContext);
}
return result;
}
[Command(2)]
// GetSystemClockContext() -> nn::time::SystemClockContext
public ResultCode GetSystemClockContext(ServiceCtx context)
{
context.ResponseData.Write((long)(_systemClockContextEpoch - Epoch).TotalSeconds);
ResultCode result = _clockCore.GetSystemClockContext(context.Thread, out SystemClockContext clockContext);
// The point in time, TODO: is there a link between epoch and this?
context.ResponseData.Write(_systemClockTimePoint);
// This seems to be some kind of identifier?
for (int i = 0; i < 0x10; i++)
if (result == ResultCode.Success)
{
context.ResponseData.Write(_systemClockContextEnding[i]);
context.ResponseData.WriteStruct(clockContext);
}
return ResultCode.Success;
return result;
}
[Command(3)]
// SetSystemClockContext(nn::time::SystemClockContext)
public ResultCode SetSystemClockContext(ServiceCtx context)
{
long newSystemClockEpoch = context.RequestData.ReadInt64();
long newSystemClockTimePoint = context.RequestData.ReadInt64();
if (!_writePermission)
{
return ResultCode.PermissionDenied;
}
_systemClockContextEpoch = Epoch.Add(TimeSpan.FromSeconds(newSystemClockEpoch));
_systemClockTimePoint = newSystemClockTimePoint;
_systemClockContextEnding = context.RequestData.ReadBytes(0x10);
SystemClockContext clockContext = context.RequestData.ReadStruct<SystemClockContext>();
return ResultCode.Success;
ResultCode result = _clockCore.SetSystemClockContext(clockContext);
if (result == ResultCode.Success)
{
result = _clockCore.Flush(clockContext);
}
return result;
}
}
}