diff --git a/Ryujinx.HLE/HOS/Horizon.cs b/Ryujinx.HLE/HOS/Horizon.cs index 341bfe0178..52c514bf6c 100644 --- a/Ryujinx.HLE/HOS/Horizon.cs +++ b/Ryujinx.HLE/HOS/Horizon.cs @@ -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) diff --git a/Ryujinx.HLE/HOS/Services/Time/Clock/StandardSteadyClockCore.cs b/Ryujinx.HLE/HOS/Services/Time/Clock/StandardSteadyClockCore.cs index e00be212e8..c68e8e4a32 100644 --- a/Ryujinx.HLE/HOS/Services/Time/Clock/StandardSteadyClockCore.cs +++ b/Ryujinx.HLE/HOS/Services/Time/Clock/StandardSteadyClockCore.cs @@ -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; } } } diff --git a/Ryujinx.HLE/HOS/Services/Time/Clock/StandardUserSystemClockCore.cs b/Ryujinx.HLE/HOS/Services/Time/Clock/StandardUserSystemClockCore.cs index 61a5eb2a75..7b2249cc26 100644 --- a/Ryujinx.HLE/HOS/Services/Time/Clock/StandardUserSystemClockCore.cs +++ b/Ryujinx.HLE/HOS/Services/Time/Clock/StandardUserSystemClockCore.cs @@ -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(); + } } } diff --git a/Ryujinx.HLE/HOS/Services/Time/Clock/SteadyClockCore.cs b/Ryujinx.HLE/HOS/Services/Time/Clock/SteadyClockCore.cs index 2f54f96db1..350dd89e3b 100644 --- a/Ryujinx.HLE/HOS/Services/Time/Clock/SteadyClockCore.cs +++ b/Ryujinx.HLE/HOS/Services/Time/Clock/SteadyClockCore.cs @@ -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); diff --git a/Ryujinx.HLE/HOS/Services/Time/Clock/TickBasedSteadyClockCore.cs b/Ryujinx.HLE/HOS/Services/Time/Clock/TickBasedSteadyClockCore.cs index 3579975753..0650208276 100644 --- a/Ryujinx.HLE/HOS/Services/Time/Clock/TickBasedSteadyClockCore.cs +++ b/Ryujinx.HLE/HOS/Services/Time/Clock/TickBasedSteadyClockCore.cs @@ -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(); diff --git a/Ryujinx.HLE/HOS/Services/Time/Clock/Types/SteadyClockTimePoint.cs b/Ryujinx.HLE/HOS/Services/Time/Clock/Types/SteadyClockTimePoint.cs index 0055b5ead5..71fb45212f 100644 --- a/Ryujinx.HLE/HOS/Services/Time/Clock/Types/SteadyClockTimePoint.cs +++ b/Ryujinx.HLE/HOS/Services/Time/Clock/Types/SteadyClockTimePoint.cs @@ -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()) + }; + } } } \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Time/Clock/Types/TimeSpanType.cs b/Ryujinx.HLE/HOS/Services/Time/Clock/Types/TimeSpanType.cs index 93579709f0..c336ad4196 100644 --- a/Ryujinx.HLE/HOS/Services/Time/Clock/Types/TimeSpanType.cs +++ b/Ryujinx.HLE/HOS/Services/Time/Clock/Types/TimeSpanType.cs @@ -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) diff --git a/Ryujinx.HLE/HOS/Services/Time/IStaticService.cs b/Ryujinx.HLE/HOS/Services/Time/IStaticService.cs index 97ce2ceba6..93bdfa118d 100644 --- a/Ryujinx.HLE/HOS/Services/Time/IStaticService.cs +++ b/Ryujinx.HLE/HOS/Services/Time/IStaticService.cs @@ -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!"); } diff --git a/Ryujinx.HLE/HOS/Services/Time/ITimeServiceManager.cs b/Ryujinx.HLE/HOS/Services/Time/ITimeServiceManager.cs index 042fc8d2fc..7caea7540f 100644 --- a/Ryujinx.HLE/HOS/Services/Time/ITimeServiceManager.cs +++ b/Ryujinx.HLE/HOS/Services/Time/ITimeServiceManager.cs @@ -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 + public ResultCode GetUserStaticService(ServiceCtx context) + { + MakeObject(context, new IStaticService(_timeManager, TimePermissions.User)); + + return ResultCode.Success; + } + + [Command(5)] + // GetAdminStaticService() -> object + public ResultCode GetAdminStaticService(ServiceCtx context) + { + MakeObject(context, new IStaticService(_timeManager, TimePermissions.Admin)); + + return ResultCode.Success; + } + + [Command(6)] + // GetRepairStaticService() -> object + public ResultCode GetRepairStaticService(ServiceCtx context) + { + MakeObject(context, new IStaticService(_timeManager, TimePermissions.Repair)); + + return ResultCode.Success; + } + + [Command(9)] + // GetManufactureStaticService() -> object + 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(); + TimeSpanType setupValue = context.RequestData.ReadStruct(); + TimeSpanType internalOffset = context.RequestData.ReadStruct(); + TimeSpanType testOffset = context.RequestData.ReadStruct(); + 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(); + 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(); + TimeSpanType sufficientAccuracy = context.RequestData.ReadStruct(); + + _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(); + + _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 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 + public ResultCode Unknown50(ServiceCtx context) + { + // TODO: figure out the usage of this event + throw new ServiceNotImplementedException(context); + } + + [Command(51)] + // Unknown51() -> handle + public ResultCode Unknown51(ServiceCtx context) + { + // TODO: figure out the usage of this event + throw new ServiceNotImplementedException(context); + } + + [Command(52)] + // Unknown52() -> handle + public ResultCode Unknown52(ServiceCtx context) + { + // TODO: figure out the usage of this event + throw new ServiceNotImplementedException(context); + } + + [Command(60)] + // GetStandardUserSystemClockAutomaticCorrectionEvent() -> handle + 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(); + + _timeManager.SetStandardSteadyClockRtcOffset(context.Thread, rtcOffset); + + return ResultCode.Success; + } + + [Command(200)] + // GetAlarmRegistrationEvent() -> handle + 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; + } } -} \ No newline at end of file +} diff --git a/Ryujinx.HLE/HOS/Services/Time/TimeManager.cs b/Ryujinx.HLE/HOS/Services/Time/TimeManager.cs index d12ef39b50..ca8c7857c3 100644 --- a/Ryujinx.HLE/HOS/Services/Time/TimeManager.cs +++ b/Ryujinx.HLE/HOS/Services/Time/TimeManager.cs @@ -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); } } } diff --git a/Ryujinx.HLE/HOS/Services/Time/TimeSharedMemory.cs b/Ryujinx.HLE/HOS/Services/Time/TimeSharedMemory.cs new file mode 100644 index 0000000000..8b51206323 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Time/TimeSharedMemory.cs @@ -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 + } + } +} diff --git a/Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZoneManager.cs b/Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZoneManager.cs index 0493e401b2..28aed3d262 100644 --- a/Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZoneManager.cs +++ b/Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZoneManager.cs @@ -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;