Start implementing time:m
Also prepare the skeleton of the shared memory
This commit is contained in:
parent
eb02cfa777
commit
9982ea30ff
12 changed files with 440 additions and 48 deletions
|
@ -25,6 +25,8 @@ using System.Threading;
|
|||
using TimeServiceManager = Ryujinx.HLE.HOS.Services.Time.TimeManager;
|
||||
|
||||
using NxStaticObject = Ryujinx.HLE.Loaders.Executables.NxStaticObject;
|
||||
using Ryujinx.HLE.Utilities;
|
||||
using Ryujinx.HLE.HOS.Services.Pcv.Bpc;
|
||||
|
||||
namespace Ryujinx.HLE.HOS
|
||||
{
|
||||
|
@ -89,8 +91,6 @@ namespace Ryujinx.HLE.HOS
|
|||
internal KSharedMemory HidSharedMem { get; private set; }
|
||||
internal KSharedMemory FontSharedMem { get; private set; }
|
||||
internal KSharedMemory IirsSharedMem { get; private set; }
|
||||
internal KSharedMemory TimeSharedMem { get; private set; }
|
||||
|
||||
internal SharedFontManager Font { get; private set; }
|
||||
|
||||
internal ContentManager ContentManager { get; private set; }
|
||||
|
@ -186,7 +186,10 @@ namespace Ryujinx.HLE.HOS
|
|||
HidSharedMem = new KSharedMemory(this, hidPageList, 0, 0, MemoryPermission.Read);
|
||||
FontSharedMem = new KSharedMemory(this, fontPageList, 0, 0, MemoryPermission.Read);
|
||||
IirsSharedMem = new KSharedMemory(this, iirsPageList, 0, 0, MemoryPermission.Read);
|
||||
TimeSharedMem = new KSharedMemory(this, timePageList, 0, 0, MemoryPermission.Read);
|
||||
|
||||
KSharedMemory timeSharedMemory = new KSharedMemory(this, timePageList, 0, 0, MemoryPermission.Read);
|
||||
|
||||
TimeServiceManager.Instance.Initialize(device, this, timeSharedMemory, (long)(timePa - DramMemoryMap.DramBase), TimeSize);
|
||||
|
||||
AppletState = new AppletStateMgr(this);
|
||||
|
||||
|
@ -202,19 +205,30 @@ namespace Ryujinx.HLE.HOS
|
|||
|
||||
ContentManager = new ContentManager(device);
|
||||
|
||||
// TODO: use set:sys (and set external clock source id from settings)
|
||||
// TODO: use set:sys (and get external clock source id from settings)
|
||||
// TODO: use "time!standard_steady_clock_rtc_update_interval_minutes" and implement a worker thread to be accurate.
|
||||
// TODO: migrate to 9.0.0+
|
||||
TimeServiceManager.Instance.StandardSteadyClock.ConfigureSetupValue();
|
||||
TimeServiceManager.Instance.StandardSteadyClock.MarkInitialized();
|
||||
UInt128 clockSourceId = new UInt128(Guid.NewGuid().ToByteArray());
|
||||
IRtcManager.GetExternalRtcValue(out ulong rtcValue);
|
||||
|
||||
// We assume the rtc is system time.
|
||||
TimeSpanType systemTime = TimeSpanType.FromSeconds((long)rtcValue);
|
||||
|
||||
// First init the standard steady clock
|
||||
TimeServiceManager.Instance.SetupStandardSteadyClock(null, clockSourceId, systemTime, TimeSpanType.Zero, TimeSpanType.Zero, false);
|
||||
TimeServiceManager.Instance.SetupStandardLocalSystemClock(null, new SystemClockContext(), systemTime.ToSeconds());
|
||||
|
||||
if (NxSettings.Settings.TryGetValue("time!standard_network_clock_sufficient_accuracy_minutes", out object standardNetworkClockSufficientAccuracyMinutes))
|
||||
{
|
||||
TimeSpanType standardNetworkClockSufficientAccuracy = new TimeSpanType((int)standardNetworkClockSufficientAccuracyMinutes * 60000000000);
|
||||
|
||||
TimeServiceManager.Instance.StandardNetworkSystemClock.SetStandardNetworkClockSufficientAccuracy(standardNetworkClockSufficientAccuracy);
|
||||
TimeServiceManager.Instance.SetupStandardNetworkSystemClock(new SystemClockContext(), standardNetworkClockSufficientAccuracy);
|
||||
}
|
||||
|
||||
TimeServiceManager.Instance.SetupStandardUserSystemClock(null, false, SteadyClockTimePoint.GetRandom());
|
||||
|
||||
// FIXME: TimeZone shoud be init here but it's actually done in ContentManager
|
||||
|
||||
TimeServiceManager.Instance.SetupEphemeralNetworkSystemClock();
|
||||
}
|
||||
|
||||
public void LoadCart(string exeFsDir, string romFsFile = null)
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using Ryujinx.HLE.HOS.Kernel.Threading;
|
||||
using Ryujinx.HLE.HOS.Services.Pcv.Bpc;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Time.Clock
|
||||
{
|
||||
|
@ -14,10 +13,10 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
|
|||
|
||||
public StandardSteadyClockCore()
|
||||
{
|
||||
_setupValue = new TimeSpanType(0);
|
||||
_testOffset = new TimeSpanType(0);
|
||||
_internalOffset = new TimeSpanType(0);
|
||||
_cachedRawTimePoint = new TimeSpanType(0);
|
||||
_setupValue = TimeSpanType.Zero;
|
||||
_testOffset = TimeSpanType.Zero;
|
||||
_internalOffset = TimeSpanType.Zero;
|
||||
_cachedRawTimePoint = TimeSpanType.Zero;
|
||||
}
|
||||
|
||||
public override SteadyClockTimePoint GetTimePoint(KThread thread)
|
||||
|
@ -53,7 +52,17 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
|
|||
|
||||
public override TimeSpanType GetCurrentRawTimePoint(KThread thread)
|
||||
{
|
||||
TimeSpanType ticksTimeSpan = TimeSpanType.FromTicks(thread.Context.CntpctEl0, thread.Context.CntfrqEl0);
|
||||
TimeSpanType ticksTimeSpan;
|
||||
|
||||
// As this may be called before the guest code, we support passing a null thread to make this api usable.
|
||||
if (thread == null)
|
||||
{
|
||||
ticksTimeSpan = TimeSpanType.FromSeconds(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
ticksTimeSpan = TimeSpanType.FromTicks(thread.Context.CntpctEl0, thread.Context.CntfrqEl0);
|
||||
}
|
||||
|
||||
TimeSpanType rawTimePoint = new TimeSpanType(_setupValue.NanoSeconds + ticksTimeSpan.NanoSeconds);
|
||||
|
||||
|
@ -67,27 +76,9 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
|
|||
return rawTimePoint;
|
||||
}
|
||||
|
||||
// TODO: move this to glue when we will have psc fully done
|
||||
public void ConfigureSetupValue()
|
||||
public void SetSetupValue(TimeSpanType setupValue)
|
||||
{
|
||||
int retry = 0;
|
||||
|
||||
ResultCode result = ResultCode.Success;
|
||||
|
||||
while (retry < 20)
|
||||
{
|
||||
result = (ResultCode)IRtcManager.GetExternalRtcValue(out ulong rtcValue);
|
||||
|
||||
if (result == ResultCode.Success)
|
||||
{
|
||||
_setupValue = TimeSpanType.FromSeconds((long)rtcValue);
|
||||
break;
|
||||
}
|
||||
|
||||
retry++;
|
||||
}
|
||||
|
||||
_setupResultCode = result;
|
||||
_setupValue = setupValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,12 +7,17 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
|
|||
private StandardLocalSystemClockCore _localSystemClockCore;
|
||||
private StandardNetworkSystemClockCore _networkSystemClockCore;
|
||||
private bool _autoCorrectionEnabled;
|
||||
private SteadyClockTimePoint _autoCorrectionTime;
|
||||
private KEvent _autoCorrectionEvent;
|
||||
|
||||
public StandardUserSystemClockCore(StandardLocalSystemClockCore localSystemClockCore, StandardNetworkSystemClockCore networkSystemClockCore) : base(localSystemClockCore.GetSteadyClockCore())
|
||||
{
|
||||
_localSystemClockCore = localSystemClockCore;
|
||||
_networkSystemClockCore = networkSystemClockCore;
|
||||
_autoCorrectionEnabled = false;
|
||||
_autoCorrectionTime = SteadyClockTimePoint.GetRandom();
|
||||
|
||||
_autoCorrectionEvent = null;
|
||||
}
|
||||
|
||||
protected override ResultCode Flush(SystemClockContext context)
|
||||
|
@ -56,6 +61,11 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
|
|||
return result;
|
||||
}
|
||||
|
||||
internal void CreateAutomaticCorrectionEvent(Horizon system)
|
||||
{
|
||||
_autoCorrectionEvent = new KEvent(system);
|
||||
}
|
||||
|
||||
public ResultCode SetAutomaticCorrectionEnabled(KThread thread, bool autoCorrectionEnabled)
|
||||
{
|
||||
ResultCode result = ApplyAutomaticCorrection(thread, autoCorrectionEnabled);
|
||||
|
@ -72,5 +82,11 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
|
|||
{
|
||||
return _autoCorrectionEnabled;
|
||||
}
|
||||
|
||||
public void SetAutomaticCorrectionUpdatedTime(SteadyClockTimePoint steadyClockTimePoint)
|
||||
{
|
||||
_autoCorrectionTime = steadyClockTimePoint;
|
||||
_autoCorrectionEvent.WritableEvent.Signal();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,6 +22,16 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
|
|||
return _clockSourceId;
|
||||
}
|
||||
|
||||
public void SetClockSourceId(UInt128 clockSourceId)
|
||||
{
|
||||
_clockSourceId = clockSourceId;
|
||||
}
|
||||
|
||||
public void SetRtcReset()
|
||||
{
|
||||
_isRtcResetDetected = true;
|
||||
}
|
||||
|
||||
public virtual TimeSpanType GetTestOffset()
|
||||
{
|
||||
return new TimeSpanType(0);
|
||||
|
|
|
@ -14,7 +14,17 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
|
|||
ClockSourceId = GetClockSourceId()
|
||||
};
|
||||
|
||||
TimeSpanType ticksTimeSpan = TimeSpanType.FromTicks(thread.Context.CntpctEl0, thread.Context.CntfrqEl0);
|
||||
TimeSpanType ticksTimeSpan;
|
||||
|
||||
// As this may be called before the guest code, we support passing a null thread to make this api usable.
|
||||
if (thread == null)
|
||||
{
|
||||
ticksTimeSpan = TimeSpanType.FromSeconds(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
ticksTimeSpan = TimeSpanType.FromTicks(thread.Context.CntpctEl0, thread.Context.CntfrqEl0);
|
||||
}
|
||||
|
||||
result.TimePoint = ticksTimeSpan.ToSeconds();
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
|
|||
[StructLayout(LayoutKind.Sequential)]
|
||||
struct SteadyClockTimePoint
|
||||
{
|
||||
public long TimePoint;
|
||||
public long TimePoint;
|
||||
public UInt128 ClockSourceId;
|
||||
|
||||
public ResultCode GetSpanBetween(SteadyClockTimePoint other, out long outSpan)
|
||||
|
@ -30,5 +30,14 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
|
|||
|
||||
return ResultCode.Overflow;
|
||||
}
|
||||
|
||||
public static SteadyClockTimePoint GetRandom()
|
||||
{
|
||||
return new SteadyClockTimePoint
|
||||
{
|
||||
TimePoint = 0,
|
||||
ClockSourceId = new UInt128(Guid.NewGuid().ToByteArray())
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,6 +7,8 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
|
|||
{
|
||||
private const long NanoSecondsPerSecond = 1000000000;
|
||||
|
||||
public static readonly TimeSpanType Zero = new TimeSpanType(0);
|
||||
|
||||
public long NanoSeconds;
|
||||
|
||||
public TimeSpanType(long nanoSeconds)
|
||||
|
|
|
@ -91,7 +91,7 @@ namespace Ryujinx.HLE.HOS.Services.Time
|
|||
{
|
||||
if (_timeSharedMemoryNativeHandle == 0)
|
||||
{
|
||||
if (context.Process.HandleTable.GenerateHandle(context.Device.System.TimeSharedMem, out _timeSharedMemoryNativeHandle) != KernelResult.Success)
|
||||
if (context.Process.HandleTable.GenerateHandle(_timeManager.SharedMemory.GetSharedMemory(), out _timeSharedMemoryNativeHandle) != KernelResult.Success)
|
||||
{
|
||||
throw new InvalidOperationException("Out of handles!");
|
||||
}
|
||||
|
|
|
@ -1,8 +1,203 @@
|
|||
namespace Ryujinx.HLE.HOS.Services.Time
|
||||
using Ryujinx.Common;
|
||||
using Ryujinx.HLE.Exceptions;
|
||||
using Ryujinx.HLE.HOS.Ipc;
|
||||
using Ryujinx.HLE.HOS.Kernel.Common;
|
||||
using Ryujinx.HLE.HOS.Services.Time.Clock;
|
||||
using Ryujinx.HLE.Utilities;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Time
|
||||
{
|
||||
[Service("time:m")] // 9.0.0+
|
||||
class ITimeServiceManager : IpcService
|
||||
{
|
||||
public ITimeServiceManager(ServiceCtx context) { }
|
||||
private TimeManager _timeManager;
|
||||
private int _automaticCorrectionEvent;
|
||||
|
||||
public ITimeServiceManager(ServiceCtx context)
|
||||
{
|
||||
_timeManager = TimeManager.Instance;
|
||||
_automaticCorrectionEvent = 0;
|
||||
}
|
||||
|
||||
[Command(0)]
|
||||
// GetUserStaticService() -> object<nn::timesrv::detail::service::IStaticService>
|
||||
public ResultCode GetUserStaticService(ServiceCtx context)
|
||||
{
|
||||
MakeObject(context, new IStaticService(_timeManager, TimePermissions.User));
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
[Command(5)]
|
||||
// GetAdminStaticService() -> object<nn::timesrv::detail::service::IStaticService>
|
||||
public ResultCode GetAdminStaticService(ServiceCtx context)
|
||||
{
|
||||
MakeObject(context, new IStaticService(_timeManager, TimePermissions.Admin));
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
[Command(6)]
|
||||
// GetRepairStaticService() -> object<nn::timesrv::detail::service::IStaticService>
|
||||
public ResultCode GetRepairStaticService(ServiceCtx context)
|
||||
{
|
||||
MakeObject(context, new IStaticService(_timeManager, TimePermissions.Repair));
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
[Command(9)]
|
||||
// GetManufactureStaticService() -> object<nn::timesrv::detail::service::IStaticService>
|
||||
public ResultCode GetManufactureStaticService(ServiceCtx context)
|
||||
{
|
||||
MakeObject(context, new IStaticService(_timeManager, TimePermissions.Manufacture));
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
[Command(10)]
|
||||
// SetupStandardSteadyClock(nn::util::Uuid clock_source_id, nn::TimeSpanType setup_value, nn::TimeSpanType internal_offset, nn::TimeSpanType test_offset, bool is_rtc_reset_detected)
|
||||
public ResultCode SetupStandardSteadyClock(ServiceCtx context)
|
||||
{
|
||||
UInt128 clockSourceId = context.RequestData.ReadStruct<UInt128>();
|
||||
TimeSpanType setupValue = context.RequestData.ReadStruct<TimeSpanType>();
|
||||
TimeSpanType internalOffset = context.RequestData.ReadStruct<TimeSpanType>();
|
||||
TimeSpanType testOffset = context.RequestData.ReadStruct<TimeSpanType>();
|
||||
bool isRtcResetDetected = context.RequestData.ReadBoolean();
|
||||
|
||||
return _timeManager.SetupStandardSteadyClock(context.Thread, clockSourceId, setupValue, internalOffset, testOffset, isRtcResetDetected);
|
||||
}
|
||||
|
||||
[Command(11)]
|
||||
// SetupStandardLocalSystemClock(nn::time::SystemClockContext context, nn::time::PosixTime posix_time)
|
||||
public ResultCode SetupStandardLocalSystemClock(ServiceCtx context)
|
||||
{
|
||||
SystemClockContext clockContext = context.RequestData.ReadStruct<SystemClockContext>();
|
||||
long posixTime = context.RequestData.ReadInt64();
|
||||
|
||||
_timeManager.SetupStandardLocalSystemClock(context.Thread, clockContext, posixTime);
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
[Command(12)]
|
||||
// SetupStandardNetworkSystemClock(nn::time::SystemClockContext context, nn::TimeSpanType sufficient_accuracy)
|
||||
public ResultCode SetupStandardNetworkSystemClock(ServiceCtx context)
|
||||
{
|
||||
SystemClockContext clockContext = context.RequestData.ReadStruct<SystemClockContext>();
|
||||
TimeSpanType sufficientAccuracy = context.RequestData.ReadStruct<TimeSpanType>();
|
||||
|
||||
_timeManager.SetupStandardNetworkSystemClock(clockContext, sufficientAccuracy);
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
[Command(13)]
|
||||
// SetupStandardUserSystemClock(bool automatic_correction_enabled, nn::time::SteadyClockTimePoint steady_clock_timepoint)
|
||||
public ResultCode SetupStandardUserSystemClock(ServiceCtx context)
|
||||
{
|
||||
bool isAutomaticCorrectionEnabled = context.RequestData.ReadBoolean();
|
||||
context.RequestData.BaseStream.Position += 7;
|
||||
|
||||
SteadyClockTimePoint steadyClockTimePoint = context.RequestData.ReadStruct<SteadyClockTimePoint>();
|
||||
|
||||
_timeManager.SetupStandardUserSystemClock(context.Thread, isAutomaticCorrectionEnabled, steadyClockTimePoint);
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
[Command(14)]
|
||||
// SetupTimeZoneManager(nn::time::LocationName location_name, u32 total_location_name_count, nn::time::TimeZoneRuleVersion timezone_rule_version, buffer<nn::time::TimeZoneBinary, 0x21> timezone_binary)
|
||||
public ResultCode SetupTimeZoneManager(ServiceCtx context)
|
||||
{
|
||||
// TODO
|
||||
return ResultCode.NotImplemented;
|
||||
}
|
||||
|
||||
[Command(15)]
|
||||
// SetupEphemeralNetworkSystemClock()
|
||||
public ResultCode SetupEphemeralNetworkSystemClock(ServiceCtx context)
|
||||
{
|
||||
_timeManager.SetupEphemeralNetworkSystemClock();
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
[Command(50)]
|
||||
// Unknown50() -> handle<copy>
|
||||
public ResultCode Unknown50(ServiceCtx context)
|
||||
{
|
||||
// TODO: figure out the usage of this event
|
||||
throw new ServiceNotImplementedException(context);
|
||||
}
|
||||
|
||||
[Command(51)]
|
||||
// Unknown51() -> handle<copy>
|
||||
public ResultCode Unknown51(ServiceCtx context)
|
||||
{
|
||||
// TODO: figure out the usage of this event
|
||||
throw new ServiceNotImplementedException(context);
|
||||
}
|
||||
|
||||
[Command(52)]
|
||||
// Unknown52() -> handle<copy>
|
||||
public ResultCode Unknown52(ServiceCtx context)
|
||||
{
|
||||
// TODO: figure out the usage of this event
|
||||
throw new ServiceNotImplementedException(context);
|
||||
}
|
||||
|
||||
[Command(60)]
|
||||
// GetStandardUserSystemClockAutomaticCorrectionEvent() -> handle<copy>
|
||||
public ResultCode GetStandardUserSystemClockAutomaticCorrectionEvent(ServiceCtx context)
|
||||
{
|
||||
if (_automaticCorrectionEvent == 0)
|
||||
{
|
||||
if (context.Process.HandleTable.GenerateHandle(_timeManager.SharedMemory.GetSharedMemory(), out _automaticCorrectionEvent) != KernelResult.Success)
|
||||
{
|
||||
throw new InvalidOperationException("Out of handles!");
|
||||
}
|
||||
}
|
||||
|
||||
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_automaticCorrectionEvent);
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
[Command(100)]
|
||||
// SetStandardSteadyClockRtcOffset(nn::TimeSpanType rtc_offset)
|
||||
public ResultCode SetStandardSteadyClockRtcOffset(ServiceCtx context)
|
||||
{
|
||||
TimeSpanType rtcOffset = context.RequestData.ReadStruct<TimeSpanType>();
|
||||
|
||||
_timeManager.SetStandardSteadyClockRtcOffset(context.Thread, rtcOffset);
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
[Command(200)]
|
||||
// GetAlarmRegistrationEvent() -> handle<copy>
|
||||
public ResultCode GetAlarmRegistrationEvent(ServiceCtx context)
|
||||
{
|
||||
// TODO
|
||||
return ResultCode.NotImplemented;
|
||||
}
|
||||
|
||||
[Command(201)]
|
||||
// UpdateSteadyAlarms()
|
||||
public ResultCode UpdateSteadyAlarms(ServiceCtx context)
|
||||
{
|
||||
// TODO
|
||||
return ResultCode.NotImplemented;
|
||||
}
|
||||
|
||||
[Command(202)]
|
||||
// TryGetNextSteadyClockAlarmSnapshot() -> (bool, nn::time::SteadyClockAlarmSnapshot)
|
||||
public ResultCode TryGetNextSteadyClockAlarmSnapshot(ServiceCtx context)
|
||||
{
|
||||
// TODO
|
||||
return ResultCode.NotImplemented;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
using Ryujinx.HLE.HOS.Services.Time.Clock;
|
||||
using System;
|
||||
using Ryujinx.HLE.HOS.Kernel.Memory;
|
||||
using Ryujinx.HLE.HOS.Kernel.Threading;
|
||||
using Ryujinx.HLE.HOS.Services.Time.Clock;
|
||||
using Ryujinx.HLE.HOS.Services.Time.TimeZone;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Ryujinx.HLE.Utilities;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Time
|
||||
{
|
||||
|
@ -30,6 +31,7 @@ namespace Ryujinx.HLE.HOS.Services.Time
|
|||
public StandardUserSystemClockCore StandardUserSystemClock { get; private set; }
|
||||
public TimeZoneManager TimeZone { get; private set; }
|
||||
public EphemeralNetworkSystemClockCore EphemeralNetworkSystemClock { get; private set; }
|
||||
public TimeSharedMemory SharedMemory { get; private set; }
|
||||
|
||||
// TODO: 9.0.0+ power state, alarms, clock writers
|
||||
|
||||
|
@ -42,6 +44,107 @@ namespace Ryujinx.HLE.HOS.Services.Time
|
|||
StandardUserSystemClock = new StandardUserSystemClockCore(StandardLocalSystemClock, StandardNetworkSystemClock);
|
||||
TimeZone = new TimeZoneManager();
|
||||
EphemeralNetworkSystemClock = new EphemeralNetworkSystemClockCore(StandardSteadyClock);
|
||||
SharedMemory = new TimeSharedMemory();
|
||||
}
|
||||
|
||||
public void Initialize(Switch device, Horizon system, KSharedMemory sharedMemory, long timeSharedMemoryAddress, int timeSharedMemorySize)
|
||||
{
|
||||
SharedMemory.Initialize(device, sharedMemory, timeSharedMemoryAddress, timeSharedMemorySize);
|
||||
|
||||
// Here we use system on purpose as device.System isn't initialized at this point.
|
||||
StandardUserSystemClock.CreateAutomaticCorrectionEvent(system);
|
||||
}
|
||||
|
||||
|
||||
public ResultCode SetupStandardSteadyClock(KThread thread, UInt128 clockSourceId, TimeSpanType setupValue, TimeSpanType internalOffset, TimeSpanType testOffset, bool isRtcResetDetected)
|
||||
{
|
||||
SetupInternalStandardSteadyClock(clockSourceId, setupValue, internalOffset, testOffset, isRtcResetDetected);
|
||||
|
||||
TimeSpanType currentTimePoint = StandardSteadyClock.GetCurrentRawTimePoint(thread);
|
||||
|
||||
SharedMemory.SetupStandardSteadyClock(clockSourceId, currentTimePoint);
|
||||
|
||||
// TODO: propagate IPC late binding of "time:s" and "time:p"
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
private void SetupInternalStandardSteadyClock(UInt128 clockSourceId, TimeSpanType setupValue, TimeSpanType internalOffset, TimeSpanType testOffset, bool isRtcResetDetected)
|
||||
{
|
||||
StandardSteadyClock.SetClockSourceId(clockSourceId);
|
||||
StandardSteadyClock.SetSetupValue(setupValue);
|
||||
StandardSteadyClock.SetInternalOffset(internalOffset);
|
||||
StandardSteadyClock.SetTestOffset(testOffset);
|
||||
|
||||
if (isRtcResetDetected)
|
||||
{
|
||||
StandardSteadyClock.SetRtcReset();
|
||||
}
|
||||
|
||||
StandardSteadyClock.MarkInitialized();
|
||||
|
||||
// TODO: propagate IPC late binding of "time:s" and "time:p"
|
||||
}
|
||||
|
||||
public void SetupStandardLocalSystemClock(KThread thread, SystemClockContext clockContext, long posixTime)
|
||||
{
|
||||
SteadyClockTimePoint currentTimePoint = StandardLocalSystemClock.GetSteadyClockCore().GetCurrentTimePoint(thread);
|
||||
if (currentTimePoint.ClockSourceId == clockContext.SteadyTimePoint.ClockSourceId)
|
||||
{
|
||||
StandardLocalSystemClock.SetSystemClockContext(clockContext);
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: if the result of this is wrong, abort
|
||||
StandardLocalSystemClock.SetCurrentTime(thread, posixTime);
|
||||
}
|
||||
|
||||
StandardLocalSystemClock.MarkInitialized();
|
||||
|
||||
// TODO: propagate IPC late binding of "time:s" and "time:p"
|
||||
|
||||
}
|
||||
|
||||
public void SetupStandardNetworkSystemClock(SystemClockContext clockContext, TimeSpanType sufficientAccuracy)
|
||||
{
|
||||
// TODO: if the result of this is wrong, abort
|
||||
StandardNetworkSystemClock.SetSystemClockContext(clockContext);
|
||||
|
||||
StandardNetworkSystemClock.SetStandardNetworkClockSufficientAccuracy(sufficientAccuracy);
|
||||
StandardNetworkSystemClock.MarkInitialized();
|
||||
|
||||
// TODO: propagate IPC late binding of "time:s" and "time:p"
|
||||
|
||||
}
|
||||
|
||||
public void SetupEphemeralNetworkSystemClock()
|
||||
{
|
||||
EphemeralNetworkSystemClock.MarkInitialized();
|
||||
|
||||
// TODO: propagate IPC late binding of "time:s" and "time:p"
|
||||
|
||||
}
|
||||
|
||||
public void SetupStandardUserSystemClock(KThread thread, bool isAutomaticCorrectionEnabled, SteadyClockTimePoint steadyClockTimePoint)
|
||||
{
|
||||
// TODO: if the result of this is wrong, abort
|
||||
StandardUserSystemClock.SetAutomaticCorrectionEnabled(thread, isAutomaticCorrectionEnabled);
|
||||
|
||||
StandardUserSystemClock.SetAutomaticCorrectionUpdatedTime(steadyClockTimePoint);
|
||||
StandardUserSystemClock.MarkInitialized();
|
||||
|
||||
SharedMemory.SetAutomaticCorrectionEnabled(isAutomaticCorrectionEnabled);
|
||||
|
||||
// TODO: propagate IPC late binding of "time:s" and "time:p"
|
||||
|
||||
}
|
||||
|
||||
public void SetStandardSteadyClockRtcOffset(KThread thread, TimeSpanType rtcOffset)
|
||||
{
|
||||
StandardSteadyClock.SetSetupValue(rtcOffset);
|
||||
|
||||
TimeSpanType currentTimePoint = StandardSteadyClock.GetCurrentRawTimePoint(thread);
|
||||
|
||||
SharedMemory.SetSteadyClockRawTimePoint(currentTimePoint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
46
Ryujinx.HLE/HOS/Services/Time/TimeSharedMemory.cs
Normal file
46
Ryujinx.HLE/HOS/Services/Time/TimeSharedMemory.cs
Normal file
|
@ -0,0 +1,46 @@
|
|||
using System;
|
||||
using Ryujinx.HLE.HOS.Kernel.Memory;
|
||||
using Ryujinx.HLE.HOS.Services.Time.Clock;
|
||||
using Ryujinx.HLE.Utilities;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Time
|
||||
{
|
||||
class TimeSharedMemory
|
||||
{
|
||||
private Switch _device;
|
||||
private KSharedMemory _sharedMemory;
|
||||
private long _timeSharedMemoryAddress;
|
||||
private int _timeSharedMemorySize;
|
||||
|
||||
public void Initialize(Switch device, KSharedMemory sharedMemory, long timeSharedMemoryAddress, int timeSharedMemorySize)
|
||||
{
|
||||
_device = device;
|
||||
_sharedMemory = sharedMemory;
|
||||
_timeSharedMemoryAddress = timeSharedMemoryAddress;
|
||||
_timeSharedMemorySize = timeSharedMemorySize;
|
||||
|
||||
// Clean the shared memory
|
||||
_device.Memory.FillWithZeros(_timeSharedMemoryAddress, _timeSharedMemorySize);
|
||||
}
|
||||
|
||||
public KSharedMemory GetSharedMemory()
|
||||
{
|
||||
return _sharedMemory;
|
||||
}
|
||||
|
||||
public void SetupStandardSteadyClock(UInt128 clockSourceId, TimeSpanType currentTimePoint)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
public void SetAutomaticCorrectionEnabled(bool isAutomaticCorrectionEnabled)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
public void SetSteadyClockRawTimePoint(TimeSpanType currentTimePoint)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
}
|
|
@ -17,10 +17,6 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
|
|||
{
|
||||
private const long TimeZoneBinaryTitleId = 0x010000000000080E;
|
||||
|
||||
private static TimeZoneManager instance;
|
||||
|
||||
private static object instanceLock = new object();
|
||||
|
||||
private Switch _device;
|
||||
private TimeZoneRule _myRules;
|
||||
private string _deviceLocationName;
|
||||
|
|
Loading…
Add table
Reference in a new issue