diff options
| author | 2023-10-29 13:50:55 +0000 | |
|---|---|---|
| committer | 2024-01-24 04:26:55 +0000 | |
| commit | e4915fb7d2077584a11a15141bc81d28ed2b0125 (patch) | |
| tree | 1783055dc2e98eaf9099e8e7b194b55f8f607747 /src/core/hle/service/glue | |
| parent | Merge pull request #12678 from german77/settings_impl (diff) | |
| download | yuzu-e4915fb7d2077584a11a15141bc81d28ed2b0125.tar.gz yuzu-e4915fb7d2077584a11a15141bc81d28ed2b0125.tar.xz yuzu-e4915fb7d2077584a11a15141bc81d28ed2b0125.zip | |
Rework time service to fix time passing offline.
Diffstat (limited to 'src/core/hle/service/glue')
19 files changed, 2404 insertions, 0 deletions
diff --git a/src/core/hle/service/glue/glue.cpp b/src/core/hle/service/glue/glue.cpp index 993c3d21d..10376bfac 100644 --- a/src/core/hle/service/glue/glue.cpp +++ b/src/core/hle/service/glue/glue.cpp | |||
| @@ -8,6 +8,9 @@ | |||
| 8 | #include "core/hle/service/glue/ectx.h" | 8 | #include "core/hle/service/glue/ectx.h" |
| 9 | #include "core/hle/service/glue/glue.h" | 9 | #include "core/hle/service/glue/glue.h" |
| 10 | #include "core/hle/service/glue/notif.h" | 10 | #include "core/hle/service/glue/notif.h" |
| 11 | #include "core/hle/service/glue/time/manager.h" | ||
| 12 | #include "core/hle/service/glue/time/static.h" | ||
| 13 | #include "core/hle/service/psc/time/common.h" | ||
| 11 | #include "core/hle/service/server_manager.h" | 14 | #include "core/hle/service/server_manager.h" |
| 12 | 15 | ||
| 13 | namespace Service::Glue { | 16 | namespace Service::Glue { |
| @@ -31,6 +34,22 @@ void LoopProcess(Core::System& system) { | |||
| 31 | // Notification Services for application | 34 | // Notification Services for application |
| 32 | server_manager->RegisterNamedService("notif:a", std::make_shared<NOTIF_A>(system)); | 35 | server_manager->RegisterNamedService("notif:a", std::make_shared<NOTIF_A>(system)); |
| 33 | 36 | ||
| 37 | // Time | ||
| 38 | auto time = std::make_shared<Time::TimeManager>(system); | ||
| 39 | |||
| 40 | server_manager->RegisterNamedService( | ||
| 41 | "time:u", | ||
| 42 | std::make_shared<Time::StaticService>( | ||
| 43 | system, Service::PSC::Time::StaticServiceSetupInfo{0, 0, 0, 0, 0, 0}, time, "time:u")); | ||
| 44 | server_manager->RegisterNamedService( | ||
| 45 | "time:a", | ||
| 46 | std::make_shared<Time::StaticService>( | ||
| 47 | system, Service::PSC::Time::StaticServiceSetupInfo{1, 1, 0, 1, 0, 0}, time, "time:a")); | ||
| 48 | server_manager->RegisterNamedService( | ||
| 49 | "time:r", | ||
| 50 | std::make_shared<Time::StaticService>( | ||
| 51 | system, Service::PSC::Time::StaticServiceSetupInfo{0, 0, 0, 0, 1, 0}, time, "time:r")); | ||
| 52 | |||
| 34 | ServerManager::RunServer(std::move(server_manager)); | 53 | ServerManager::RunServer(std::move(server_manager)); |
| 35 | } | 54 | } |
| 36 | 55 | ||
diff --git a/src/core/hle/service/glue/time/alarm_worker.cpp b/src/core/hle/service/glue/time/alarm_worker.cpp new file mode 100644 index 000000000..f549ed00a --- /dev/null +++ b/src/core/hle/service/glue/time/alarm_worker.cpp | |||
| @@ -0,0 +1,82 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "core/core.h" | ||
| 5 | #include "core/core_timing.h" | ||
| 6 | #include "core/hle/kernel/svc.h" | ||
| 7 | #include "core/hle/service/glue/time/alarm_worker.h" | ||
| 8 | #include "core/hle/service/psc/time/service_manager.h" | ||
| 9 | #include "core/hle/service/sm/sm.h" | ||
| 10 | |||
| 11 | namespace Service::Glue::Time { | ||
| 12 | |||
| 13 | AlarmWorker::AlarmWorker(Core::System& system, StandardSteadyClockResource& steady_clock_resource) | ||
| 14 | : m_system{system}, m_ctx{system, "Glue:AlarmWorker"}, m_steady_clock_resource{ | ||
| 15 | steady_clock_resource} {} | ||
| 16 | |||
| 17 | AlarmWorker::~AlarmWorker() { | ||
| 18 | m_system.CoreTiming().UnscheduleEvent(m_timer_timing_event); | ||
| 19 | |||
| 20 | m_ctx.CloseEvent(m_timer_event); | ||
| 21 | } | ||
| 22 | |||
| 23 | void AlarmWorker::Initialize(std::shared_ptr<Service::PSC::Time::ServiceManager> time_m) { | ||
| 24 | m_time_m = std::move(time_m); | ||
| 25 | |||
| 26 | m_timer_event = m_ctx.CreateEvent("Glue:AlarmWorker:TimerEvent"); | ||
| 27 | m_timer_timing_event = Core::Timing::CreateEvent( | ||
| 28 | "Glue:AlarmWorker::AlarmTimer", | ||
| 29 | [this](s64 time, | ||
| 30 | std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> { | ||
| 31 | m_timer_event->Signal(); | ||
| 32 | return std::nullopt; | ||
| 33 | }); | ||
| 34 | |||
| 35 | AttachToClosestAlarmEvent(); | ||
| 36 | } | ||
| 37 | |||
| 38 | bool AlarmWorker::GetClosestAlarmInfo(Service::PSC::Time::AlarmInfo& out_alarm_info, | ||
| 39 | s64& out_time) { | ||
| 40 | bool is_valid{}; | ||
| 41 | Service::PSC::Time::AlarmInfo alarm_info{}; | ||
| 42 | s64 closest_time{}; | ||
| 43 | |||
| 44 | auto res = m_time_m->GetClosestAlarmInfo(is_valid, alarm_info, closest_time); | ||
| 45 | ASSERT(res == ResultSuccess); | ||
| 46 | |||
| 47 | if (is_valid) { | ||
| 48 | out_alarm_info = alarm_info; | ||
| 49 | out_time = closest_time; | ||
| 50 | } | ||
| 51 | |||
| 52 | return is_valid; | ||
| 53 | } | ||
| 54 | |||
| 55 | void AlarmWorker::OnPowerStateChanged() { | ||
| 56 | Service::PSC::Time::AlarmInfo closest_alarm_info{}; | ||
| 57 | s64 closest_time{}; | ||
| 58 | if (!GetClosestAlarmInfo(closest_alarm_info, closest_time)) { | ||
| 59 | m_system.CoreTiming().UnscheduleEvent(m_timer_timing_event); | ||
| 60 | m_timer_event->Clear(); | ||
| 61 | return; | ||
| 62 | } | ||
| 63 | |||
| 64 | if (closest_alarm_info.alert_time <= closest_time) { | ||
| 65 | m_time_m->CheckAndSignalAlarms(); | ||
| 66 | } else { | ||
| 67 | auto next_time{closest_alarm_info.alert_time - closest_time}; | ||
| 68 | |||
| 69 | m_system.CoreTiming().UnscheduleEvent(m_timer_timing_event); | ||
| 70 | m_timer_event->Clear(); | ||
| 71 | |||
| 72 | m_system.CoreTiming().ScheduleEvent(std::chrono::nanoseconds(next_time), | ||
| 73 | m_timer_timing_event); | ||
| 74 | } | ||
| 75 | } | ||
| 76 | |||
| 77 | Result AlarmWorker::AttachToClosestAlarmEvent() { | ||
| 78 | m_time_m->GetClosestAlarmUpdatedEvent(&m_event); | ||
| 79 | R_SUCCEED(); | ||
| 80 | } | ||
| 81 | |||
| 82 | } // namespace Service::Glue::Time | ||
diff --git a/src/core/hle/service/glue/time/alarm_worker.h b/src/core/hle/service/glue/time/alarm_worker.h new file mode 100644 index 000000000..f269cffdb --- /dev/null +++ b/src/core/hle/service/glue/time/alarm_worker.h | |||
| @@ -0,0 +1,53 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "common/common_types.h" | ||
| 7 | #include "core/hle/kernel/k_event.h" | ||
| 8 | #include "core/hle/service/kernel_helpers.h" | ||
| 9 | #include "core/hle/service/psc/time/common.h" | ||
| 10 | |||
| 11 | namespace Core { | ||
| 12 | class System; | ||
| 13 | } | ||
| 14 | |||
| 15 | namespace Service::PSC::Time { | ||
| 16 | class ServiceManager; | ||
| 17 | } | ||
| 18 | |||
| 19 | namespace Service::Glue::Time { | ||
| 20 | class StandardSteadyClockResource; | ||
| 21 | |||
| 22 | class AlarmWorker { | ||
| 23 | public: | ||
| 24 | explicit AlarmWorker(Core::System& system, StandardSteadyClockResource& steady_clock_resource); | ||
| 25 | ~AlarmWorker(); | ||
| 26 | |||
| 27 | void Initialize(std::shared_ptr<Service::PSC::Time::ServiceManager> time_m); | ||
| 28 | |||
| 29 | Kernel::KEvent& GetEvent() { | ||
| 30 | return *m_event; | ||
| 31 | } | ||
| 32 | |||
| 33 | Kernel::KEvent& GetTimerEvent() { | ||
| 34 | return *m_timer_event; | ||
| 35 | } | ||
| 36 | |||
| 37 | void OnPowerStateChanged(); | ||
| 38 | |||
| 39 | private: | ||
| 40 | bool GetClosestAlarmInfo(Service::PSC::Time::AlarmInfo& out_alarm_info, s64& out_time); | ||
| 41 | Result AttachToClosestAlarmEvent(); | ||
| 42 | |||
| 43 | Core::System& m_system; | ||
| 44 | KernelHelpers::ServiceContext m_ctx; | ||
| 45 | std::shared_ptr<Service::PSC::Time::ServiceManager> m_time_m; | ||
| 46 | |||
| 47 | Kernel::KEvent* m_event{}; | ||
| 48 | Kernel::KEvent* m_timer_event{}; | ||
| 49 | std::shared_ptr<Core::Timing::EventType> m_timer_timing_event; | ||
| 50 | StandardSteadyClockResource& m_steady_clock_resource; | ||
| 51 | }; | ||
| 52 | |||
| 53 | } // namespace Service::Glue::Time | ||
diff --git a/src/core/hle/service/glue/time/file_timestamp_worker.cpp b/src/core/hle/service/glue/time/file_timestamp_worker.cpp new file mode 100644 index 000000000..5a6309549 --- /dev/null +++ b/src/core/hle/service/glue/time/file_timestamp_worker.cpp | |||
| @@ -0,0 +1,23 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "core/hle/service/glue/time/file_timestamp_worker.h" | ||
| 5 | #include "core/hle/service/psc/time/common.h" | ||
| 6 | #include "core/hle/service/psc/time/system_clock.h" | ||
| 7 | #include "core/hle/service/psc/time/time_zone_service.h" | ||
| 8 | |||
| 9 | namespace Service::Glue::Time { | ||
| 10 | |||
| 11 | void FileTimestampWorker::SetFilesystemPosixTime() { | ||
| 12 | s64 time{}; | ||
| 13 | Service::PSC::Time::CalendarTime calendar_time{}; | ||
| 14 | Service::PSC::Time::CalendarAdditionalInfo additional_info{}; | ||
| 15 | |||
| 16 | if (m_initialized && m_system_clock->GetCurrentTime(time) == ResultSuccess && | ||
| 17 | m_time_zone->ToCalendarTimeWithMyRule(calendar_time, additional_info, time) == | ||
| 18 | ResultSuccess) { | ||
| 19 | // TODO IFileSystemProxy::SetCurrentPosixTime | ||
| 20 | } | ||
| 21 | } | ||
| 22 | |||
| 23 | } // namespace Service::Glue::Time | ||
diff --git a/src/core/hle/service/glue/time/file_timestamp_worker.h b/src/core/hle/service/glue/time/file_timestamp_worker.h new file mode 100644 index 000000000..5f8b9b049 --- /dev/null +++ b/src/core/hle/service/glue/time/file_timestamp_worker.h | |||
| @@ -0,0 +1,28 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <memory> | ||
| 7 | |||
| 8 | #include "common/common_types.h" | ||
| 9 | |||
| 10 | namespace Service::PSC::Time { | ||
| 11 | class SystemClock; | ||
| 12 | class TimeZoneService; | ||
| 13 | } // namespace Service::PSC::Time | ||
| 14 | |||
| 15 | namespace Service::Glue::Time { | ||
| 16 | |||
| 17 | class FileTimestampWorker { | ||
| 18 | public: | ||
| 19 | FileTimestampWorker() = default; | ||
| 20 | |||
| 21 | void SetFilesystemPosixTime(); | ||
| 22 | |||
| 23 | std::shared_ptr<Service::PSC::Time::SystemClock> m_system_clock{}; | ||
| 24 | std::shared_ptr<Service::PSC::Time::TimeZoneService> m_time_zone{}; | ||
| 25 | bool m_initialized{}; | ||
| 26 | }; | ||
| 27 | |||
| 28 | } // namespace Service::Glue::Time | ||
diff --git a/src/core/hle/service/glue/time/manager.cpp b/src/core/hle/service/glue/time/manager.cpp new file mode 100644 index 000000000..6423e5089 --- /dev/null +++ b/src/core/hle/service/glue/time/manager.cpp | |||
| @@ -0,0 +1,277 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include <chrono> | ||
| 5 | |||
| 6 | #include "core/core.h" | ||
| 7 | #include "core/core_timing.h" | ||
| 8 | |||
| 9 | #include "common/settings.h" | ||
| 10 | #include "common/time_zone.h" | ||
| 11 | #include "core/file_sys/vfs.h" | ||
| 12 | #include "core/hle/kernel/svc.h" | ||
| 13 | #include "core/hle/service/glue/time/manager.h" | ||
| 14 | #include "core/hle/service/glue/time/time_zone_binary.h" | ||
| 15 | #include "core/hle/service/psc/time/service_manager.h" | ||
| 16 | #include "core/hle/service/psc/time/static.h" | ||
| 17 | #include "core/hle/service/psc/time/system_clock.h" | ||
| 18 | #include "core/hle/service/psc/time/time_zone_service.h" | ||
| 19 | #include "core/hle/service/set/system_settings_server.h" | ||
| 20 | #include "core/hle/service/sm/sm.h" | ||
| 21 | |||
| 22 | namespace Service::Glue::Time { | ||
| 23 | namespace { | ||
| 24 | |||
| 25 | template <typename T> | ||
| 26 | T GetSettingsItemValue(std::shared_ptr<Service::Set::ISystemSettingsServer>& set_sys, | ||
| 27 | const char* category, const char* name) { | ||
| 28 | std::vector<u8> interval_buf; | ||
| 29 | auto res = set_sys->GetSettingsItemValue(interval_buf, category, name); | ||
| 30 | ASSERT(res == ResultSuccess); | ||
| 31 | |||
| 32 | T v{}; | ||
| 33 | std::memcpy(&v, interval_buf.data(), sizeof(T)); | ||
| 34 | return v; | ||
| 35 | } | ||
| 36 | |||
| 37 | s64 CalendarTimeToEpoch(Service::PSC::Time::CalendarTime calendar) { | ||
| 38 | constexpr auto is_leap = [](s32 year) -> bool { | ||
| 39 | return (((year) % 4) == 0 && (((year) % 100) != 0 || ((year) % 400) == 0)); | ||
| 40 | }; | ||
| 41 | constexpr std::array<s32, 12> MonthStartDayOfYear{ | ||
| 42 | 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, | ||
| 43 | }; | ||
| 44 | |||
| 45 | s16 month_s16{calendar.month}; | ||
| 46 | s8 month{static_cast<s8>(((month_s16 * 43) & ~std::numeric_limits<s16>::max()) + | ||
| 47 | ((month_s16 * 43) >> 9))}; | ||
| 48 | s8 month_index{static_cast<s8>(calendar.month - 12 * month)}; | ||
| 49 | if (month_index == 0) { | ||
| 50 | month_index = 12; | ||
| 51 | } | ||
| 52 | s32 year{(month + calendar.year) - !month_index}; | ||
| 53 | s32 v8{year >= 0 ? year : year + 3}; | ||
| 54 | |||
| 55 | s64 days_since_epoch = calendar.day + MonthStartDayOfYear[month_index - 1]; | ||
| 56 | days_since_epoch += (year * 365) + (v8 / 4) - (year / 100) + (year / 400) - 365; | ||
| 57 | |||
| 58 | if (month_index <= 2 && is_leap(year)) { | ||
| 59 | days_since_epoch--; | ||
| 60 | } | ||
| 61 | auto epoch_s{((24ll * days_since_epoch + calendar.hour) * 60ll + calendar.minute) * 60ll + | ||
| 62 | calendar.second}; | ||
| 63 | return epoch_s - 62135683200ll; | ||
| 64 | } | ||
| 65 | |||
| 66 | s64 GetEpochTimeFromInitialYear(std::shared_ptr<Service::Set::ISystemSettingsServer>& set_sys) { | ||
| 67 | Service::PSC::Time::CalendarTime calendar{ | ||
| 68 | .year = GetSettingsItemValue<s16>(set_sys, "time", "standard_user_clock_initial_year"), | ||
| 69 | .month = 1, | ||
| 70 | .day = 1, | ||
| 71 | .hour = 0, | ||
| 72 | .minute = 0, | ||
| 73 | .second = 0, | ||
| 74 | }; | ||
| 75 | return CalendarTimeToEpoch(calendar); | ||
| 76 | } | ||
| 77 | |||
| 78 | Service::PSC::Time::LocationName GetTimeZoneString(Service::PSC::Time::LocationName& in_name) { | ||
| 79 | auto configured_zone = Settings::GetTimeZoneString(Settings::values.time_zone_index.GetValue()); | ||
| 80 | |||
| 81 | Service::PSC::Time::LocationName configured_name{}; | ||
| 82 | std::memcpy(configured_name.name.data(), configured_zone.data(), | ||
| 83 | std::min(configured_name.name.size(), configured_zone.size())); | ||
| 84 | |||
| 85 | if (!IsTimeZoneBinaryValid(configured_name)) { | ||
| 86 | configured_zone = Common::TimeZone::FindSystemTimeZone(); | ||
| 87 | configured_name = {}; | ||
| 88 | std::memcpy(configured_name.name.data(), configured_zone.data(), | ||
| 89 | std::min(configured_name.name.size(), configured_zone.size())); | ||
| 90 | } | ||
| 91 | |||
| 92 | ASSERT_MSG(IsTimeZoneBinaryValid(configured_name), "Invalid time zone {}!", | ||
| 93 | configured_name.name.data()); | ||
| 94 | |||
| 95 | return configured_name; | ||
| 96 | } | ||
| 97 | |||
| 98 | } // namespace | ||
| 99 | |||
| 100 | TimeManager::TimeManager(Core::System& system) | ||
| 101 | : m_steady_clock_resource{system}, m_worker{system, m_steady_clock_resource, | ||
| 102 | m_file_timestamp_worker} { | ||
| 103 | m_time_m = | ||
| 104 | system.ServiceManager().GetService<Service::PSC::Time::ServiceManager>("time:m", true); | ||
| 105 | |||
| 106 | auto res = m_time_m->GetStaticServiceAsServiceManager(m_time_sm); | ||
| 107 | ASSERT(res == ResultSuccess); | ||
| 108 | |||
| 109 | m_set_sys = | ||
| 110 | system.ServiceManager().GetService<Service::Set::ISystemSettingsServer>("set:sys", true); | ||
| 111 | |||
| 112 | res = MountTimeZoneBinary(system); | ||
| 113 | ASSERT(res == ResultSuccess); | ||
| 114 | |||
| 115 | m_worker.Initialize(m_time_sm, m_set_sys); | ||
| 116 | |||
| 117 | res = m_time_sm->GetStandardUserSystemClock(m_file_timestamp_worker.m_system_clock); | ||
| 118 | ASSERT(res == ResultSuccess); | ||
| 119 | |||
| 120 | res = m_time_sm->GetTimeZoneService(m_file_timestamp_worker.m_time_zone); | ||
| 121 | ASSERT(res == ResultSuccess); | ||
| 122 | |||
| 123 | res = SetupStandardSteadyClockCore(); | ||
| 124 | ASSERT(res == ResultSuccess); | ||
| 125 | |||
| 126 | Service::PSC::Time::SystemClockContext user_clock_context{}; | ||
| 127 | res = m_set_sys->GetUserSystemClockContext(user_clock_context); | ||
| 128 | ASSERT(res == ResultSuccess); | ||
| 129 | |||
| 130 | // TODO the local clock should initialise with this epoch time, and be updated somewhere else on | ||
| 131 | // first boot to update it, but I haven't been able to find that point (likely via ntc's auto | ||
| 132 | // correct as it's defaulted to be enabled). So to get a time that isn't stuck in the past for | ||
| 133 | // first boot, grab the current real seconds. | ||
| 134 | auto epoch_time{GetEpochTimeFromInitialYear(m_set_sys)}; | ||
| 135 | if (user_clock_context == Service::PSC::Time::SystemClockContext{}) { | ||
| 136 | m_steady_clock_resource.GetRtcTimeInSeconds(epoch_time); | ||
| 137 | } | ||
| 138 | |||
| 139 | res = m_time_m->SetupStandardLocalSystemClockCore(user_clock_context, epoch_time); | ||
| 140 | ASSERT(res == ResultSuccess); | ||
| 141 | |||
| 142 | Service::PSC::Time::SystemClockContext network_clock_context{}; | ||
| 143 | res = m_set_sys->GetNetworkSystemClockContext(network_clock_context); | ||
| 144 | ASSERT(res == ResultSuccess); | ||
| 145 | |||
| 146 | auto network_accuracy_m{GetSettingsItemValue<s32>( | ||
| 147 | m_set_sys, "time", "standard_network_clock_sufficient_accuracy_minutes")}; | ||
| 148 | auto one_minute_ns{ | ||
| 149 | std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::minutes(1)).count()}; | ||
| 150 | s64 network_accuracy_ns{network_accuracy_m * one_minute_ns}; | ||
| 151 | |||
| 152 | res = m_time_m->SetupStandardNetworkSystemClockCore(network_clock_context, network_accuracy_ns); | ||
| 153 | ASSERT(res == ResultSuccess); | ||
| 154 | |||
| 155 | bool is_automatic_correction_enabled{}; | ||
| 156 | res = m_set_sys->IsUserSystemClockAutomaticCorrectionEnabled(is_automatic_correction_enabled); | ||
| 157 | ASSERT(res == ResultSuccess); | ||
| 158 | |||
| 159 | Service::PSC::Time::SteadyClockTimePoint automatic_correction_time_point{}; | ||
| 160 | res = m_set_sys->GetUserSystemClockAutomaticCorrectionUpdatedTime( | ||
| 161 | automatic_correction_time_point); | ||
| 162 | ASSERT(res == ResultSuccess); | ||
| 163 | |||
| 164 | res = m_time_m->SetupStandardUserSystemClockCore(automatic_correction_time_point, | ||
| 165 | is_automatic_correction_enabled); | ||
| 166 | ASSERT(res == ResultSuccess); | ||
| 167 | |||
| 168 | res = m_time_m->SetupEphemeralNetworkSystemClockCore(); | ||
| 169 | ASSERT(res == ResultSuccess); | ||
| 170 | |||
| 171 | res = SetupTimeZoneServiceCore(); | ||
| 172 | ASSERT(res == ResultSuccess); | ||
| 173 | |||
| 174 | s64 rtc_time_s{}; | ||
| 175 | res = m_steady_clock_resource.GetRtcTimeInSeconds(rtc_time_s); | ||
| 176 | ASSERT(res == ResultSuccess); | ||
| 177 | |||
| 178 | // TODO system report "launch" | ||
| 179 | // "rtc_reset" = m_steady_clock_resource.m_rtc_reset | ||
| 180 | // "rtc_value" = rtc_time_s | ||
| 181 | |||
| 182 | m_worker.StartThread(); | ||
| 183 | |||
| 184 | m_file_timestamp_worker.m_initialized = true; | ||
| 185 | |||
| 186 | s64 system_clock_time{}; | ||
| 187 | if (m_file_timestamp_worker.m_system_clock->GetCurrentTime(system_clock_time) == | ||
| 188 | ResultSuccess) { | ||
| 189 | Service::PSC::Time::CalendarTime calendar_time{}; | ||
| 190 | Service::PSC::Time::CalendarAdditionalInfo calendar_additional{}; | ||
| 191 | if (m_file_timestamp_worker.m_time_zone->ToCalendarTimeWithMyRule( | ||
| 192 | calendar_time, calendar_additional, system_clock_time) == ResultSuccess) { | ||
| 193 | // TODO IFileSystemProxy::SetCurrentPosixTime(system_clock_time, | ||
| 194 | // calendar_additional.ut_offset) | ||
| 195 | } | ||
| 196 | } | ||
| 197 | } | ||
| 198 | |||
| 199 | Result TimeManager::SetupStandardSteadyClockCore() { | ||
| 200 | Common::UUID external_clock_source_id{}; | ||
| 201 | auto res = m_set_sys->GetExternalSteadyClockSourceId(external_clock_source_id); | ||
| 202 | ASSERT(res == ResultSuccess); | ||
| 203 | |||
| 204 | s64 external_steady_clock_internal_offset_s{}; | ||
| 205 | res = m_set_sys->GetExternalSteadyClockInternalOffset(external_steady_clock_internal_offset_s); | ||
| 206 | ASSERT(res == ResultSuccess); | ||
| 207 | |||
| 208 | auto one_second_ns{ | ||
| 209 | std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::seconds(1)).count()}; | ||
| 210 | s64 external_steady_clock_internal_offset_ns{external_steady_clock_internal_offset_s * | ||
| 211 | one_second_ns}; | ||
| 212 | |||
| 213 | s32 standard_steady_clock_test_offset_m{ | ||
| 214 | GetSettingsItemValue<s32>(m_set_sys, "time", "standard_steady_clock_test_offset_minutes")}; | ||
| 215 | auto one_minute_ns{ | ||
| 216 | std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::minutes(1)).count()}; | ||
| 217 | s64 standard_steady_clock_test_offset_ns{standard_steady_clock_test_offset_m * one_minute_ns}; | ||
| 218 | |||
| 219 | auto reset_detected = m_steady_clock_resource.GetResetDetected(); | ||
| 220 | if (reset_detected) { | ||
| 221 | external_clock_source_id = {}; | ||
| 222 | } | ||
| 223 | |||
| 224 | Common::UUID clock_source_id{}; | ||
| 225 | m_steady_clock_resource.Initialize(&clock_source_id, &external_clock_source_id); | ||
| 226 | |||
| 227 | if (clock_source_id != external_clock_source_id) { | ||
| 228 | m_set_sys->SetExternalSteadyClockSourceId(clock_source_id); | ||
| 229 | } | ||
| 230 | |||
| 231 | res = m_time_m->SetupStandardSteadyClockCore(clock_source_id, m_steady_clock_resource.GetTime(), | ||
| 232 | external_steady_clock_internal_offset_ns, | ||
| 233 | standard_steady_clock_test_offset_ns, | ||
| 234 | reset_detected); | ||
| 235 | ASSERT(res == ResultSuccess); | ||
| 236 | R_SUCCEED(); | ||
| 237 | } | ||
| 238 | |||
| 239 | Result TimeManager::SetupTimeZoneServiceCore() { | ||
| 240 | Service::PSC::Time::LocationName name{}; | ||
| 241 | auto res = m_set_sys->GetDeviceTimeZoneLocationName(name); | ||
| 242 | ASSERT(res == ResultSuccess); | ||
| 243 | |||
| 244 | auto configured_zone = GetTimeZoneString(name); | ||
| 245 | |||
| 246 | if (configured_zone.name != name.name) { | ||
| 247 | m_set_sys->SetDeviceTimeZoneLocationName(configured_zone); | ||
| 248 | name = configured_zone; | ||
| 249 | |||
| 250 | std::shared_ptr<Service::PSC::Time::SystemClock> local_clock; | ||
| 251 | m_time_sm->GetStandardLocalSystemClock(local_clock); | ||
| 252 | Service::PSC::Time::SystemClockContext context{}; | ||
| 253 | local_clock->GetSystemClockContext(context); | ||
| 254 | m_set_sys->SetDeviceTimeZoneLocationUpdatedTime(context.steady_time_point); | ||
| 255 | } | ||
| 256 | |||
| 257 | Service::PSC::Time::SteadyClockTimePoint time_point{}; | ||
| 258 | res = m_set_sys->GetDeviceTimeZoneLocationUpdatedTime(time_point); | ||
| 259 | ASSERT(res == ResultSuccess); | ||
| 260 | |||
| 261 | auto location_count = GetTimeZoneCount(); | ||
| 262 | Service::PSC::Time::RuleVersion rule_version{}; | ||
| 263 | GetTimeZoneVersion(rule_version); | ||
| 264 | |||
| 265 | std::span<const u8> rule_buffer{}; | ||
| 266 | size_t rule_size{}; | ||
| 267 | res = GetTimeZoneRule(rule_buffer, rule_size, name); | ||
| 268 | ASSERT(res == ResultSuccess); | ||
| 269 | |||
| 270 | res = m_time_m->SetupTimeZoneServiceCore(name, time_point, rule_version, location_count, | ||
| 271 | rule_buffer); | ||
| 272 | ASSERT(res == ResultSuccess); | ||
| 273 | |||
| 274 | R_SUCCEED(); | ||
| 275 | } | ||
| 276 | |||
| 277 | } // namespace Service::Glue::Time | ||
diff --git a/src/core/hle/service/glue/time/manager.h b/src/core/hle/service/glue/time/manager.h new file mode 100644 index 000000000..a46ec6364 --- /dev/null +++ b/src/core/hle/service/glue/time/manager.h | |||
| @@ -0,0 +1,42 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <functional> | ||
| 7 | #include <string> | ||
| 8 | |||
| 9 | #include "common/common_types.h" | ||
| 10 | #include "core/file_sys/vfs_types.h" | ||
| 11 | #include "core/hle/service/glue/time/file_timestamp_worker.h" | ||
| 12 | #include "core/hle/service/glue/time/standard_steady_clock_resource.h" | ||
| 13 | #include "core/hle/service/glue/time/worker.h" | ||
| 14 | #include "core/hle/service/service.h" | ||
| 15 | |||
| 16 | namespace Core { | ||
| 17 | class System; | ||
| 18 | } | ||
| 19 | |||
| 20 | namespace Service::PSC::Time { | ||
| 21 | class ServiceManager; | ||
| 22 | class StaticService; | ||
| 23 | } // namespace Service::PSC::Time | ||
| 24 | |||
| 25 | namespace Service::Glue::Time { | ||
| 26 | class TimeManager { | ||
| 27 | public: | ||
| 28 | explicit TimeManager(Core::System& system); | ||
| 29 | |||
| 30 | std::shared_ptr<Service::Set::ISystemSettingsServer> m_set_sys; | ||
| 31 | |||
| 32 | std::shared_ptr<Service::PSC::Time::ServiceManager> m_time_m{}; | ||
| 33 | std::shared_ptr<Service::PSC::Time::StaticService> m_time_sm{}; | ||
| 34 | StandardSteadyClockResource m_steady_clock_resource; | ||
| 35 | FileTimestampWorker m_file_timestamp_worker; | ||
| 36 | TimeWorker m_worker; | ||
| 37 | |||
| 38 | private: | ||
| 39 | Result SetupStandardSteadyClockCore(); | ||
| 40 | Result SetupTimeZoneServiceCore(); | ||
| 41 | }; | ||
| 42 | } // namespace Service::Glue::Time | ||
diff --git a/src/core/hle/service/glue/time/pm_state_change_handler.cpp b/src/core/hle/service/glue/time/pm_state_change_handler.cpp new file mode 100644 index 000000000..7470fb225 --- /dev/null +++ b/src/core/hle/service/glue/time/pm_state_change_handler.cpp | |||
| @@ -0,0 +1,13 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "core/hle/service/glue/time/pm_state_change_handler.h" | ||
| 5 | |||
| 6 | namespace Service::Glue::Time { | ||
| 7 | |||
| 8 | PmStateChangeHandler::PmStateChangeHandler(AlarmWorker& alarm_worker) | ||
| 9 | : m_alarm_worker{alarm_worker} { | ||
| 10 | // TODO Initialize IPmModule, dependent on Rtc and Fs | ||
| 11 | } | ||
| 12 | |||
| 13 | } // namespace Service::Glue::Time | ||
diff --git a/src/core/hle/service/glue/time/pm_state_change_handler.h b/src/core/hle/service/glue/time/pm_state_change_handler.h new file mode 100644 index 000000000..27d9f7872 --- /dev/null +++ b/src/core/hle/service/glue/time/pm_state_change_handler.h | |||
| @@ -0,0 +1,18 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "common/common_types.h" | ||
| 7 | |||
| 8 | namespace Service::Glue::Time { | ||
| 9 | class AlarmWorker; | ||
| 10 | |||
| 11 | class PmStateChangeHandler { | ||
| 12 | public: | ||
| 13 | explicit PmStateChangeHandler(AlarmWorker& alarm_worker); | ||
| 14 | |||
| 15 | AlarmWorker& m_alarm_worker; | ||
| 16 | s32 m_priority{}; | ||
| 17 | }; | ||
| 18 | } // namespace Service::Glue::Time | ||
diff --git a/src/core/hle/service/glue/time/standard_steady_clock_resource.cpp b/src/core/hle/service/glue/time/standard_steady_clock_resource.cpp new file mode 100644 index 000000000..5ebaa33e0 --- /dev/null +++ b/src/core/hle/service/glue/time/standard_steady_clock_resource.cpp | |||
| @@ -0,0 +1,123 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include <chrono> | ||
| 5 | |||
| 6 | #include "common/settings.h" | ||
| 7 | #include "core/core.h" | ||
| 8 | #include "core/core_timing.h" | ||
| 9 | #include "core/hle/kernel/svc.h" | ||
| 10 | #include "core/hle/service/glue/time/standard_steady_clock_resource.h" | ||
| 11 | #include "core/hle/service/psc/time/errors.h" | ||
| 12 | |||
| 13 | namespace Service::Glue::Time { | ||
| 14 | namespace { | ||
| 15 | [[maybe_unused]] constexpr u32 Max77620PmicSession = 0x3A000001; | ||
| 16 | [[maybe_unused]] constexpr u32 Max77620RtcSession = 0x3B000001; | ||
| 17 | |||
| 18 | Result GetTimeInSeconds(Core::System& system, s64& out_time_s) { | ||
| 19 | out_time_s = std::chrono::duration_cast<std::chrono::seconds>( | ||
| 20 | std::chrono::system_clock::now().time_since_epoch()) | ||
| 21 | .count(); | ||
| 22 | |||
| 23 | if (Settings::values.custom_rtc_enabled) { | ||
| 24 | out_time_s += Settings::values.custom_rtc_offset.GetValue(); | ||
| 25 | } | ||
| 26 | R_SUCCEED(); | ||
| 27 | } | ||
| 28 | } // namespace | ||
| 29 | |||
| 30 | StandardSteadyClockResource::StandardSteadyClockResource(Core::System& system) : m_system{system} {} | ||
| 31 | |||
| 32 | void StandardSteadyClockResource::Initialize(Common::UUID* out_source_id, | ||
| 33 | Common::UUID* external_source_id) { | ||
| 34 | constexpr size_t NUM_TRIES{20}; | ||
| 35 | |||
| 36 | size_t i{0}; | ||
| 37 | Result res{ResultSuccess}; | ||
| 38 | for (; i < NUM_TRIES; i++) { | ||
| 39 | res = SetCurrentTime(); | ||
| 40 | if (res == ResultSuccess) { | ||
| 41 | break; | ||
| 42 | } | ||
| 43 | Kernel::Svc::SleepThread(m_system, std::chrono::duration_cast<std::chrono::nanoseconds>( | ||
| 44 | std::chrono::milliseconds(1)) | ||
| 45 | .count()); | ||
| 46 | } | ||
| 47 | |||
| 48 | if (i < NUM_TRIES) { | ||
| 49 | m_set_time_result = ResultSuccess; | ||
| 50 | if (*external_source_id != Service::PSC::Time::ClockSourceId{}) { | ||
| 51 | m_clock_source_id = *external_source_id; | ||
| 52 | } else { | ||
| 53 | m_clock_source_id = Common::UUID::MakeRandom(); | ||
| 54 | } | ||
| 55 | } else { | ||
| 56 | m_set_time_result = res; | ||
| 57 | auto ticks{m_system.CoreTiming().GetClockTicks()}; | ||
| 58 | m_time = -Service::PSC::Time::ConvertToTimeSpan(ticks).count(); | ||
| 59 | m_clock_source_id = Common::UUID::MakeRandom(); | ||
| 60 | } | ||
| 61 | |||
| 62 | if (out_source_id) { | ||
| 63 | *out_source_id = m_clock_source_id; | ||
| 64 | } | ||
| 65 | } | ||
| 66 | |||
| 67 | bool StandardSteadyClockResource::GetResetDetected() { | ||
| 68 | // TODO: | ||
| 69 | // call Rtc::GetRtcResetDetected(Max77620RtcSession) | ||
| 70 | // if detected: | ||
| 71 | // SetSys::SetExternalSteadyClockSourceId(invalid_id) | ||
| 72 | // Rtc::ClearRtcResetDetected(Max77620RtcSession) | ||
| 73 | // set m_rtc_reset to result | ||
| 74 | // Instead, only set reset to true if we're booting for the first time. | ||
| 75 | m_rtc_reset = false; | ||
| 76 | return m_rtc_reset; | ||
| 77 | } | ||
| 78 | |||
| 79 | Result StandardSteadyClockResource::SetCurrentTime() { | ||
| 80 | auto start_tick{m_system.CoreTiming().GetClockTicks()}; | ||
| 81 | |||
| 82 | s64 rtc_time_s{}; | ||
| 83 | // TODO R_TRY(Rtc::GetTimeInSeconds(rtc_time_s, Max77620RtcSession)) | ||
| 84 | R_TRY(GetTimeInSeconds(m_system, rtc_time_s)); | ||
| 85 | |||
| 86 | auto end_tick{m_system.CoreTiming().GetClockTicks()}; | ||
| 87 | auto diff{Service::PSC::Time::ConvertToTimeSpan(end_tick - start_tick)}; | ||
| 88 | // Why is this here? | ||
| 89 | R_UNLESS(diff < std::chrono::milliseconds(101), Service::PSC::Time::ResultRtcTimeout); | ||
| 90 | |||
| 91 | auto one_second_ns{ | ||
| 92 | std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::seconds(1)).count()}; | ||
| 93 | s64 boot_time{rtc_time_s * one_second_ns - | ||
| 94 | Service::PSC::Time::ConvertToTimeSpan(end_tick).count()}; | ||
| 95 | |||
| 96 | std::scoped_lock l{m_mutex}; | ||
| 97 | m_time = boot_time; | ||
| 98 | R_SUCCEED(); | ||
| 99 | } | ||
| 100 | |||
| 101 | Result StandardSteadyClockResource::GetRtcTimeInSeconds(s64& out_time) { | ||
| 102 | // TODO | ||
| 103 | // R_TRY(Rtc::GetTimeInSeconds(time_s, Max77620RtcSession) | ||
| 104 | R_RETURN(GetTimeInSeconds(m_system, out_time)); | ||
| 105 | } | ||
| 106 | |||
| 107 | void StandardSteadyClockResource::UpdateTime() { | ||
| 108 | constexpr size_t NUM_TRIES{3}; | ||
| 109 | |||
| 110 | size_t i{0}; | ||
| 111 | Result res{ResultSuccess}; | ||
| 112 | for (; i < NUM_TRIES; i++) { | ||
| 113 | res = SetCurrentTime(); | ||
| 114 | if (res == ResultSuccess) { | ||
| 115 | break; | ||
| 116 | } | ||
| 117 | Kernel::Svc::SleepThread(m_system, std::chrono::duration_cast<std::chrono::nanoseconds>( | ||
| 118 | std::chrono::milliseconds(1)) | ||
| 119 | .count()); | ||
| 120 | } | ||
| 121 | } | ||
| 122 | |||
| 123 | } // namespace Service::Glue::Time | ||
diff --git a/src/core/hle/service/glue/time/standard_steady_clock_resource.h b/src/core/hle/service/glue/time/standard_steady_clock_resource.h new file mode 100644 index 000000000..978d6b63b --- /dev/null +++ b/src/core/hle/service/glue/time/standard_steady_clock_resource.h | |||
| @@ -0,0 +1,41 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <mutex> | ||
| 7 | |||
| 8 | #include "common/common_types.h" | ||
| 9 | #include "core/hle/result.h" | ||
| 10 | #include "core/hle/service/psc/time/common.h" | ||
| 11 | |||
| 12 | namespace Core { | ||
| 13 | class System; | ||
| 14 | } | ||
| 15 | |||
| 16 | namespace Service::Glue::Time { | ||
| 17 | class StandardSteadyClockResource { | ||
| 18 | public: | ||
| 19 | StandardSteadyClockResource(Core::System& system); | ||
| 20 | |||
| 21 | void Initialize(Common::UUID* out_source_id, Common::UUID* external_source_id); | ||
| 22 | |||
| 23 | s64 GetTime() const { | ||
| 24 | return m_time; | ||
| 25 | } | ||
| 26 | |||
| 27 | bool GetResetDetected(); | ||
| 28 | Result SetCurrentTime(); | ||
| 29 | Result GetRtcTimeInSeconds(s64& out_time); | ||
| 30 | void UpdateTime(); | ||
| 31 | |||
| 32 | private: | ||
| 33 | Core::System& m_system; | ||
| 34 | |||
| 35 | std::mutex m_mutex; | ||
| 36 | Service::PSC::Time::ClockSourceId m_clock_source_id{}; | ||
| 37 | s64 m_time{}; | ||
| 38 | Result m_set_time_result; | ||
| 39 | bool m_rtc_reset; | ||
| 40 | }; | ||
| 41 | } // namespace Service::Glue::Time | ||
diff --git a/src/core/hle/service/glue/time/static.cpp b/src/core/hle/service/glue/time/static.cpp new file mode 100644 index 000000000..63b7d91da --- /dev/null +++ b/src/core/hle/service/glue/time/static.cpp | |||
| @@ -0,0 +1,448 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include <chrono> | ||
| 5 | |||
| 6 | #include "core/core.h" | ||
| 7 | #include "core/hle/kernel/k_shared_memory.h" | ||
| 8 | #include "core/hle/kernel/svc.h" | ||
| 9 | #include "core/hle/service/glue/time/file_timestamp_worker.h" | ||
| 10 | #include "core/hle/service/glue/time/static.h" | ||
| 11 | #include "core/hle/service/psc/time/errors.h" | ||
| 12 | #include "core/hle/service/psc/time/service_manager.h" | ||
| 13 | #include "core/hle/service/psc/time/static.h" | ||
| 14 | #include "core/hle/service/psc/time/steady_clock.h" | ||
| 15 | #include "core/hle/service/psc/time/system_clock.h" | ||
| 16 | #include "core/hle/service/psc/time/time_zone_service.h" | ||
| 17 | #include "core/hle/service/set/system_settings_server.h" | ||
| 18 | #include "core/hle/service/sm/sm.h" | ||
| 19 | |||
| 20 | namespace Service::Glue::Time { | ||
| 21 | namespace { | ||
| 22 | template <typename T> | ||
| 23 | T GetSettingsItemValue(std::shared_ptr<Service::Set::ISystemSettingsServer>& set_sys, | ||
| 24 | const char* category, const char* name) { | ||
| 25 | std::vector<u8> interval_buf; | ||
| 26 | auto res = set_sys->GetSettingsItemValue(interval_buf, category, name); | ||
| 27 | ASSERT(res == ResultSuccess); | ||
| 28 | |||
| 29 | T v{}; | ||
| 30 | std::memcpy(&v, interval_buf.data(), sizeof(T)); | ||
| 31 | return v; | ||
| 32 | } | ||
| 33 | } // namespace | ||
| 34 | |||
| 35 | StaticService::StaticService(Core::System& system_, | ||
| 36 | Service::PSC::Time::StaticServiceSetupInfo setup_info, | ||
| 37 | std::shared_ptr<TimeManager> time, const char* name) | ||
| 38 | : ServiceFramework{system_, name}, m_system{system_}, m_time_m{time->m_time_m}, | ||
| 39 | m_setup_info{setup_info}, m_time_sm{time->m_time_sm}, | ||
| 40 | m_file_timestamp_worker{time->m_file_timestamp_worker}, m_standard_steady_clock_resource{ | ||
| 41 | time->m_steady_clock_resource} { | ||
| 42 | // clang-format off | ||
| 43 | static const FunctionInfo functions[] = { | ||
| 44 | {0, &StaticService::Handle_GetStandardUserSystemClock, "GetStandardUserSystemClock"}, | ||
| 45 | {1, &StaticService::Handle_GetStandardNetworkSystemClock, "GetStandardNetworkSystemClock"}, | ||
| 46 | {2, &StaticService::Handle_GetStandardSteadyClock, "GetStandardSteadyClock"}, | ||
| 47 | {3, &StaticService::Handle_GetTimeZoneService, "GetTimeZoneService"}, | ||
| 48 | {4, &StaticService::Handle_GetStandardLocalSystemClock, "GetStandardLocalSystemClock"}, | ||
| 49 | {5, &StaticService::Handle_GetEphemeralNetworkSystemClock, "GetEphemeralNetworkSystemClock"}, | ||
| 50 | {20, &StaticService::Handle_GetSharedMemoryNativeHandle, "GetSharedMemoryNativeHandle"}, | ||
| 51 | {50, &StaticService::Handle_SetStandardSteadyClockInternalOffset, "SetStandardSteadyClockInternalOffset"}, | ||
| 52 | {51, &StaticService::Handle_GetStandardSteadyClockRtcValue, "GetStandardSteadyClockRtcValue"}, | ||
| 53 | {100, &StaticService::Handle_IsStandardUserSystemClockAutomaticCorrectionEnabled, "IsStandardUserSystemClockAutomaticCorrectionEnabled"}, | ||
| 54 | {101, &StaticService::Handle_SetStandardUserSystemClockAutomaticCorrectionEnabled, "SetStandardUserSystemClockAutomaticCorrectionEnabled"}, | ||
| 55 | {102, &StaticService::Handle_GetStandardUserSystemClockInitialYear, "GetStandardUserSystemClockInitialYear"}, | ||
| 56 | {200, &StaticService::Handle_IsStandardNetworkSystemClockAccuracySufficient, "IsStandardNetworkSystemClockAccuracySufficient"}, | ||
| 57 | {201, &StaticService::Handle_GetStandardUserSystemClockAutomaticCorrectionUpdatedTime, "GetStandardUserSystemClockAutomaticCorrectionUpdatedTime"}, | ||
| 58 | {300, &StaticService::Handle_CalculateMonotonicSystemClockBaseTimePoint, "CalculateMonotonicSystemClockBaseTimePoint"}, | ||
| 59 | {400, &StaticService::Handle_GetClockSnapshot, "GetClockSnapshot"}, | ||
| 60 | {401, &StaticService::Handle_GetClockSnapshotFromSystemClockContext, "GetClockSnapshotFromSystemClockContext"}, | ||
| 61 | {500, &StaticService::Handle_CalculateStandardUserSystemClockDifferenceByUser, "CalculateStandardUserSystemClockDifferenceByUser"}, | ||
| 62 | {501, &StaticService::Handle_CalculateSpanBetween, "CalculateSpanBetween"}, | ||
| 63 | }; | ||
| 64 | // clang-format on | ||
| 65 | |||
| 66 | RegisterHandlers(functions); | ||
| 67 | |||
| 68 | m_set_sys = | ||
| 69 | m_system.ServiceManager().GetService<Service::Set::ISystemSettingsServer>("set:sys", true); | ||
| 70 | |||
| 71 | if (m_setup_info.can_write_local_clock && m_setup_info.can_write_user_clock && | ||
| 72 | !m_setup_info.can_write_network_clock && m_setup_info.can_write_timezone_device_location && | ||
| 73 | !m_setup_info.can_write_steady_clock && !m_setup_info.can_write_uninitialized_clock) { | ||
| 74 | m_time_m->GetStaticServiceAsAdmin(m_wrapped_service); | ||
| 75 | } else if (!m_setup_info.can_write_local_clock && !m_setup_info.can_write_user_clock && | ||
| 76 | !m_setup_info.can_write_network_clock && | ||
| 77 | !m_setup_info.can_write_timezone_device_location && | ||
| 78 | !m_setup_info.can_write_steady_clock && | ||
| 79 | !m_setup_info.can_write_uninitialized_clock) { | ||
| 80 | m_time_m->GetStaticServiceAsUser(m_wrapped_service); | ||
| 81 | } else if (!m_setup_info.can_write_local_clock && !m_setup_info.can_write_user_clock && | ||
| 82 | !m_setup_info.can_write_network_clock && | ||
| 83 | !m_setup_info.can_write_timezone_device_location && | ||
| 84 | m_setup_info.can_write_steady_clock && !m_setup_info.can_write_uninitialized_clock) { | ||
| 85 | m_time_m->GetStaticServiceAsRepair(m_wrapped_service); | ||
| 86 | } else { | ||
| 87 | UNREACHABLE(); | ||
| 88 | } | ||
| 89 | |||
| 90 | auto res = m_wrapped_service->GetTimeZoneService(m_time_zone); | ||
| 91 | ASSERT(res == ResultSuccess); | ||
| 92 | } | ||
| 93 | |||
| 94 | void StaticService::Handle_GetStandardUserSystemClock(HLERequestContext& ctx) { | ||
| 95 | LOG_DEBUG(Service_Time, "called."); | ||
| 96 | |||
| 97 | std::shared_ptr<Service::PSC::Time::SystemClock> service{}; | ||
| 98 | auto res = GetStandardUserSystemClock(service); | ||
| 99 | |||
| 100 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||
| 101 | rb.Push(res); | ||
| 102 | rb.PushIpcInterface<Service::PSC::Time::SystemClock>(std::move(service)); | ||
| 103 | } | ||
| 104 | |||
| 105 | void StaticService::Handle_GetStandardNetworkSystemClock(HLERequestContext& ctx) { | ||
| 106 | LOG_DEBUG(Service_Time, "called."); | ||
| 107 | |||
| 108 | std::shared_ptr<Service::PSC::Time::SystemClock> service{}; | ||
| 109 | auto res = GetStandardNetworkSystemClock(service); | ||
| 110 | |||
| 111 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||
| 112 | rb.Push(res); | ||
| 113 | rb.PushIpcInterface<Service::PSC::Time::SystemClock>(std::move(service)); | ||
| 114 | } | ||
| 115 | |||
| 116 | void StaticService::Handle_GetStandardSteadyClock(HLERequestContext& ctx) { | ||
| 117 | LOG_DEBUG(Service_Time, "called."); | ||
| 118 | |||
| 119 | std::shared_ptr<Service::PSC::Time::SteadyClock> service{}; | ||
| 120 | auto res = GetStandardSteadyClock(service); | ||
| 121 | |||
| 122 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||
| 123 | rb.Push(res); | ||
| 124 | rb.PushIpcInterface(std::move(service)); | ||
| 125 | } | ||
| 126 | |||
| 127 | void StaticService::Handle_GetTimeZoneService(HLERequestContext& ctx) { | ||
| 128 | LOG_DEBUG(Service_Time, "called."); | ||
| 129 | |||
| 130 | std::shared_ptr<TimeZoneService> service{}; | ||
| 131 | auto res = GetTimeZoneService(service); | ||
| 132 | |||
| 133 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||
| 134 | rb.Push(res); | ||
| 135 | rb.PushIpcInterface(std::move(service)); | ||
| 136 | } | ||
| 137 | |||
| 138 | void StaticService::Handle_GetStandardLocalSystemClock(HLERequestContext& ctx) { | ||
| 139 | LOG_DEBUG(Service_Time, "called."); | ||
| 140 | |||
| 141 | std::shared_ptr<Service::PSC::Time::SystemClock> service{}; | ||
| 142 | auto res = GetStandardLocalSystemClock(service); | ||
| 143 | |||
| 144 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||
| 145 | rb.Push(res); | ||
| 146 | rb.PushIpcInterface<Service::PSC::Time::SystemClock>(std::move(service)); | ||
| 147 | } | ||
| 148 | |||
| 149 | void StaticService::Handle_GetEphemeralNetworkSystemClock(HLERequestContext& ctx) { | ||
| 150 | LOG_DEBUG(Service_Time, "called."); | ||
| 151 | |||
| 152 | std::shared_ptr<Service::PSC::Time::SystemClock> service{}; | ||
| 153 | auto res = GetEphemeralNetworkSystemClock(service); | ||
| 154 | |||
| 155 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||
| 156 | rb.Push(res); | ||
| 157 | rb.PushIpcInterface<Service::PSC::Time::SystemClock>(std::move(service)); | ||
| 158 | } | ||
| 159 | |||
| 160 | void StaticService::Handle_GetSharedMemoryNativeHandle(HLERequestContext& ctx) { | ||
| 161 | LOG_DEBUG(Service_Time, "called."); | ||
| 162 | |||
| 163 | Kernel::KSharedMemory* shared_memory{}; | ||
| 164 | auto res = GetSharedMemoryNativeHandle(&shared_memory); | ||
| 165 | |||
| 166 | IPC::ResponseBuilder rb{ctx, 2, 1}; | ||
| 167 | rb.Push(res); | ||
| 168 | rb.PushCopyObjects(shared_memory); | ||
| 169 | } | ||
| 170 | |||
| 171 | void StaticService::Handle_SetStandardSteadyClockInternalOffset(HLERequestContext& ctx) { | ||
| 172 | LOG_DEBUG(Service_Time, "called."); | ||
| 173 | |||
| 174 | IPC::RequestParser rp{ctx}; | ||
| 175 | auto offset_ns{rp.Pop<s64>()}; | ||
| 176 | |||
| 177 | auto res = SetStandardSteadyClockInternalOffset(offset_ns); | ||
| 178 | |||
| 179 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 180 | rb.Push(res); | ||
| 181 | } | ||
| 182 | |||
| 183 | void StaticService::Handle_GetStandardSteadyClockRtcValue(HLERequestContext& ctx) { | ||
| 184 | LOG_DEBUG(Service_Time, "called."); | ||
| 185 | |||
| 186 | s64 rtc_value{}; | ||
| 187 | auto res = GetStandardSteadyClockRtcValue(rtc_value); | ||
| 188 | |||
| 189 | IPC::ResponseBuilder rb{ctx, 4}; | ||
| 190 | rb.Push(res); | ||
| 191 | rb.Push(rtc_value); | ||
| 192 | } | ||
| 193 | |||
| 194 | void StaticService::Handle_IsStandardUserSystemClockAutomaticCorrectionEnabled( | ||
| 195 | HLERequestContext& ctx) { | ||
| 196 | LOG_DEBUG(Service_Time, "called."); | ||
| 197 | |||
| 198 | bool is_enabled{}; | ||
| 199 | auto res = IsStandardUserSystemClockAutomaticCorrectionEnabled(is_enabled); | ||
| 200 | |||
| 201 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 202 | rb.Push(res); | ||
| 203 | rb.Push<bool>(is_enabled); | ||
| 204 | } | ||
| 205 | |||
| 206 | void StaticService::Handle_SetStandardUserSystemClockAutomaticCorrectionEnabled( | ||
| 207 | HLERequestContext& ctx) { | ||
| 208 | LOG_DEBUG(Service_Time, "called."); | ||
| 209 | |||
| 210 | IPC::RequestParser rp{ctx}; | ||
| 211 | auto automatic_correction{rp.Pop<bool>()}; | ||
| 212 | |||
| 213 | auto res = SetStandardUserSystemClockAutomaticCorrectionEnabled(automatic_correction); | ||
| 214 | |||
| 215 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 216 | rb.Push(res); | ||
| 217 | } | ||
| 218 | |||
| 219 | void StaticService::Handle_GetStandardUserSystemClockInitialYear(HLERequestContext& ctx) { | ||
| 220 | LOG_DEBUG(Service_Time, "called."); | ||
| 221 | |||
| 222 | s32 initial_year{}; | ||
| 223 | auto res = GetStandardUserSystemClockInitialYear(initial_year); | ||
| 224 | |||
| 225 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 226 | rb.Push(res); | ||
| 227 | rb.Push(initial_year); | ||
| 228 | } | ||
| 229 | |||
| 230 | void StaticService::Handle_IsStandardNetworkSystemClockAccuracySufficient(HLERequestContext& ctx) { | ||
| 231 | LOG_DEBUG(Service_Time, "called."); | ||
| 232 | |||
| 233 | bool is_sufficient{}; | ||
| 234 | auto res = IsStandardNetworkSystemClockAccuracySufficient(is_sufficient); | ||
| 235 | |||
| 236 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 237 | rb.Push(res); | ||
| 238 | rb.Push<bool>(is_sufficient); | ||
| 239 | } | ||
| 240 | |||
| 241 | void StaticService::Handle_GetStandardUserSystemClockAutomaticCorrectionUpdatedTime( | ||
| 242 | HLERequestContext& ctx) { | ||
| 243 | LOG_DEBUG(Service_Time, "called."); | ||
| 244 | |||
| 245 | Service::PSC::Time::SteadyClockTimePoint time_point{}; | ||
| 246 | auto res = GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(time_point); | ||
| 247 | |||
| 248 | IPC::ResponseBuilder rb{ctx, | ||
| 249 | 2 + sizeof(Service::PSC::Time::SteadyClockTimePoint) / sizeof(u32)}; | ||
| 250 | rb.Push(res); | ||
| 251 | rb.PushRaw<Service::PSC::Time::SteadyClockTimePoint>(time_point); | ||
| 252 | } | ||
| 253 | |||
| 254 | void StaticService::Handle_CalculateMonotonicSystemClockBaseTimePoint(HLERequestContext& ctx) { | ||
| 255 | LOG_DEBUG(Service_Time, "called."); | ||
| 256 | |||
| 257 | IPC::RequestParser rp{ctx}; | ||
| 258 | auto context{rp.PopRaw<Service::PSC::Time::SystemClockContext>()}; | ||
| 259 | |||
| 260 | s64 time{}; | ||
| 261 | auto res = CalculateMonotonicSystemClockBaseTimePoint(time, context); | ||
| 262 | |||
| 263 | IPC::ResponseBuilder rb{ctx, 4}; | ||
| 264 | rb.Push(res); | ||
| 265 | rb.Push<s64>(time); | ||
| 266 | } | ||
| 267 | |||
| 268 | void StaticService::Handle_GetClockSnapshot(HLERequestContext& ctx) { | ||
| 269 | LOG_DEBUG(Service_Time, "called."); | ||
| 270 | |||
| 271 | IPC::RequestParser rp{ctx}; | ||
| 272 | auto type{rp.PopEnum<Service::PSC::Time::TimeType>()}; | ||
| 273 | |||
| 274 | Service::PSC::Time::ClockSnapshot snapshot{}; | ||
| 275 | auto res = GetClockSnapshot(snapshot, type); | ||
| 276 | |||
| 277 | ctx.WriteBuffer(snapshot); | ||
| 278 | |||
| 279 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 280 | rb.Push(res); | ||
| 281 | } | ||
| 282 | |||
| 283 | void StaticService::Handle_GetClockSnapshotFromSystemClockContext(HLERequestContext& ctx) { | ||
| 284 | LOG_DEBUG(Service_Time, "called."); | ||
| 285 | |||
| 286 | IPC::RequestParser rp{ctx}; | ||
| 287 | auto clock_type{rp.PopEnum<Service::PSC::Time::TimeType>()}; | ||
| 288 | [[maybe_unused]] auto alignment{rp.Pop<u32>()}; | ||
| 289 | auto user_context{rp.PopRaw<Service::PSC::Time::SystemClockContext>()}; | ||
| 290 | auto network_context{rp.PopRaw<Service::PSC::Time::SystemClockContext>()}; | ||
| 291 | |||
| 292 | Service::PSC::Time::ClockSnapshot snapshot{}; | ||
| 293 | auto res = | ||
| 294 | GetClockSnapshotFromSystemClockContext(snapshot, user_context, network_context, clock_type); | ||
| 295 | |||
| 296 | ctx.WriteBuffer(snapshot); | ||
| 297 | |||
| 298 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 299 | rb.Push(res); | ||
| 300 | } | ||
| 301 | |||
| 302 | void StaticService::Handle_CalculateStandardUserSystemClockDifferenceByUser( | ||
| 303 | HLERequestContext& ctx) { | ||
| 304 | LOG_DEBUG(Service_Time, "called."); | ||
| 305 | |||
| 306 | Service::PSC::Time::ClockSnapshot a{}; | ||
| 307 | Service::PSC::Time::ClockSnapshot b{}; | ||
| 308 | |||
| 309 | auto a_buffer{ctx.ReadBuffer(0)}; | ||
| 310 | auto b_buffer{ctx.ReadBuffer(1)}; | ||
| 311 | |||
| 312 | std::memcpy(&a, a_buffer.data(), sizeof(Service::PSC::Time::ClockSnapshot)); | ||
| 313 | std::memcpy(&b, b_buffer.data(), sizeof(Service::PSC::Time::ClockSnapshot)); | ||
| 314 | |||
| 315 | s64 difference{}; | ||
| 316 | auto res = CalculateStandardUserSystemClockDifferenceByUser(difference, a, b); | ||
| 317 | |||
| 318 | IPC::ResponseBuilder rb{ctx, 4}; | ||
| 319 | rb.Push(res); | ||
| 320 | rb.Push(difference); | ||
| 321 | } | ||
| 322 | |||
| 323 | void StaticService::Handle_CalculateSpanBetween(HLERequestContext& ctx) { | ||
| 324 | LOG_DEBUG(Service_Time, "called."); | ||
| 325 | |||
| 326 | Service::PSC::Time::ClockSnapshot a{}; | ||
| 327 | Service::PSC::Time::ClockSnapshot b{}; | ||
| 328 | |||
| 329 | auto a_buffer{ctx.ReadBuffer(0)}; | ||
| 330 | auto b_buffer{ctx.ReadBuffer(1)}; | ||
| 331 | |||
| 332 | std::memcpy(&a, a_buffer.data(), sizeof(Service::PSC::Time::ClockSnapshot)); | ||
| 333 | std::memcpy(&b, b_buffer.data(), sizeof(Service::PSC::Time::ClockSnapshot)); | ||
| 334 | |||
| 335 | s64 time{}; | ||
| 336 | auto res = CalculateSpanBetween(time, a, b); | ||
| 337 | |||
| 338 | IPC::ResponseBuilder rb{ctx, 4}; | ||
| 339 | rb.Push(res); | ||
| 340 | rb.Push(time); | ||
| 341 | } | ||
| 342 | |||
| 343 | // =============================== Implementations =========================== | ||
| 344 | |||
| 345 | Result StaticService::GetStandardUserSystemClock( | ||
| 346 | std::shared_ptr<Service::PSC::Time::SystemClock>& out_service) { | ||
| 347 | R_RETURN(m_wrapped_service->GetStandardUserSystemClock(out_service)); | ||
| 348 | } | ||
| 349 | |||
| 350 | Result StaticService::GetStandardNetworkSystemClock( | ||
| 351 | std::shared_ptr<Service::PSC::Time::SystemClock>& out_service) { | ||
| 352 | R_RETURN(m_wrapped_service->GetStandardNetworkSystemClock(out_service)); | ||
| 353 | } | ||
| 354 | |||
| 355 | Result StaticService::GetStandardSteadyClock( | ||
| 356 | std::shared_ptr<Service::PSC::Time::SteadyClock>& out_service) { | ||
| 357 | R_RETURN(m_wrapped_service->GetStandardSteadyClock(out_service)); | ||
| 358 | } | ||
| 359 | |||
| 360 | Result StaticService::GetTimeZoneService(std::shared_ptr<TimeZoneService>& out_service) { | ||
| 361 | out_service = std::make_shared<TimeZoneService>(m_system, m_file_timestamp_worker, | ||
| 362 | m_setup_info.can_write_timezone_device_location, | ||
| 363 | m_time_zone); | ||
| 364 | R_SUCCEED(); | ||
| 365 | } | ||
| 366 | |||
| 367 | Result StaticService::GetStandardLocalSystemClock( | ||
| 368 | std::shared_ptr<Service::PSC::Time::SystemClock>& out_service) { | ||
| 369 | R_RETURN(m_wrapped_service->GetStandardLocalSystemClock(out_service)); | ||
| 370 | } | ||
| 371 | |||
| 372 | Result StaticService::GetEphemeralNetworkSystemClock( | ||
| 373 | std::shared_ptr<Service::PSC::Time::SystemClock>& out_service) { | ||
| 374 | R_RETURN(m_wrapped_service->GetEphemeralNetworkSystemClock(out_service)); | ||
| 375 | } | ||
| 376 | |||
| 377 | Result StaticService::GetSharedMemoryNativeHandle(Kernel::KSharedMemory** out_shared_memory) { | ||
| 378 | R_RETURN(m_wrapped_service->GetSharedMemoryNativeHandle(out_shared_memory)); | ||
| 379 | } | ||
| 380 | |||
| 381 | Result StaticService::SetStandardSteadyClockInternalOffset(s64 offset_ns) { | ||
| 382 | R_UNLESS(m_setup_info.can_write_steady_clock, Service::PSC::Time::ResultPermissionDenied); | ||
| 383 | |||
| 384 | R_RETURN(m_set_sys->SetExternalSteadyClockInternalOffset( | ||
| 385 | offset_ns / | ||
| 386 | std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::seconds(1)).count())); | ||
| 387 | } | ||
| 388 | |||
| 389 | Result StaticService::GetStandardSteadyClockRtcValue(s64& out_rtc_value) { | ||
| 390 | R_RETURN(m_standard_steady_clock_resource.GetRtcTimeInSeconds(out_rtc_value)); | ||
| 391 | } | ||
| 392 | |||
| 393 | Result StaticService::IsStandardUserSystemClockAutomaticCorrectionEnabled( | ||
| 394 | bool& out_automatic_correction) { | ||
| 395 | R_RETURN(m_wrapped_service->IsStandardUserSystemClockAutomaticCorrectionEnabled( | ||
| 396 | out_automatic_correction)); | ||
| 397 | } | ||
| 398 | |||
| 399 | Result StaticService::SetStandardUserSystemClockAutomaticCorrectionEnabled( | ||
| 400 | bool automatic_correction) { | ||
| 401 | R_RETURN(m_wrapped_service->SetStandardUserSystemClockAutomaticCorrectionEnabled( | ||
| 402 | automatic_correction)); | ||
| 403 | } | ||
| 404 | |||
| 405 | Result StaticService::GetStandardUserSystemClockInitialYear(s32& out_year) { | ||
| 406 | out_year = GetSettingsItemValue<s32>(m_set_sys, "time", "standard_user_clock_initial_year"); | ||
| 407 | R_SUCCEED(); | ||
| 408 | } | ||
| 409 | |||
| 410 | Result StaticService::IsStandardNetworkSystemClockAccuracySufficient(bool& out_is_sufficient) { | ||
| 411 | R_RETURN(m_wrapped_service->IsStandardNetworkSystemClockAccuracySufficient(out_is_sufficient)); | ||
| 412 | } | ||
| 413 | |||
| 414 | Result StaticService::GetStandardUserSystemClockAutomaticCorrectionUpdatedTime( | ||
| 415 | Service::PSC::Time::SteadyClockTimePoint& out_time_point) { | ||
| 416 | R_RETURN(m_wrapped_service->GetStandardUserSystemClockAutomaticCorrectionUpdatedTime( | ||
| 417 | out_time_point)); | ||
| 418 | } | ||
| 419 | |||
| 420 | Result StaticService::CalculateMonotonicSystemClockBaseTimePoint( | ||
| 421 | s64& out_time, Service::PSC::Time::SystemClockContext& context) { | ||
| 422 | R_RETURN(m_wrapped_service->CalculateMonotonicSystemClockBaseTimePoint(out_time, context)); | ||
| 423 | } | ||
| 424 | |||
| 425 | Result StaticService::GetClockSnapshot(Service::PSC::Time::ClockSnapshot& out_snapshot, | ||
| 426 | Service::PSC::Time::TimeType type) { | ||
| 427 | R_RETURN(m_wrapped_service->GetClockSnapshot(out_snapshot, type)); | ||
| 428 | } | ||
| 429 | |||
| 430 | Result StaticService::GetClockSnapshotFromSystemClockContext( | ||
| 431 | Service::PSC::Time::ClockSnapshot& out_snapshot, | ||
| 432 | Service::PSC::Time::SystemClockContext& user_context, | ||
| 433 | Service::PSC::Time::SystemClockContext& network_context, Service::PSC::Time::TimeType type) { | ||
| 434 | R_RETURN(m_wrapped_service->GetClockSnapshotFromSystemClockContext(out_snapshot, user_context, | ||
| 435 | network_context, type)); | ||
| 436 | } | ||
| 437 | |||
| 438 | Result StaticService::CalculateStandardUserSystemClockDifferenceByUser( | ||
| 439 | s64& out_time, Service::PSC::Time::ClockSnapshot& a, Service::PSC::Time::ClockSnapshot& b) { | ||
| 440 | R_RETURN(m_wrapped_service->CalculateStandardUserSystemClockDifferenceByUser(out_time, a, b)); | ||
| 441 | } | ||
| 442 | |||
| 443 | Result StaticService::CalculateSpanBetween(s64& out_time, Service::PSC::Time::ClockSnapshot& a, | ||
| 444 | Service::PSC::Time::ClockSnapshot& b) { | ||
| 445 | R_RETURN(m_wrapped_service->CalculateSpanBetween(out_time, a, b)); | ||
| 446 | } | ||
| 447 | |||
| 448 | } // namespace Service::Glue::Time | ||
diff --git a/src/core/hle/service/glue/time/static.h b/src/core/hle/service/glue/time/static.h new file mode 100644 index 000000000..75fe4e2cd --- /dev/null +++ b/src/core/hle/service/glue/time/static.h | |||
| @@ -0,0 +1,110 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "common/common_types.h" | ||
| 7 | #include "core/hle/service/glue/time/manager.h" | ||
| 8 | #include "core/hle/service/glue/time/time_zone.h" | ||
| 9 | #include "core/hle/service/psc/time/common.h" | ||
| 10 | |||
| 11 | namespace Core { | ||
| 12 | class System; | ||
| 13 | } | ||
| 14 | |||
| 15 | namespace Service::Set { | ||
| 16 | class ISystemSettingsServer; | ||
| 17 | } | ||
| 18 | |||
| 19 | namespace Service::PSC::Time { | ||
| 20 | class StaticService; | ||
| 21 | class SystemClock; | ||
| 22 | class SteadyClock; | ||
| 23 | class TimeZoneService; | ||
| 24 | class ServiceManager; | ||
| 25 | } // namespace Service::PSC::Time | ||
| 26 | |||
| 27 | namespace Service::Glue::Time { | ||
| 28 | class FileTimestampWorker; | ||
| 29 | class StandardSteadyClockResource; | ||
| 30 | |||
| 31 | class StaticService final : public ServiceFramework<StaticService> { | ||
| 32 | public: | ||
| 33 | explicit StaticService(Core::System& system, | ||
| 34 | Service::PSC::Time::StaticServiceSetupInfo setup_info, | ||
| 35 | std::shared_ptr<TimeManager> time, const char* name); | ||
| 36 | |||
| 37 | ~StaticService() override = default; | ||
| 38 | |||
| 39 | Result GetStandardUserSystemClock( | ||
| 40 | std::shared_ptr<Service::PSC::Time::SystemClock>& out_service); | ||
| 41 | Result GetStandardNetworkSystemClock( | ||
| 42 | std::shared_ptr<Service::PSC::Time::SystemClock>& out_service); | ||
| 43 | Result GetStandardSteadyClock(std::shared_ptr<Service::PSC::Time::SteadyClock>& out_service); | ||
| 44 | Result GetTimeZoneService(std::shared_ptr<TimeZoneService>& out_service); | ||
| 45 | Result GetStandardLocalSystemClock( | ||
| 46 | std::shared_ptr<Service::PSC::Time::SystemClock>& out_service); | ||
| 47 | Result GetEphemeralNetworkSystemClock( | ||
| 48 | std::shared_ptr<Service::PSC::Time::SystemClock>& out_service); | ||
| 49 | Result GetSharedMemoryNativeHandle(Kernel::KSharedMemory** out_shared_memory); | ||
| 50 | Result SetStandardSteadyClockInternalOffset(s64 offset); | ||
| 51 | Result GetStandardSteadyClockRtcValue(s64& out_rtc_value); | ||
| 52 | Result IsStandardUserSystemClockAutomaticCorrectionEnabled(bool& out_automatic_correction); | ||
| 53 | Result SetStandardUserSystemClockAutomaticCorrectionEnabled(bool automatic_correction); | ||
| 54 | Result GetStandardUserSystemClockInitialYear(s32& out_year); | ||
| 55 | Result IsStandardNetworkSystemClockAccuracySufficient(bool& out_is_sufficient); | ||
| 56 | Result GetStandardUserSystemClockAutomaticCorrectionUpdatedTime( | ||
| 57 | Service::PSC::Time::SteadyClockTimePoint& out_time_point); | ||
| 58 | Result CalculateMonotonicSystemClockBaseTimePoint( | ||
| 59 | s64& out_time, Service::PSC::Time::SystemClockContext& context); | ||
| 60 | Result GetClockSnapshot(Service::PSC::Time::ClockSnapshot& out_snapshot, | ||
| 61 | Service::PSC::Time::TimeType type); | ||
| 62 | Result GetClockSnapshotFromSystemClockContext( | ||
| 63 | Service::PSC::Time::ClockSnapshot& out_snapshot, | ||
| 64 | Service::PSC::Time::SystemClockContext& user_context, | ||
| 65 | Service::PSC::Time::SystemClockContext& network_context, Service::PSC::Time::TimeType type); | ||
| 66 | Result CalculateStandardUserSystemClockDifferenceByUser(s64& out_time, | ||
| 67 | Service::PSC::Time::ClockSnapshot& a, | ||
| 68 | Service::PSC::Time::ClockSnapshot& b); | ||
| 69 | Result CalculateSpanBetween(s64& out_time, Service::PSC::Time::ClockSnapshot& a, | ||
| 70 | Service::PSC::Time::ClockSnapshot& b); | ||
| 71 | |||
| 72 | private: | ||
| 73 | Result GetClockSnapshotImpl(Service::PSC::Time::ClockSnapshot& out_snapshot, | ||
| 74 | Service::PSC::Time::SystemClockContext& user_context, | ||
| 75 | Service::PSC::Time::SystemClockContext& network_context, | ||
| 76 | Service::PSC::Time::TimeType type); | ||
| 77 | |||
| 78 | void Handle_GetStandardUserSystemClock(HLERequestContext& ctx); | ||
| 79 | void Handle_GetStandardNetworkSystemClock(HLERequestContext& ctx); | ||
| 80 | void Handle_GetStandardSteadyClock(HLERequestContext& ctx); | ||
| 81 | void Handle_GetTimeZoneService(HLERequestContext& ctx); | ||
| 82 | void Handle_GetStandardLocalSystemClock(HLERequestContext& ctx); | ||
| 83 | void Handle_GetEphemeralNetworkSystemClock(HLERequestContext& ctx); | ||
| 84 | void Handle_GetSharedMemoryNativeHandle(HLERequestContext& ctx); | ||
| 85 | void Handle_SetStandardSteadyClockInternalOffset(HLERequestContext& ctx); | ||
| 86 | void Handle_GetStandardSteadyClockRtcValue(HLERequestContext& ctx); | ||
| 87 | void Handle_IsStandardUserSystemClockAutomaticCorrectionEnabled(HLERequestContext& ctx); | ||
| 88 | void Handle_SetStandardUserSystemClockAutomaticCorrectionEnabled(HLERequestContext& ctx); | ||
| 89 | void Handle_GetStandardUserSystemClockInitialYear(HLERequestContext& ctx); | ||
| 90 | void Handle_IsStandardNetworkSystemClockAccuracySufficient(HLERequestContext& ctx); | ||
| 91 | void Handle_GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(HLERequestContext& ctx); | ||
| 92 | void Handle_CalculateMonotonicSystemClockBaseTimePoint(HLERequestContext& ctx); | ||
| 93 | void Handle_GetClockSnapshot(HLERequestContext& ctx); | ||
| 94 | void Handle_GetClockSnapshotFromSystemClockContext(HLERequestContext& ctx); | ||
| 95 | void Handle_CalculateStandardUserSystemClockDifferenceByUser(HLERequestContext& ctx); | ||
| 96 | void Handle_CalculateSpanBetween(HLERequestContext& ctx); | ||
| 97 | |||
| 98 | Core::System& m_system; | ||
| 99 | |||
| 100 | std::shared_ptr<Service::Set::ISystemSettingsServer> m_set_sys; | ||
| 101 | std::shared_ptr<Service::PSC::Time::ServiceManager> m_time_m; | ||
| 102 | std::shared_ptr<Service::PSC::Time::StaticService> m_wrapped_service; | ||
| 103 | |||
| 104 | Service::PSC::Time::StaticServiceSetupInfo m_setup_info; | ||
| 105 | std::shared_ptr<Service::PSC::Time::StaticService> m_time_sm; | ||
| 106 | std::shared_ptr<Service::PSC::Time::TimeZoneService> m_time_zone; | ||
| 107 | FileTimestampWorker& m_file_timestamp_worker; | ||
| 108 | StandardSteadyClockResource& m_standard_steady_clock_resource; | ||
| 109 | }; | ||
| 110 | } // namespace Service::Glue::Time | ||
diff --git a/src/core/hle/service/glue/time/time_zone.cpp b/src/core/hle/service/glue/time/time_zone.cpp new file mode 100644 index 000000000..503c327dd --- /dev/null +++ b/src/core/hle/service/glue/time/time_zone.cpp | |||
| @@ -0,0 +1,377 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include <chrono> | ||
| 5 | |||
| 6 | #include "core/core.h" | ||
| 7 | #include "core/hle/kernel/svc.h" | ||
| 8 | #include "core/hle/service/glue/time/file_timestamp_worker.h" | ||
| 9 | #include "core/hle/service/glue/time/time_zone.h" | ||
| 10 | #include "core/hle/service/glue/time/time_zone_binary.h" | ||
| 11 | #include "core/hle/service/psc/time/time_zone_service.h" | ||
| 12 | #include "core/hle/service/set/system_settings_server.h" | ||
| 13 | #include "core/hle/service/sm/sm.h" | ||
| 14 | |||
| 15 | namespace Service::Glue::Time { | ||
| 16 | namespace { | ||
| 17 | static std::mutex g_list_mutex; | ||
| 18 | static Common::IntrusiveListBaseTraits<Service::PSC::Time::OperationEvent>::ListType g_list_nodes{}; | ||
| 19 | } // namespace | ||
| 20 | |||
| 21 | TimeZoneService::TimeZoneService( | ||
| 22 | Core::System& system_, FileTimestampWorker& file_timestamp_worker, | ||
| 23 | bool can_write_timezone_device_location, | ||
| 24 | std::shared_ptr<Service::PSC::Time::TimeZoneService> time_zone_service) | ||
| 25 | : ServiceFramework{system_, "ITimeZoneService"}, m_system{system}, | ||
| 26 | m_can_write_timezone_device_location{can_write_timezone_device_location}, | ||
| 27 | m_file_timestamp_worker{file_timestamp_worker}, | ||
| 28 | m_wrapped_service{std::move(time_zone_service)}, m_operation_event{m_system} { | ||
| 29 | // clang-format off | ||
| 30 | static const FunctionInfo functions[] = { | ||
| 31 | {0, &TimeZoneService::Handle_GetDeviceLocationName, "GetDeviceLocationName"}, | ||
| 32 | {1, &TimeZoneService::Handle_SetDeviceLocationName, "SetDeviceLocationName"}, | ||
| 33 | {2, &TimeZoneService::Handle_GetTotalLocationNameCount, "GetTotalLocationNameCount"}, | ||
| 34 | {3, &TimeZoneService::Handle_LoadLocationNameList, "LoadLocationNameList"}, | ||
| 35 | {4, &TimeZoneService::Handle_LoadTimeZoneRule, "LoadTimeZoneRule"}, | ||
| 36 | {5, &TimeZoneService::Handle_GetTimeZoneRuleVersion, "GetTimeZoneRuleVersion"}, | ||
| 37 | {6, &TimeZoneService::Handle_GetDeviceLocationNameAndUpdatedTime, "GetDeviceLocationNameAndUpdatedTime"}, | ||
| 38 | {7, &TimeZoneService::Handle_SetDeviceLocationNameWithTimeZoneRule, "SetDeviceLocationNameWithTimeZoneRule"}, | ||
| 39 | {8, &TimeZoneService::Handle_ParseTimeZoneBinary, "ParseTimeZoneBinary"}, | ||
| 40 | {20, &TimeZoneService::Handle_GetDeviceLocationNameOperationEventReadableHandle, "GetDeviceLocationNameOperationEventReadableHandle"}, | ||
| 41 | {100, &TimeZoneService::Handle_ToCalendarTime, "ToCalendarTime"}, | ||
| 42 | {101, &TimeZoneService::Handle_ToCalendarTimeWithMyRule, "ToCalendarTimeWithMyRule"}, | ||
| 43 | {201, &TimeZoneService::Handle_ToPosixTime, "ToPosixTime"}, | ||
| 44 | {202, &TimeZoneService::Handle_ToPosixTimeWithMyRule, "ToPosixTimeWithMyRule"}, | ||
| 45 | }; | ||
| 46 | // clang-format on | ||
| 47 | RegisterHandlers(functions); | ||
| 48 | |||
| 49 | g_list_nodes.clear(); | ||
| 50 | m_set_sys = | ||
| 51 | m_system.ServiceManager().GetService<Service::Set::ISystemSettingsServer>("set:sys", true); | ||
| 52 | } | ||
| 53 | |||
| 54 | TimeZoneService::~TimeZoneService() = default; | ||
| 55 | |||
| 56 | void TimeZoneService::Handle_GetDeviceLocationName(HLERequestContext& ctx) { | ||
| 57 | LOG_DEBUG(Service_Time, "called."); | ||
| 58 | |||
| 59 | Service::PSC::Time::LocationName name{}; | ||
| 60 | auto res = GetDeviceLocationName(name); | ||
| 61 | |||
| 62 | IPC::ResponseBuilder rb{ctx, 2 + sizeof(Service::PSC::Time::LocationName) / sizeof(u32)}; | ||
| 63 | rb.Push(res); | ||
| 64 | rb.PushRaw<Service::PSC::Time::LocationName>(name); | ||
| 65 | } | ||
| 66 | |||
| 67 | void TimeZoneService::Handle_SetDeviceLocationName(HLERequestContext& ctx) { | ||
| 68 | LOG_DEBUG(Service_Time, "called."); | ||
| 69 | |||
| 70 | IPC::RequestParser rp{ctx}; | ||
| 71 | auto name{rp.PopRaw<Service::PSC::Time::LocationName>()}; | ||
| 72 | |||
| 73 | auto res = SetDeviceLocation(name); | ||
| 74 | |||
| 75 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 76 | rb.Push(res); | ||
| 77 | } | ||
| 78 | |||
| 79 | void TimeZoneService::Handle_GetTotalLocationNameCount(HLERequestContext& ctx) { | ||
| 80 | LOG_DEBUG(Service_Time, "called."); | ||
| 81 | |||
| 82 | u32 count{}; | ||
| 83 | auto res = GetTotalLocationNameCount(count); | ||
| 84 | |||
| 85 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 86 | rb.Push(res); | ||
| 87 | rb.Push(count); | ||
| 88 | } | ||
| 89 | |||
| 90 | void TimeZoneService::Handle_LoadLocationNameList(HLERequestContext& ctx) { | ||
| 91 | LOG_DEBUG(Service_Time, "called."); | ||
| 92 | |||
| 93 | IPC::RequestParser rp{ctx}; | ||
| 94 | auto index{rp.Pop<u32>()}; | ||
| 95 | |||
| 96 | auto max_names{ctx.GetWriteBufferSize() / sizeof(Service::PSC::Time::LocationName)}; | ||
| 97 | |||
| 98 | std::vector<Service::PSC::Time::LocationName> names{}; | ||
| 99 | u32 count{}; | ||
| 100 | auto res = LoadLocationNameList(count, names, max_names, index); | ||
| 101 | |||
| 102 | ctx.WriteBuffer(names); | ||
| 103 | |||
| 104 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 105 | rb.Push(res); | ||
| 106 | rb.Push(count); | ||
| 107 | } | ||
| 108 | |||
| 109 | void TimeZoneService::Handle_LoadTimeZoneRule(HLERequestContext& ctx) { | ||
| 110 | LOG_DEBUG(Service_Time, "called."); | ||
| 111 | |||
| 112 | IPC::RequestParser rp{ctx}; | ||
| 113 | auto name{rp.PopRaw<Service::PSC::Time::LocationName>()}; | ||
| 114 | |||
| 115 | Tz::Rule rule{}; | ||
| 116 | auto res = LoadTimeZoneRule(rule, name); | ||
| 117 | |||
| 118 | ctx.WriteBuffer(rule); | ||
| 119 | |||
| 120 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 121 | rb.Push(res); | ||
| 122 | } | ||
| 123 | |||
| 124 | void TimeZoneService::Handle_GetTimeZoneRuleVersion(HLERequestContext& ctx) { | ||
| 125 | LOG_DEBUG(Service_Time, "called."); | ||
| 126 | |||
| 127 | Service::PSC::Time::RuleVersion rule_version{}; | ||
| 128 | auto res = GetTimeZoneRuleVersion(rule_version); | ||
| 129 | |||
| 130 | IPC::ResponseBuilder rb{ctx, 2 + sizeof(Service::PSC::Time::RuleVersion) / sizeof(u32)}; | ||
| 131 | rb.Push(res); | ||
| 132 | rb.PushRaw<Service::PSC::Time::RuleVersion>(rule_version); | ||
| 133 | } | ||
| 134 | |||
| 135 | void TimeZoneService::Handle_GetDeviceLocationNameAndUpdatedTime(HLERequestContext& ctx) { | ||
| 136 | LOG_DEBUG(Service_Time, "called."); | ||
| 137 | |||
| 138 | Service::PSC::Time::LocationName name{}; | ||
| 139 | Service::PSC::Time::SteadyClockTimePoint time_point{}; | ||
| 140 | auto res = GetDeviceLocationNameAndUpdatedTime(time_point, name); | ||
| 141 | |||
| 142 | IPC::ResponseBuilder rb{ctx, | ||
| 143 | 2 + (sizeof(Service::PSC::Time::LocationName) / sizeof(u32)) + | ||
| 144 | (sizeof(Service::PSC::Time::SteadyClockTimePoint) / sizeof(u32))}; | ||
| 145 | rb.Push(res); | ||
| 146 | rb.PushRaw<Service::PSC::Time::LocationName>(name); | ||
| 147 | rb.PushRaw<Service::PSC::Time::SteadyClockTimePoint>(time_point); | ||
| 148 | } | ||
| 149 | |||
| 150 | void TimeZoneService::Handle_SetDeviceLocationNameWithTimeZoneRule(HLERequestContext& ctx) { | ||
| 151 | LOG_DEBUG(Service_Time, "called."); | ||
| 152 | |||
| 153 | auto res = SetDeviceLocationNameWithTimeZoneRule(); | ||
| 154 | |||
| 155 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 156 | rb.Push(res); | ||
| 157 | } | ||
| 158 | |||
| 159 | void TimeZoneService::Handle_ParseTimeZoneBinary(HLERequestContext& ctx) { | ||
| 160 | LOG_DEBUG(Service_Time, "called."); | ||
| 161 | |||
| 162 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 163 | rb.Push(Service::PSC::Time::ResultNotImplemented); | ||
| 164 | } | ||
| 165 | |||
| 166 | void TimeZoneService::Handle_GetDeviceLocationNameOperationEventReadableHandle( | ||
| 167 | HLERequestContext& ctx) { | ||
| 168 | LOG_DEBUG(Service_Time, "called."); | ||
| 169 | |||
| 170 | Kernel::KEvent* event{}; | ||
| 171 | auto res = GetDeviceLocationNameOperationEventReadableHandle(&event); | ||
| 172 | |||
| 173 | IPC::ResponseBuilder rb{ctx, 2, 1}; | ||
| 174 | rb.Push(res); | ||
| 175 | rb.PushCopyObjects(event->GetReadableEvent()); | ||
| 176 | } | ||
| 177 | |||
| 178 | void TimeZoneService::Handle_ToCalendarTime(HLERequestContext& ctx) { | ||
| 179 | LOG_DEBUG(Service_Time, "called."); | ||
| 180 | |||
| 181 | IPC::RequestParser rp{ctx}; | ||
| 182 | auto time{rp.Pop<s64>()}; | ||
| 183 | |||
| 184 | auto rule_buffer{ctx.ReadBuffer()}; | ||
| 185 | Tz::Rule rule{}; | ||
| 186 | std::memcpy(&rule, rule_buffer.data(), sizeof(Tz::Rule)); | ||
| 187 | |||
| 188 | Service::PSC::Time::CalendarTime calendar_time{}; | ||
| 189 | Service::PSC::Time::CalendarAdditionalInfo additional_info{}; | ||
| 190 | auto res = ToCalendarTime(calendar_time, additional_info, time, rule); | ||
| 191 | |||
| 192 | IPC::ResponseBuilder rb{ctx, | ||
| 193 | 2 + (sizeof(Service::PSC::Time::CalendarTime) / sizeof(u32)) + | ||
| 194 | (sizeof(Service::PSC::Time::CalendarAdditionalInfo) / sizeof(u32))}; | ||
| 195 | rb.Push(res); | ||
| 196 | rb.PushRaw<Service::PSC::Time::CalendarTime>(calendar_time); | ||
| 197 | rb.PushRaw<Service::PSC::Time::CalendarAdditionalInfo>(additional_info); | ||
| 198 | } | ||
| 199 | |||
| 200 | void TimeZoneService::Handle_ToCalendarTimeWithMyRule(HLERequestContext& ctx) { | ||
| 201 | IPC::RequestParser rp{ctx}; | ||
| 202 | auto time{rp.Pop<s64>()}; | ||
| 203 | |||
| 204 | LOG_DEBUG(Service_Time, "called. time={}", time); | ||
| 205 | |||
| 206 | Service::PSC::Time::CalendarTime calendar_time{}; | ||
| 207 | Service::PSC::Time::CalendarAdditionalInfo additional_info{}; | ||
| 208 | auto res = ToCalendarTimeWithMyRule(calendar_time, additional_info, time); | ||
| 209 | |||
| 210 | IPC::ResponseBuilder rb{ctx, | ||
| 211 | 2 + (sizeof(Service::PSC::Time::CalendarTime) / sizeof(u32)) + | ||
| 212 | (sizeof(Service::PSC::Time::CalendarAdditionalInfo) / sizeof(u32))}; | ||
| 213 | rb.Push(res); | ||
| 214 | rb.PushRaw<Service::PSC::Time::CalendarTime>(calendar_time); | ||
| 215 | rb.PushRaw<Service::PSC::Time::CalendarAdditionalInfo>(additional_info); | ||
| 216 | } | ||
| 217 | |||
| 218 | void TimeZoneService::Handle_ToPosixTime(HLERequestContext& ctx) { | ||
| 219 | IPC::RequestParser rp{ctx}; | ||
| 220 | auto calendar{rp.PopRaw<Service::PSC::Time::CalendarTime>()}; | ||
| 221 | |||
| 222 | LOG_DEBUG(Service_Time, "called. calendar year {} month {} day {} hour {} minute {} second {}", | ||
| 223 | calendar.year, calendar.month, calendar.day, calendar.hour, calendar.minute, | ||
| 224 | calendar.second); | ||
| 225 | |||
| 226 | auto binary{ctx.ReadBuffer()}; | ||
| 227 | |||
| 228 | Tz::Rule rule{}; | ||
| 229 | std::memcpy(&rule, binary.data(), sizeof(Tz::Rule)); | ||
| 230 | |||
| 231 | u32 count{}; | ||
| 232 | std::array<s64, 2> times{}; | ||
| 233 | u32 times_count{static_cast<u32>(ctx.GetWriteBufferSize() / sizeof(s64))}; | ||
| 234 | |||
| 235 | auto res = ToPosixTime(count, times, times_count, calendar, rule); | ||
| 236 | |||
| 237 | ctx.WriteBuffer(times); | ||
| 238 | |||
| 239 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 240 | rb.Push(res); | ||
| 241 | rb.Push(count); | ||
| 242 | } | ||
| 243 | |||
| 244 | void TimeZoneService::Handle_ToPosixTimeWithMyRule(HLERequestContext& ctx) { | ||
| 245 | LOG_DEBUG(Service_Time, "called."); | ||
| 246 | |||
| 247 | IPC::RequestParser rp{ctx}; | ||
| 248 | auto calendar{rp.PopRaw<Service::PSC::Time::CalendarTime>()}; | ||
| 249 | |||
| 250 | u32 count{}; | ||
| 251 | std::array<s64, 2> times{}; | ||
| 252 | u32 times_count{static_cast<u32>(ctx.GetWriteBufferSize() / sizeof(s64))}; | ||
| 253 | |||
| 254 | auto res = ToPosixTimeWithMyRule(count, times, times_count, calendar); | ||
| 255 | |||
| 256 | ctx.WriteBuffer(times); | ||
| 257 | |||
| 258 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 259 | rb.Push(res); | ||
| 260 | rb.Push(count); | ||
| 261 | } | ||
| 262 | |||
| 263 | // =============================== Implementations =========================== | ||
| 264 | |||
| 265 | Result TimeZoneService::GetDeviceLocationName(Service::PSC::Time::LocationName& out_location_name) { | ||
| 266 | R_RETURN(m_wrapped_service->GetDeviceLocationName(out_location_name)); | ||
| 267 | } | ||
| 268 | |||
| 269 | Result TimeZoneService::SetDeviceLocation(Service::PSC::Time::LocationName& location_name) { | ||
| 270 | R_UNLESS(m_can_write_timezone_device_location, Service::PSC::Time::ResultPermissionDenied); | ||
| 271 | R_UNLESS(IsTimeZoneBinaryValid(location_name), Service::PSC::Time::ResultTimeZoneNotFound); | ||
| 272 | |||
| 273 | std::scoped_lock l{m_mutex}; | ||
| 274 | |||
| 275 | std::span<const u8> binary{}; | ||
| 276 | size_t binary_size{}; | ||
| 277 | R_TRY(GetTimeZoneRule(binary, binary_size, location_name)) | ||
| 278 | |||
| 279 | R_TRY(m_wrapped_service->SetDeviceLocationNameWithTimeZoneRule(location_name, binary)); | ||
| 280 | |||
| 281 | m_file_timestamp_worker.SetFilesystemPosixTime(); | ||
| 282 | |||
| 283 | Service::PSC::Time::SteadyClockTimePoint time_point{}; | ||
| 284 | Service::PSC::Time::LocationName name{}; | ||
| 285 | R_TRY(m_wrapped_service->GetDeviceLocationNameAndUpdatedTime(time_point, name)); | ||
| 286 | |||
| 287 | m_set_sys->SetDeviceTimeZoneLocationName(name); | ||
| 288 | m_set_sys->SetDeviceTimeZoneLocationUpdatedTime(time_point); | ||
| 289 | |||
| 290 | std::scoped_lock m{g_list_mutex}; | ||
| 291 | for (auto& operation_event : g_list_nodes) { | ||
| 292 | operation_event.m_event->Signal(); | ||
| 293 | } | ||
| 294 | R_SUCCEED(); | ||
| 295 | } | ||
| 296 | |||
| 297 | Result TimeZoneService::GetTotalLocationNameCount(u32& out_count) { | ||
| 298 | R_RETURN(m_wrapped_service->GetTotalLocationNameCount(out_count)); | ||
| 299 | } | ||
| 300 | |||
| 301 | Result TimeZoneService::LoadLocationNameList( | ||
| 302 | u32& out_count, std::vector<Service::PSC::Time::LocationName>& out_names, size_t max_names, | ||
| 303 | u32 index) { | ||
| 304 | std::scoped_lock l{m_mutex}; | ||
| 305 | R_RETURN(GetTimeZoneLocationList(out_count, out_names, max_names, index)); | ||
| 306 | } | ||
| 307 | |||
| 308 | Result TimeZoneService::LoadTimeZoneRule(Tz::Rule& out_rule, | ||
| 309 | Service::PSC::Time::LocationName& name) { | ||
| 310 | std::scoped_lock l{m_mutex}; | ||
| 311 | std::span<const u8> binary{}; | ||
| 312 | size_t binary_size{}; | ||
| 313 | R_TRY(GetTimeZoneRule(binary, binary_size, name)) | ||
| 314 | R_RETURN(m_wrapped_service->ParseTimeZoneBinary(out_rule, binary)); | ||
| 315 | } | ||
| 316 | |||
| 317 | Result TimeZoneService::GetTimeZoneRuleVersion(Service::PSC::Time::RuleVersion& out_rule_version) { | ||
| 318 | R_RETURN(m_wrapped_service->GetTimeZoneRuleVersion(out_rule_version)); | ||
| 319 | } | ||
| 320 | |||
| 321 | Result TimeZoneService::GetDeviceLocationNameAndUpdatedTime( | ||
| 322 | Service::PSC::Time::SteadyClockTimePoint& out_time_point, | ||
| 323 | Service::PSC::Time::LocationName& location_name) { | ||
| 324 | R_RETURN(m_wrapped_service->GetDeviceLocationNameAndUpdatedTime(out_time_point, location_name)); | ||
| 325 | } | ||
| 326 | |||
| 327 | Result TimeZoneService::SetDeviceLocationNameWithTimeZoneRule() { | ||
| 328 | R_UNLESS(m_can_write_timezone_device_location, Service::PSC::Time::ResultPermissionDenied); | ||
| 329 | R_RETURN(Service::PSC::Time::ResultNotImplemented); | ||
| 330 | } | ||
| 331 | |||
| 332 | Result TimeZoneService::GetDeviceLocationNameOperationEventReadableHandle( | ||
| 333 | Kernel::KEvent** out_event) { | ||
| 334 | if (!operation_event_initialized) { | ||
| 335 | operation_event_initialized = false; | ||
| 336 | |||
| 337 | m_operation_event.m_ctx.CloseEvent(m_operation_event.m_event); | ||
| 338 | m_operation_event.m_event = | ||
| 339 | m_operation_event.m_ctx.CreateEvent("Psc:TimeZoneService:OperationEvent"); | ||
| 340 | operation_event_initialized = true; | ||
| 341 | std::scoped_lock l{m_mutex}; | ||
| 342 | g_list_nodes.push_back(m_operation_event); | ||
| 343 | } | ||
| 344 | |||
| 345 | *out_event = m_operation_event.m_event; | ||
| 346 | R_SUCCEED(); | ||
| 347 | } | ||
| 348 | |||
| 349 | Result TimeZoneService::ToCalendarTime( | ||
| 350 | Service::PSC::Time::CalendarTime& out_calendar_time, | ||
| 351 | Service::PSC::Time::CalendarAdditionalInfo& out_additional_info, s64 time, Tz::Rule& rule) { | ||
| 352 | R_RETURN(m_wrapped_service->ToCalendarTime(out_calendar_time, out_additional_info, time, rule)); | ||
| 353 | } | ||
| 354 | |||
| 355 | Result TimeZoneService::ToCalendarTimeWithMyRule( | ||
| 356 | Service::PSC::Time::CalendarTime& out_calendar_time, | ||
| 357 | Service::PSC::Time::CalendarAdditionalInfo& out_additional_info, s64 time) { | ||
| 358 | R_RETURN( | ||
| 359 | m_wrapped_service->ToCalendarTimeWithMyRule(out_calendar_time, out_additional_info, time)); | ||
| 360 | } | ||
| 361 | |||
| 362 | Result TimeZoneService::ToPosixTime(u32& out_count, std::span<s64, 2> out_times, | ||
| 363 | u32 out_times_count, | ||
| 364 | Service::PSC::Time::CalendarTime& calendar_time, | ||
| 365 | Tz::Rule& rule) { | ||
| 366 | R_RETURN( | ||
| 367 | m_wrapped_service->ToPosixTime(out_count, out_times, out_times_count, calendar_time, rule)); | ||
| 368 | } | ||
| 369 | |||
| 370 | Result TimeZoneService::ToPosixTimeWithMyRule(u32& out_count, std::span<s64, 2> out_times, | ||
| 371 | u32 out_times_count, | ||
| 372 | Service::PSC::Time::CalendarTime& calendar_time) { | ||
| 373 | R_RETURN(m_wrapped_service->ToPosixTimeWithMyRule(out_count, out_times, out_times_count, | ||
| 374 | calendar_time)); | ||
| 375 | } | ||
| 376 | |||
| 377 | } // namespace Service::Glue::Time | ||
diff --git a/src/core/hle/service/glue/time/time_zone.h b/src/core/hle/service/glue/time/time_zone.h new file mode 100644 index 000000000..3c8ae4bf8 --- /dev/null +++ b/src/core/hle/service/glue/time/time_zone.h | |||
| @@ -0,0 +1,95 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <memory> | ||
| 7 | #include <mutex> | ||
| 8 | #include <span> | ||
| 9 | #include <vector> | ||
| 10 | |||
| 11 | #include "core/hle/service/ipc_helpers.h" | ||
| 12 | #include "core/hle/service/psc/time/common.h" | ||
| 13 | #include "core/hle/service/server_manager.h" | ||
| 14 | #include "core/hle/service/service.h" | ||
| 15 | |||
| 16 | namespace Core { | ||
| 17 | class System; | ||
| 18 | } | ||
| 19 | |||
| 20 | namespace Tz { | ||
| 21 | struct Rule; | ||
| 22 | } | ||
| 23 | |||
| 24 | namespace Service::Set { | ||
| 25 | class ISystemSettingsServer; | ||
| 26 | } | ||
| 27 | |||
| 28 | namespace Service::PSC::Time { | ||
| 29 | class TimeZoneService; | ||
| 30 | } | ||
| 31 | |||
| 32 | namespace Service::Glue::Time { | ||
| 33 | class FileTimestampWorker; | ||
| 34 | |||
| 35 | class TimeZoneService final : public ServiceFramework<TimeZoneService> { | ||
| 36 | public: | ||
| 37 | explicit TimeZoneService( | ||
| 38 | Core::System& system, FileTimestampWorker& file_timestamp_worker, | ||
| 39 | bool can_write_timezone_device_location, | ||
| 40 | std::shared_ptr<Service::PSC::Time::TimeZoneService> time_zone_service); | ||
| 41 | |||
| 42 | ~TimeZoneService() override; | ||
| 43 | |||
| 44 | Result GetDeviceLocationName(Service::PSC::Time::LocationName& out_location_name); | ||
| 45 | Result SetDeviceLocation(Service::PSC::Time::LocationName& location_name); | ||
| 46 | Result GetTotalLocationNameCount(u32& out_count); | ||
| 47 | Result LoadLocationNameList(u32& out_count, | ||
| 48 | std::vector<Service::PSC::Time::LocationName>& out_names, | ||
| 49 | size_t max_names, u32 index); | ||
| 50 | Result LoadTimeZoneRule(Tz::Rule& out_rule, Service::PSC::Time::LocationName& name); | ||
| 51 | Result GetTimeZoneRuleVersion(Service::PSC::Time::RuleVersion& out_rule_version); | ||
| 52 | Result GetDeviceLocationNameAndUpdatedTime( | ||
| 53 | Service::PSC::Time::SteadyClockTimePoint& out_time_point, | ||
| 54 | Service::PSC::Time::LocationName& location_name); | ||
| 55 | Result SetDeviceLocationNameWithTimeZoneRule(); | ||
| 56 | Result GetDeviceLocationNameOperationEventReadableHandle(Kernel::KEvent** out_event); | ||
| 57 | Result ToCalendarTime(Service::PSC::Time::CalendarTime& out_calendar_time, | ||
| 58 | Service::PSC::Time::CalendarAdditionalInfo& out_additional_info, s64 time, | ||
| 59 | Tz::Rule& rule); | ||
| 60 | Result ToCalendarTimeWithMyRule(Service::PSC::Time::CalendarTime& out_calendar_time, | ||
| 61 | Service::PSC::Time::CalendarAdditionalInfo& out_additional_info, | ||
| 62 | s64 time); | ||
| 63 | Result ToPosixTime(u32& out_count, std::span<s64, 2> out_times, u32 out_times_count, | ||
| 64 | Service::PSC::Time::CalendarTime& calendar_time, Tz::Rule& rule); | ||
| 65 | Result ToPosixTimeWithMyRule(u32& out_count, std::span<s64, 2> out_times, u32 out_times_count, | ||
| 66 | Service::PSC::Time::CalendarTime& calendar_time); | ||
| 67 | |||
| 68 | private: | ||
| 69 | void Handle_GetDeviceLocationName(HLERequestContext& ctx); | ||
| 70 | void Handle_SetDeviceLocationName(HLERequestContext& ctx); | ||
| 71 | void Handle_GetTotalLocationNameCount(HLERequestContext& ctx); | ||
| 72 | void Handle_LoadLocationNameList(HLERequestContext& ctx); | ||
| 73 | void Handle_LoadTimeZoneRule(HLERequestContext& ctx); | ||
| 74 | void Handle_GetTimeZoneRuleVersion(HLERequestContext& ctx); | ||
| 75 | void Handle_GetDeviceLocationNameAndUpdatedTime(HLERequestContext& ctx); | ||
| 76 | void Handle_SetDeviceLocationNameWithTimeZoneRule(HLERequestContext& ctx); | ||
| 77 | void Handle_ParseTimeZoneBinary(HLERequestContext& ctx); | ||
| 78 | void Handle_GetDeviceLocationNameOperationEventReadableHandle(HLERequestContext& ctx); | ||
| 79 | void Handle_ToCalendarTime(HLERequestContext& ctx); | ||
| 80 | void Handle_ToCalendarTimeWithMyRule(HLERequestContext& ctx); | ||
| 81 | void Handle_ToPosixTime(HLERequestContext& ctx); | ||
| 82 | void Handle_ToPosixTimeWithMyRule(HLERequestContext& ctx); | ||
| 83 | |||
| 84 | Core::System& m_system; | ||
| 85 | std::shared_ptr<Service::Set::ISystemSettingsServer> m_set_sys; | ||
| 86 | |||
| 87 | bool m_can_write_timezone_device_location; | ||
| 88 | FileTimestampWorker& m_file_timestamp_worker; | ||
| 89 | std::shared_ptr<Service::PSC::Time::TimeZoneService> m_wrapped_service; | ||
| 90 | std::mutex m_mutex; | ||
| 91 | bool operation_event_initialized{}; | ||
| 92 | Service::PSC::Time::OperationEvent m_operation_event; | ||
| 93 | }; | ||
| 94 | |||
| 95 | } // namespace Service::Glue::Time | ||
diff --git a/src/core/hle/service/glue/time/time_zone_binary.cpp b/src/core/hle/service/glue/time/time_zone_binary.cpp new file mode 100644 index 000000000..67969aa3f --- /dev/null +++ b/src/core/hle/service/glue/time/time_zone_binary.cpp | |||
| @@ -0,0 +1,221 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "core/core.h" | ||
| 5 | #include "core/file_sys/content_archive.h" | ||
| 6 | #include "core/file_sys/nca_metadata.h" | ||
| 7 | #include "core/file_sys/registered_cache.h" | ||
| 8 | #include "core/file_sys/romfs.h" | ||
| 9 | #include "core/file_sys/system_archive/system_archive.h" | ||
| 10 | #include "core/file_sys/vfs.h" | ||
| 11 | #include "core/hle/service/filesystem/filesystem.h" | ||
| 12 | #include "core/hle/service/glue/time/time_zone_binary.h" | ||
| 13 | |||
| 14 | namespace Service::Glue::Time { | ||
| 15 | namespace { | ||
| 16 | constexpr u64 TimeZoneBinaryId = 0x10000000000080E; | ||
| 17 | |||
| 18 | static FileSys::VirtualDir g_time_zone_binary_romfs{}; | ||
| 19 | static Result g_time_zone_binary_mount_result{ResultUnknown}; | ||
| 20 | static std::vector<u8> g_time_zone_scratch_space(0x2800, 0); | ||
| 21 | |||
| 22 | Result TimeZoneReadBinary(size_t& out_read_size, std::span<u8> out_buffer, size_t out_buffer_size, | ||
| 23 | std::string_view path) { | ||
| 24 | R_UNLESS(g_time_zone_binary_mount_result == ResultSuccess, g_time_zone_binary_mount_result); | ||
| 25 | |||
| 26 | auto vfs_file{g_time_zone_binary_romfs->GetFileRelative(path)}; | ||
| 27 | R_UNLESS(vfs_file, ResultUnknown); | ||
| 28 | |||
| 29 | auto file_size{vfs_file->GetSize()}; | ||
| 30 | R_UNLESS(file_size > 0, ResultUnknown); | ||
| 31 | |||
| 32 | R_UNLESS(file_size <= out_buffer_size, Service::PSC::Time::ResultFailed); | ||
| 33 | |||
| 34 | out_read_size = vfs_file->Read(out_buffer.data(), file_size); | ||
| 35 | R_UNLESS(out_read_size > 0, ResultUnknown); | ||
| 36 | |||
| 37 | R_SUCCEED(); | ||
| 38 | } | ||
| 39 | } // namespace | ||
| 40 | |||
| 41 | void ResetTimeZoneBinary() { | ||
| 42 | g_time_zone_binary_romfs = {}; | ||
| 43 | g_time_zone_binary_mount_result = ResultUnknown; | ||
| 44 | g_time_zone_scratch_space.clear(); | ||
| 45 | g_time_zone_scratch_space.resize(0x2800, 0); | ||
| 46 | } | ||
| 47 | |||
| 48 | Result MountTimeZoneBinary(Core::System& system) { | ||
| 49 | ResetTimeZoneBinary(); | ||
| 50 | |||
| 51 | auto& fsc{system.GetFileSystemController()}; | ||
| 52 | std::unique_ptr<FileSys::NCA> nca{}; | ||
| 53 | |||
| 54 | auto* bis_system = fsc.GetSystemNANDContents(); | ||
| 55 | |||
| 56 | R_UNLESS(bis_system, ResultUnknown); | ||
| 57 | |||
| 58 | nca = bis_system->GetEntry(TimeZoneBinaryId, FileSys::ContentRecordType::Data); | ||
| 59 | |||
| 60 | if (nca) { | ||
| 61 | g_time_zone_binary_romfs = FileSys::ExtractRomFS(nca->GetRomFS()); | ||
| 62 | } | ||
| 63 | |||
| 64 | if (g_time_zone_binary_romfs) { | ||
| 65 | // Validate that the romfs is readable, using invalid firmware keys can cause this to get | ||
| 66 | // set but the files to be garbage. In that case, we want to hit the next path and | ||
| 67 | // synthesise them instead. | ||
| 68 | Service::PSC::Time::LocationName name{"Etc/GMT"}; | ||
| 69 | if (!IsTimeZoneBinaryValid(name)) { | ||
| 70 | ResetTimeZoneBinary(); | ||
| 71 | } | ||
| 72 | } | ||
| 73 | |||
| 74 | if (!g_time_zone_binary_romfs) { | ||
| 75 | g_time_zone_binary_romfs = FileSys::ExtractRomFS( | ||
| 76 | FileSys::SystemArchive::SynthesizeSystemArchive(TimeZoneBinaryId)); | ||
| 77 | } | ||
| 78 | |||
| 79 | R_UNLESS(g_time_zone_binary_romfs, ResultUnknown); | ||
| 80 | |||
| 81 | g_time_zone_binary_mount_result = ResultSuccess; | ||
| 82 | R_SUCCEED(); | ||
| 83 | } | ||
| 84 | |||
| 85 | void GetTimeZoneBinaryListPath(std::string& out_path) { | ||
| 86 | if (g_time_zone_binary_mount_result != ResultSuccess) { | ||
| 87 | return; | ||
| 88 | } | ||
| 89 | // out_path = fmt::format("{}:/binaryList.txt", "TimeZoneBinary"); | ||
| 90 | out_path = "/binaryList.txt"; | ||
| 91 | } | ||
| 92 | |||
| 93 | void GetTimeZoneBinaryVersionPath(std::string& out_path) { | ||
| 94 | if (g_time_zone_binary_mount_result != ResultSuccess) { | ||
| 95 | return; | ||
| 96 | } | ||
| 97 | // out_path = fmt::format("{}:/version.txt", "TimeZoneBinary"); | ||
| 98 | out_path = "/version.txt"; | ||
| 99 | } | ||
| 100 | |||
| 101 | void GetTimeZoneZonePath(std::string& out_path, Service::PSC::Time::LocationName& name) { | ||
| 102 | if (g_time_zone_binary_mount_result != ResultSuccess) { | ||
| 103 | return; | ||
| 104 | } | ||
| 105 | // out_path = fmt::format("{}:/zoneinfo/{}", "TimeZoneBinary", name); | ||
| 106 | out_path = fmt::format("/zoneinfo/{}", name.name.data()); | ||
| 107 | } | ||
| 108 | |||
| 109 | bool IsTimeZoneBinaryValid(Service::PSC::Time::LocationName& name) { | ||
| 110 | std::string path{}; | ||
| 111 | GetTimeZoneZonePath(path, name); | ||
| 112 | |||
| 113 | auto vfs_file{g_time_zone_binary_romfs->GetFileRelative(path)}; | ||
| 114 | if (!vfs_file) { | ||
| 115 | LOG_INFO(Service_Time, "Could not find timezone file {}", path); | ||
| 116 | return false; | ||
| 117 | } | ||
| 118 | return vfs_file->GetSize() != 0; | ||
| 119 | } | ||
| 120 | |||
| 121 | u32 GetTimeZoneCount() { | ||
| 122 | std::string path{}; | ||
| 123 | GetTimeZoneBinaryListPath(path); | ||
| 124 | |||
| 125 | size_t bytes_read{}; | ||
| 126 | if (TimeZoneReadBinary(bytes_read, g_time_zone_scratch_space, 0x2800, path) != ResultSuccess) { | ||
| 127 | return 0; | ||
| 128 | } | ||
| 129 | if (bytes_read == 0) { | ||
| 130 | return 0; | ||
| 131 | } | ||
| 132 | |||
| 133 | auto chars = std::span(reinterpret_cast<char*>(g_time_zone_scratch_space.data()), bytes_read); | ||
| 134 | u32 count{}; | ||
| 135 | for (auto chr : chars) { | ||
| 136 | if (chr == '\n') { | ||
| 137 | count++; | ||
| 138 | } | ||
| 139 | } | ||
| 140 | return count; | ||
| 141 | } | ||
| 142 | |||
| 143 | Result GetTimeZoneVersion(Service::PSC::Time::RuleVersion& out_rule_version) { | ||
| 144 | std::string path{}; | ||
| 145 | GetTimeZoneBinaryVersionPath(path); | ||
| 146 | |||
| 147 | auto rule_version_buffer{std::span(reinterpret_cast<u8*>(&out_rule_version), | ||
| 148 | sizeof(Service::PSC::Time::RuleVersion))}; | ||
| 149 | size_t bytes_read{}; | ||
| 150 | R_TRY(TimeZoneReadBinary(bytes_read, rule_version_buffer, rule_version_buffer.size_bytes(), | ||
| 151 | path)); | ||
| 152 | |||
| 153 | rule_version_buffer[bytes_read] = 0; | ||
| 154 | R_SUCCEED(); | ||
| 155 | } | ||
| 156 | |||
| 157 | Result GetTimeZoneRule(std::span<const u8>& out_rule, size_t& out_rule_size, | ||
| 158 | Service::PSC::Time::LocationName& name) { | ||
| 159 | std::string path{}; | ||
| 160 | GetTimeZoneZonePath(path, name); | ||
| 161 | |||
| 162 | size_t bytes_read{}; | ||
| 163 | R_TRY(TimeZoneReadBinary(bytes_read, g_time_zone_scratch_space, | ||
| 164 | g_time_zone_scratch_space.size(), path)); | ||
| 165 | |||
| 166 | out_rule = std::span(g_time_zone_scratch_space.data(), bytes_read); | ||
| 167 | out_rule_size = bytes_read; | ||
| 168 | R_SUCCEED(); | ||
| 169 | } | ||
| 170 | |||
| 171 | Result GetTimeZoneLocationList(u32& out_count, | ||
| 172 | std::vector<Service::PSC::Time::LocationName>& out_names, | ||
| 173 | size_t max_names, u32 index) { | ||
| 174 | std::string path{}; | ||
| 175 | GetTimeZoneBinaryListPath(path); | ||
| 176 | |||
| 177 | size_t bytes_read{}; | ||
| 178 | R_TRY(TimeZoneReadBinary(bytes_read, g_time_zone_scratch_space, | ||
| 179 | g_time_zone_scratch_space.size(), path)); | ||
| 180 | |||
| 181 | out_count = 0; | ||
| 182 | R_SUCCEED_IF(bytes_read == 0); | ||
| 183 | |||
| 184 | Service::PSC::Time::LocationName current_name{}; | ||
| 185 | size_t current_name_len{}; | ||
| 186 | std::span<const u8> chars{g_time_zone_scratch_space}; | ||
| 187 | u32 name_count{}; | ||
| 188 | |||
| 189 | for (auto chr : chars) { | ||
| 190 | if (chr == '\r') { | ||
| 191 | continue; | ||
| 192 | } | ||
| 193 | |||
| 194 | if (chr == '\n') { | ||
| 195 | if (name_count >= index) { | ||
| 196 | out_names.push_back(current_name); | ||
| 197 | out_count++; | ||
| 198 | if (out_count >= max_names) { | ||
| 199 | break; | ||
| 200 | } | ||
| 201 | } | ||
| 202 | name_count++; | ||
| 203 | current_name_len = 0; | ||
| 204 | current_name = {}; | ||
| 205 | continue; | ||
| 206 | } | ||
| 207 | |||
| 208 | if (chr == '\0') { | ||
| 209 | break; | ||
| 210 | } | ||
| 211 | |||
| 212 | R_UNLESS(current_name_len <= current_name.name.size() - 2, | ||
| 213 | Service::PSC::Time::ResultFailed); | ||
| 214 | |||
| 215 | current_name.name[current_name_len++] = chr; | ||
| 216 | } | ||
| 217 | |||
| 218 | R_SUCCEED(); | ||
| 219 | } | ||
| 220 | |||
| 221 | } // namespace Service::Glue::Time | ||
diff --git a/src/core/hle/service/glue/time/time_zone_binary.h b/src/core/hle/service/glue/time/time_zone_binary.h new file mode 100644 index 000000000..2cad6b458 --- /dev/null +++ b/src/core/hle/service/glue/time/time_zone_binary.h | |||
| @@ -0,0 +1,32 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <span> | ||
| 7 | #include <string> | ||
| 8 | #include <string_view> | ||
| 9 | |||
| 10 | #include "core/hle/service/psc/time/common.h" | ||
| 11 | |||
| 12 | namespace Core { | ||
| 13 | class System; | ||
| 14 | } | ||
| 15 | |||
| 16 | namespace Service::Glue::Time { | ||
| 17 | |||
| 18 | void ResetTimeZoneBinary(); | ||
| 19 | Result MountTimeZoneBinary(Core::System& system); | ||
| 20 | void GetTimeZoneBinaryListPath(std::string& out_path); | ||
| 21 | void GetTimeZoneBinaryVersionPath(std::string& out_path); | ||
| 22 | void GetTimeZoneZonePath(std::string& out_path, Service::PSC::Time::LocationName& name); | ||
| 23 | bool IsTimeZoneBinaryValid(Service::PSC::Time::LocationName& name); | ||
| 24 | u32 GetTimeZoneCount(); | ||
| 25 | Result GetTimeZoneVersion(Service::PSC::Time::RuleVersion& out_rule_version); | ||
| 26 | Result GetTimeZoneRule(std::span<const u8>& out_rule, size_t& out_rule_size, | ||
| 27 | Service::PSC::Time::LocationName& name); | ||
| 28 | Result GetTimeZoneLocationList(u32& out_count, | ||
| 29 | std::vector<Service::PSC::Time::LocationName>& out_names, | ||
| 30 | size_t max_names, u32 index); | ||
| 31 | |||
| 32 | } // namespace Service::Glue::Time | ||
diff --git a/src/core/hle/service/glue/time/worker.cpp b/src/core/hle/service/glue/time/worker.cpp new file mode 100644 index 000000000..ea0e49b90 --- /dev/null +++ b/src/core/hle/service/glue/time/worker.cpp | |||
| @@ -0,0 +1,338 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "common/scope_exit.h" | ||
| 5 | #include "core/core.h" | ||
| 6 | #include "core/core_timing.h" | ||
| 7 | #include "core/hle/service/glue/time/file_timestamp_worker.h" | ||
| 8 | #include "core/hle/service/glue/time/standard_steady_clock_resource.h" | ||
| 9 | #include "core/hle/service/glue/time/worker.h" | ||
| 10 | #include "core/hle/service/psc/time/common.h" | ||
| 11 | #include "core/hle/service/psc/time/service_manager.h" | ||
| 12 | #include "core/hle/service/psc/time/static.h" | ||
| 13 | #include "core/hle/service/psc/time/system_clock.h" | ||
| 14 | #include "core/hle/service/set/system_settings_server.h" | ||
| 15 | #include "core/hle/service/sm/sm.h" | ||
| 16 | |||
| 17 | namespace Service::Glue::Time { | ||
| 18 | namespace { | ||
| 19 | |||
| 20 | bool g_ig_report_network_clock_context_set{}; | ||
| 21 | Service::PSC::Time::SystemClockContext g_report_network_clock_context{}; | ||
| 22 | bool g_ig_report_ephemeral_clock_context_set{}; | ||
| 23 | Service::PSC::Time::SystemClockContext g_report_ephemeral_clock_context{}; | ||
| 24 | |||
| 25 | template <typename T> | ||
| 26 | T GetSettingsItemValue(std::shared_ptr<Service::Set::ISystemSettingsServer>& set_sys, | ||
| 27 | const char* category, const char* name) { | ||
| 28 | std::vector<u8> interval_buf; | ||
| 29 | auto res = set_sys->GetSettingsItemValue(interval_buf, category, name); | ||
| 30 | ASSERT(res == ResultSuccess); | ||
| 31 | |||
| 32 | T v{}; | ||
| 33 | std::memcpy(&v, interval_buf.data(), sizeof(T)); | ||
| 34 | return v; | ||
| 35 | } | ||
| 36 | |||
| 37 | } // namespace | ||
| 38 | |||
| 39 | TimeWorker::TimeWorker(Core::System& system, StandardSteadyClockResource& steady_clock_resource, | ||
| 40 | FileTimestampWorker& file_timestamp_worker) | ||
| 41 | : m_system{system}, m_ctx{m_system, "Glue:58"}, m_event{m_ctx.CreateEvent("Glue:58:Event")}, | ||
| 42 | m_steady_clock_resource{steady_clock_resource}, | ||
| 43 | m_file_timestamp_worker{file_timestamp_worker}, m_timer_steady_clock{m_ctx.CreateEvent( | ||
| 44 | "Glue:58:SteadyClockTimerEvent")}, | ||
| 45 | m_timer_file_system{m_ctx.CreateEvent("Glue:58:FileTimeTimerEvent")}, | ||
| 46 | m_alarm_worker{m_system, m_steady_clock_resource}, m_pm_state_change_handler{m_alarm_worker} { | ||
| 47 | g_ig_report_network_clock_context_set = false; | ||
| 48 | g_report_network_clock_context = {}; | ||
| 49 | g_ig_report_ephemeral_clock_context_set = false; | ||
| 50 | g_report_ephemeral_clock_context = {}; | ||
| 51 | |||
| 52 | m_timer_steady_clock_timing_event = Core::Timing::CreateEvent( | ||
| 53 | "Time::SteadyClockEvent", | ||
| 54 | [this](s64 time, | ||
| 55 | std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> { | ||
| 56 | m_timer_steady_clock->Signal(); | ||
| 57 | return std::nullopt; | ||
| 58 | }); | ||
| 59 | |||
| 60 | m_timer_file_system_timing_event = Core::Timing::CreateEvent( | ||
| 61 | "Time::SteadyClockEvent", | ||
| 62 | [this](s64 time, | ||
| 63 | std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> { | ||
| 64 | m_timer_file_system->Signal(); | ||
| 65 | return std::nullopt; | ||
| 66 | }); | ||
| 67 | } | ||
| 68 | |||
| 69 | TimeWorker::~TimeWorker() { | ||
| 70 | m_local_clock_event->Signal(); | ||
| 71 | m_network_clock_event->Signal(); | ||
| 72 | m_ephemeral_clock_event->Signal(); | ||
| 73 | std::this_thread::sleep_for(std::chrono::milliseconds(16)); | ||
| 74 | |||
| 75 | m_thread.request_stop(); | ||
| 76 | m_event->Signal(); | ||
| 77 | m_thread.join(); | ||
| 78 | |||
| 79 | m_ctx.CloseEvent(m_event); | ||
| 80 | m_system.CoreTiming().UnscheduleEvent(m_timer_steady_clock_timing_event); | ||
| 81 | m_ctx.CloseEvent(m_timer_steady_clock); | ||
| 82 | m_system.CoreTiming().UnscheduleEvent(m_timer_file_system_timing_event); | ||
| 83 | m_ctx.CloseEvent(m_timer_file_system); | ||
| 84 | } | ||
| 85 | |||
| 86 | void TimeWorker::Initialize(std::shared_ptr<Service::PSC::Time::StaticService> time_sm, | ||
| 87 | std::shared_ptr<Service::Set::ISystemSettingsServer> set_sys) { | ||
| 88 | m_set_sys = std::move(set_sys); | ||
| 89 | m_time_m = | ||
| 90 | m_system.ServiceManager().GetService<Service::PSC::Time::ServiceManager>("time:m", true); | ||
| 91 | m_time_sm = std::move(time_sm); | ||
| 92 | |||
| 93 | m_alarm_worker.Initialize(m_time_m); | ||
| 94 | |||
| 95 | auto steady_clock_interval_m = GetSettingsItemValue<s32>( | ||
| 96 | m_set_sys, "time", "standard_steady_clock_rtc_update_interval_minutes"); | ||
| 97 | |||
| 98 | auto one_minute_ns{ | ||
| 99 | std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::minutes(1)).count()}; | ||
| 100 | s64 steady_clock_interval_ns{steady_clock_interval_m * one_minute_ns}; | ||
| 101 | |||
| 102 | m_system.CoreTiming().ScheduleLoopingEvent(std::chrono::nanoseconds(0), | ||
| 103 | std::chrono::nanoseconds(steady_clock_interval_ns), | ||
| 104 | m_timer_steady_clock_timing_event); | ||
| 105 | |||
| 106 | auto fs_notify_time_s = | ||
| 107 | GetSettingsItemValue<s32>(m_set_sys, "time", "notify_time_to_fs_interval_seconds"); | ||
| 108 | auto one_second_ns{ | ||
| 109 | std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::seconds(1)).count()}; | ||
| 110 | s64 fs_notify_time_ns{fs_notify_time_s * one_second_ns}; | ||
| 111 | |||
| 112 | m_system.CoreTiming().ScheduleLoopingEvent(std::chrono::nanoseconds(0), | ||
| 113 | std::chrono::nanoseconds(fs_notify_time_ns), | ||
| 114 | m_timer_file_system_timing_event); | ||
| 115 | |||
| 116 | auto res = m_time_sm->GetStandardLocalSystemClock(m_local_clock); | ||
| 117 | ASSERT(res == ResultSuccess); | ||
| 118 | res = m_time_m->GetStandardLocalClockOperationEvent(&m_local_clock_event); | ||
| 119 | ASSERT(res == ResultSuccess); | ||
| 120 | |||
| 121 | res = m_time_sm->GetStandardNetworkSystemClock(m_network_clock); | ||
| 122 | ASSERT(res == ResultSuccess); | ||
| 123 | res = m_time_m->GetStandardNetworkClockOperationEventForServiceManager(&m_network_clock_event); | ||
| 124 | ASSERT(res == ResultSuccess); | ||
| 125 | |||
| 126 | res = m_time_sm->GetEphemeralNetworkSystemClock(m_ephemeral_clock); | ||
| 127 | ASSERT(res == ResultSuccess); | ||
| 128 | res = | ||
| 129 | m_time_m->GetEphemeralNetworkClockOperationEventForServiceManager(&m_ephemeral_clock_event); | ||
| 130 | ASSERT(res == ResultSuccess); | ||
| 131 | |||
| 132 | res = m_time_m->GetStandardUserSystemClockAutomaticCorrectionUpdatedEvent( | ||
| 133 | &m_standard_user_auto_correct_clock_event); | ||
| 134 | ASSERT(res == ResultSuccess); | ||
| 135 | } | ||
| 136 | |||
| 137 | void TimeWorker::StartThread() { | ||
| 138 | m_thread = std::jthread(std::bind_front(&TimeWorker::ThreadFunc, this)); | ||
| 139 | } | ||
| 140 | |||
| 141 | void TimeWorker::ThreadFunc(std::stop_token stop_token) { | ||
| 142 | Common::SetCurrentThreadName("TimeWorker"); | ||
| 143 | Common::SetCurrentThreadPriority(Common::ThreadPriority::Low); | ||
| 144 | |||
| 145 | enum class EventType { | ||
| 146 | Exit = 0, | ||
| 147 | IpmModuleService_GetEvent = 1, | ||
| 148 | PowerStateChange = 2, | ||
| 149 | SignalAlarms = 3, | ||
| 150 | UpdateLocalSystemClock = 4, | ||
| 151 | UpdateNetworkSystemClock = 5, | ||
| 152 | UpdateEphemeralSystemClock = 6, | ||
| 153 | UpdateSteadyClock = 7, | ||
| 154 | UpdateFileTimestamp = 8, | ||
| 155 | AutoCorrect = 9, | ||
| 156 | Max = 10, | ||
| 157 | }; | ||
| 158 | |||
| 159 | s32 num_objs{}; | ||
| 160 | std::array<Kernel::KSynchronizationObject*, static_cast<u32>(EventType::Max)> wait_objs{}; | ||
| 161 | std::array<EventType, static_cast<u32>(EventType::Max)> wait_indices{}; | ||
| 162 | |||
| 163 | const auto AddWaiter{ | ||
| 164 | [&](Kernel::KSynchronizationObject* synchronization_object, EventType type) { | ||
| 165 | // Open a new reference to the object. | ||
| 166 | synchronization_object->Open(); | ||
| 167 | |||
| 168 | // Insert into the list. | ||
| 169 | wait_indices[num_objs] = type; | ||
| 170 | wait_objs[num_objs++] = synchronization_object; | ||
| 171 | }}; | ||
| 172 | |||
| 173 | while (!stop_token.stop_requested()) { | ||
| 174 | SCOPE_EXIT({ | ||
| 175 | for (s32 i = 0; i < num_objs; i++) { | ||
| 176 | wait_objs[i]->Close(); | ||
| 177 | } | ||
| 178 | }); | ||
| 179 | |||
| 180 | num_objs = {}; | ||
| 181 | wait_objs = {}; | ||
| 182 | if (m_pm_state_change_handler.m_priority != 0) { | ||
| 183 | AddWaiter(&m_event->GetReadableEvent(), EventType::Exit); | ||
| 184 | // TODO | ||
| 185 | // AddWaiter(gIPmModuleService::GetEvent(), 1); | ||
| 186 | AddWaiter(&m_alarm_worker.GetEvent().GetReadableEvent(), EventType::PowerStateChange); | ||
| 187 | } else { | ||
| 188 | AddWaiter(&m_event->GetReadableEvent(), EventType::Exit); | ||
| 189 | // TODO | ||
| 190 | // AddWaiter(gIPmModuleService::GetEvent(), 1); | ||
| 191 | AddWaiter(&m_alarm_worker.GetEvent().GetReadableEvent(), EventType::PowerStateChange); | ||
| 192 | AddWaiter(&m_alarm_worker.GetTimerEvent().GetReadableEvent(), EventType::SignalAlarms); | ||
| 193 | AddWaiter(&m_local_clock_event->GetReadableEvent(), EventType::UpdateLocalSystemClock); | ||
| 194 | AddWaiter(&m_network_clock_event->GetReadableEvent(), | ||
| 195 | EventType::UpdateNetworkSystemClock); | ||
| 196 | AddWaiter(&m_ephemeral_clock_event->GetReadableEvent(), | ||
| 197 | EventType::UpdateEphemeralSystemClock); | ||
| 198 | AddWaiter(&m_timer_steady_clock->GetReadableEvent(), EventType::UpdateSteadyClock); | ||
| 199 | AddWaiter(&m_timer_file_system->GetReadableEvent(), EventType::UpdateFileTimestamp); | ||
| 200 | AddWaiter(&m_standard_user_auto_correct_clock_event->GetReadableEvent(), | ||
| 201 | EventType::AutoCorrect); | ||
| 202 | } | ||
| 203 | |||
| 204 | s32 out_index{-1}; | ||
| 205 | Kernel::KSynchronizationObject::Wait(m_system.Kernel(), &out_index, wait_objs.data(), | ||
| 206 | num_objs, -1); | ||
| 207 | ASSERT(out_index >= 0 && out_index < num_objs); | ||
| 208 | |||
| 209 | if (stop_token.stop_requested()) { | ||
| 210 | return; | ||
| 211 | } | ||
| 212 | |||
| 213 | switch (wait_indices[out_index]) { | ||
| 214 | case EventType::Exit: | ||
| 215 | return; | ||
| 216 | |||
| 217 | case EventType::IpmModuleService_GetEvent: | ||
| 218 | // TODO | ||
| 219 | // IPmModuleService::GetEvent() | ||
| 220 | // clear the event | ||
| 221 | // Handle power state change event | ||
| 222 | break; | ||
| 223 | |||
| 224 | case EventType::PowerStateChange: | ||
| 225 | m_alarm_worker.GetEvent().Clear(); | ||
| 226 | if (m_pm_state_change_handler.m_priority <= 1) { | ||
| 227 | m_alarm_worker.OnPowerStateChanged(); | ||
| 228 | } | ||
| 229 | break; | ||
| 230 | |||
| 231 | case EventType::SignalAlarms: | ||
| 232 | m_alarm_worker.GetTimerEvent().Clear(); | ||
| 233 | m_time_m->CheckAndSignalAlarms(); | ||
| 234 | break; | ||
| 235 | |||
| 236 | case EventType::UpdateLocalSystemClock: { | ||
| 237 | m_local_clock_event->Clear(); | ||
| 238 | |||
| 239 | Service::PSC::Time::SystemClockContext context{}; | ||
| 240 | auto res = m_local_clock->GetSystemClockContext(context); | ||
| 241 | ASSERT(res == ResultSuccess); | ||
| 242 | |||
| 243 | m_set_sys->SetUserSystemClockContext(context); | ||
| 244 | |||
| 245 | m_file_timestamp_worker.SetFilesystemPosixTime(); | ||
| 246 | } break; | ||
| 247 | |||
| 248 | case EventType::UpdateNetworkSystemClock: { | ||
| 249 | m_network_clock_event->Clear(); | ||
| 250 | Service::PSC::Time::SystemClockContext context{}; | ||
| 251 | auto res = m_network_clock->GetSystemClockContext(context); | ||
| 252 | ASSERT(res == ResultSuccess); | ||
| 253 | m_set_sys->SetNetworkSystemClockContext(context); | ||
| 254 | |||
| 255 | s64 time{}; | ||
| 256 | if (m_network_clock->GetCurrentTime(time) != ResultSuccess) { | ||
| 257 | break; | ||
| 258 | } | ||
| 259 | |||
| 260 | [[maybe_unused]] auto offset_before{ | ||
| 261 | g_ig_report_network_clock_context_set ? g_report_network_clock_context.offset : 0}; | ||
| 262 | // TODO system report "standard_netclock_operation" | ||
| 263 | // "clock_time" = time | ||
| 264 | // "context_offset_before" = offset_before | ||
| 265 | // "context_offset_after" = context.offset | ||
| 266 | g_report_network_clock_context = context; | ||
| 267 | if (!g_ig_report_network_clock_context_set) { | ||
| 268 | g_ig_report_network_clock_context_set = true; | ||
| 269 | } | ||
| 270 | |||
| 271 | m_file_timestamp_worker.SetFilesystemPosixTime(); | ||
| 272 | } break; | ||
| 273 | |||
| 274 | case EventType::UpdateEphemeralSystemClock: { | ||
| 275 | m_ephemeral_clock_event->Clear(); | ||
| 276 | |||
| 277 | Service::PSC::Time::SystemClockContext context{}; | ||
| 278 | auto res = m_ephemeral_clock->GetSystemClockContext(context); | ||
| 279 | if (res != ResultSuccess) { | ||
| 280 | break; | ||
| 281 | } | ||
| 282 | |||
| 283 | s64 time{}; | ||
| 284 | res = m_ephemeral_clock->GetCurrentTime(time); | ||
| 285 | if (res != ResultSuccess) { | ||
| 286 | break; | ||
| 287 | } | ||
| 288 | |||
| 289 | [[maybe_unused]] auto offset_before{g_ig_report_ephemeral_clock_context_set | ||
| 290 | ? g_report_ephemeral_clock_context.offset | ||
| 291 | : 0}; | ||
| 292 | // TODO system report "ephemeral_netclock_operation" | ||
| 293 | // "clock_time" = time | ||
| 294 | // "context_offset_before" = offset_before | ||
| 295 | // "context_offset_after" = context.offset | ||
| 296 | g_report_ephemeral_clock_context = context; | ||
| 297 | if (!g_ig_report_ephemeral_clock_context_set) { | ||
| 298 | g_ig_report_ephemeral_clock_context_set = true; | ||
| 299 | } | ||
| 300 | } break; | ||
| 301 | |||
| 302 | case EventType::UpdateSteadyClock: | ||
| 303 | m_timer_steady_clock->Clear(); | ||
| 304 | |||
| 305 | m_steady_clock_resource.UpdateTime(); | ||
| 306 | m_time_m->SetStandardSteadyClockBaseTime(m_steady_clock_resource.GetTime()); | ||
| 307 | break; | ||
| 308 | |||
| 309 | case EventType::UpdateFileTimestamp: | ||
| 310 | m_timer_file_system->Clear(); | ||
| 311 | |||
| 312 | m_file_timestamp_worker.SetFilesystemPosixTime(); | ||
| 313 | break; | ||
| 314 | |||
| 315 | case EventType::AutoCorrect: { | ||
| 316 | m_standard_user_auto_correct_clock_event->Clear(); | ||
| 317 | |||
| 318 | bool automatic_correction{}; | ||
| 319 | auto res = m_time_sm->IsStandardUserSystemClockAutomaticCorrectionEnabled( | ||
| 320 | automatic_correction); | ||
| 321 | ASSERT(res == ResultSuccess); | ||
| 322 | |||
| 323 | Service::PSC::Time::SteadyClockTimePoint time_point{}; | ||
| 324 | res = m_time_sm->GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(time_point); | ||
| 325 | ASSERT(res == ResultSuccess); | ||
| 326 | |||
| 327 | m_set_sys->SetUserSystemClockAutomaticCorrectionEnabled(automatic_correction); | ||
| 328 | m_set_sys->SetUserSystemClockAutomaticCorrectionUpdatedTime(time_point); | ||
| 329 | } break; | ||
| 330 | |||
| 331 | default: | ||
| 332 | UNREACHABLE(); | ||
| 333 | break; | ||
| 334 | } | ||
| 335 | } | ||
| 336 | } | ||
| 337 | |||
| 338 | } // namespace Service::Glue::Time | ||
diff --git a/src/core/hle/service/glue/time/worker.h b/src/core/hle/service/glue/time/worker.h new file mode 100644 index 000000000..adbbe6b6d --- /dev/null +++ b/src/core/hle/service/glue/time/worker.h | |||
| @@ -0,0 +1,64 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "common/common_types.h" | ||
| 7 | #include "core/hle/kernel/k_event.h" | ||
| 8 | #include "core/hle/service/glue/time/alarm_worker.h" | ||
| 9 | #include "core/hle/service/glue/time/pm_state_change_handler.h" | ||
| 10 | #include "core/hle/service/kernel_helpers.h" | ||
| 11 | |||
| 12 | namespace Service::Set { | ||
| 13 | class ISystemSettingsServer; | ||
| 14 | } | ||
| 15 | |||
| 16 | namespace Service::PSC::Time { | ||
| 17 | class StaticService; | ||
| 18 | class SystemClock; | ||
| 19 | } // namespace Service::PSC::Time | ||
| 20 | |||
| 21 | namespace Service::Glue::Time { | ||
| 22 | class FileTimestampWorker; | ||
| 23 | class StandardSteadyClockResource; | ||
| 24 | |||
| 25 | class TimeWorker { | ||
| 26 | public: | ||
| 27 | explicit TimeWorker(Core::System& system, StandardSteadyClockResource& steady_clock_resource, | ||
| 28 | FileTimestampWorker& file_timestamp_worker); | ||
| 29 | ~TimeWorker(); | ||
| 30 | |||
| 31 | void Initialize(std::shared_ptr<Service::PSC::Time::StaticService> time_sm, | ||
| 32 | std::shared_ptr<Service::Set::ISystemSettingsServer> set_sys); | ||
| 33 | |||
| 34 | void StartThread(); | ||
| 35 | |||
| 36 | private: | ||
| 37 | void ThreadFunc(std::stop_token stop_token); | ||
| 38 | |||
| 39 | Core::System& m_system; | ||
| 40 | KernelHelpers::ServiceContext m_ctx; | ||
| 41 | std::shared_ptr<Service::Set::ISystemSettingsServer> m_set_sys; | ||
| 42 | |||
| 43 | std::jthread m_thread; | ||
| 44 | Kernel::KEvent* m_event{}; | ||
| 45 | std::shared_ptr<Service::PSC::Time::ServiceManager> m_time_m; | ||
| 46 | std::shared_ptr<Service::PSC::Time::StaticService> m_time_sm; | ||
| 47 | std::shared_ptr<Service::PSC::Time::SystemClock> m_network_clock; | ||
| 48 | std::shared_ptr<Service::PSC::Time::SystemClock> m_local_clock; | ||
| 49 | std::shared_ptr<Service::PSC::Time::SystemClock> m_ephemeral_clock; | ||
| 50 | StandardSteadyClockResource& m_steady_clock_resource; | ||
| 51 | FileTimestampWorker& m_file_timestamp_worker; | ||
| 52 | Kernel::KEvent* m_local_clock_event{}; | ||
| 53 | Kernel::KEvent* m_network_clock_event{}; | ||
| 54 | Kernel::KEvent* m_ephemeral_clock_event{}; | ||
| 55 | Kernel::KEvent* m_standard_user_auto_correct_clock_event{}; | ||
| 56 | Kernel::KEvent* m_timer_steady_clock{}; | ||
| 57 | std::shared_ptr<Core::Timing::EventType> m_timer_steady_clock_timing_event; | ||
| 58 | Kernel::KEvent* m_timer_file_system{}; | ||
| 59 | std::shared_ptr<Core::Timing::EventType> m_timer_file_system_timing_event; | ||
| 60 | AlarmWorker m_alarm_worker; | ||
| 61 | PmStateChangeHandler m_pm_state_change_handler; | ||
| 62 | }; | ||
| 63 | |||
| 64 | } // namespace Service::Glue::Time | ||