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:
parent
4ad3936afd
commit
97d0c62423
13 changed files with 522 additions and 82 deletions
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue