manager.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include <chrono>
  4. #include "core/core.h"
  5. #include "core/core_timing.h"
  6. #include "common/settings.h"
  7. #include "common/time_zone.h"
  8. #include "core/file_sys/vfs/vfs.h"
  9. #include "core/hle/kernel/svc.h"
  10. #include "core/hle/service/glue/time/manager.h"
  11. #include "core/hle/service/glue/time/time_zone_binary.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/system_clock.h"
  15. #include "core/hle/service/psc/time/time_zone_service.h"
  16. #include "core/hle/service/set/system_settings_server.h"
  17. #include "core/hle/service/sm/sm.h"
  18. namespace Service::Glue::Time {
  19. namespace {
  20. s64 CalendarTimeToEpoch(Service::PSC::Time::CalendarTime calendar) {
  21. constexpr auto is_leap = [](s32 year) -> bool {
  22. return (((year) % 4) == 0 && (((year) % 100) != 0 || ((year) % 400) == 0));
  23. };
  24. constexpr std::array<s32, 12> MonthStartDayOfYear{
  25. 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334,
  26. };
  27. s16 month_s16{calendar.month};
  28. s8 month{static_cast<s8>(((month_s16 * 43) & ~std::numeric_limits<s16>::max()) +
  29. ((month_s16 * 43) >> 9))};
  30. s8 month_index{static_cast<s8>(calendar.month - 12 * month)};
  31. if (month_index == 0) {
  32. month_index = 12;
  33. }
  34. s32 year{(month + calendar.year) - !month_index};
  35. s32 v8{year >= 0 ? year : year + 3};
  36. s64 days_since_epoch = calendar.day + MonthStartDayOfYear[month_index - 1];
  37. days_since_epoch += (year * 365) + (v8 / 4) - (year / 100) + (year / 400) - 365;
  38. if (month_index <= 2 && is_leap(year)) {
  39. days_since_epoch--;
  40. }
  41. auto epoch_s{((24ll * days_since_epoch + calendar.hour) * 60ll + calendar.minute) * 60ll +
  42. calendar.second};
  43. return epoch_s - 62135683200ll;
  44. }
  45. s64 GetEpochTimeFromInitialYear(std::shared_ptr<Service::Set::ISystemSettingsServer>& set_sys) {
  46. Service::PSC::Time::CalendarTime calendar{
  47. .year = 2000,
  48. .month = 1,
  49. .day = 1,
  50. .hour = 0,
  51. .minute = 0,
  52. .second = 0,
  53. };
  54. set_sys->GetSettingsItemValueImpl<s16>(calendar.year, "time",
  55. "standard_user_clock_initial_year");
  56. return CalendarTimeToEpoch(calendar);
  57. }
  58. Service::PSC::Time::LocationName GetTimeZoneString(Service::PSC::Time::LocationName& in_name) {
  59. auto configured_zone = Settings::GetTimeZoneString(Settings::values.time_zone_index.GetValue());
  60. Service::PSC::Time::LocationName configured_name{};
  61. std::memcpy(configured_name.data(), configured_zone.data(),
  62. std::min(configured_name.size(), configured_zone.size()));
  63. if (!IsTimeZoneBinaryValid(configured_name)) {
  64. configured_zone = Common::TimeZone::FindSystemTimeZone();
  65. configured_name = {};
  66. std::memcpy(configured_name.data(), configured_zone.data(),
  67. std::min(configured_name.size(), configured_zone.size()));
  68. }
  69. ASSERT_MSG(IsTimeZoneBinaryValid(configured_name), "Invalid time zone {}!",
  70. configured_name.data());
  71. return configured_name;
  72. }
  73. } // namespace
  74. TimeManager::TimeManager(Core::System& system)
  75. : m_steady_clock_resource{system}, m_worker{system, m_steady_clock_resource,
  76. m_file_timestamp_worker} {
  77. m_time_m =
  78. system.ServiceManager().GetService<Service::PSC::Time::ServiceManager>("time:m", true);
  79. auto res = m_time_m->GetStaticServiceAsServiceManager(&m_time_sm);
  80. ASSERT(res == ResultSuccess);
  81. m_set_sys =
  82. system.ServiceManager().GetService<Service::Set::ISystemSettingsServer>("set:sys", true);
  83. res = MountTimeZoneBinary(system);
  84. ASSERT(res == ResultSuccess);
  85. m_worker.Initialize(m_time_sm, m_set_sys);
  86. res = m_time_sm->GetStandardUserSystemClock(&m_file_timestamp_worker.m_system_clock);
  87. ASSERT(res == ResultSuccess);
  88. res = m_time_sm->GetTimeZoneService(&m_file_timestamp_worker.m_time_zone);
  89. ASSERT(res == ResultSuccess);
  90. res = SetupStandardSteadyClockCore();
  91. ASSERT(res == ResultSuccess);
  92. Service::PSC::Time::SystemClockContext user_clock_context{};
  93. res = m_set_sys->GetUserSystemClockContext(&user_clock_context);
  94. ASSERT(res == ResultSuccess);
  95. // TODO the local clock should initialise with this epoch time, and be updated somewhere else on
  96. // first boot to update it, but I haven't been able to find that point (likely via ntc's auto
  97. // correct as it's defaulted to be enabled). So to get a time that isn't stuck in the past for
  98. // first boot, grab the current real seconds.
  99. auto epoch_time{GetEpochTimeFromInitialYear(m_set_sys)};
  100. if (user_clock_context == Service::PSC::Time::SystemClockContext{}) {
  101. m_steady_clock_resource.GetRtcTimeInSeconds(epoch_time);
  102. }
  103. res = m_time_m->SetupStandardLocalSystemClockCore(user_clock_context, epoch_time);
  104. ASSERT(res == ResultSuccess);
  105. Service::PSC::Time::SystemClockContext network_clock_context{};
  106. res = m_set_sys->GetNetworkSystemClockContext(&network_clock_context);
  107. ASSERT(res == ResultSuccess);
  108. s32 network_accuracy_m{};
  109. m_set_sys->GetSettingsItemValueImpl<s32>(network_accuracy_m, "time",
  110. "standard_network_clock_sufficient_accuracy_minutes");
  111. auto one_minute_ns{
  112. std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::minutes(1)).count()};
  113. s64 network_accuracy_ns{network_accuracy_m * one_minute_ns};
  114. res = m_time_m->SetupStandardNetworkSystemClockCore(network_clock_context, network_accuracy_ns);
  115. ASSERT(res == ResultSuccess);
  116. bool is_automatic_correction_enabled{};
  117. res = m_set_sys->IsUserSystemClockAutomaticCorrectionEnabled(&is_automatic_correction_enabled);
  118. ASSERT(res == ResultSuccess);
  119. Service::PSC::Time::SteadyClockTimePoint automatic_correction_time_point{};
  120. res = m_set_sys->GetUserSystemClockAutomaticCorrectionUpdatedTime(
  121. &automatic_correction_time_point);
  122. ASSERT(res == ResultSuccess);
  123. res = m_time_m->SetupStandardUserSystemClockCore(is_automatic_correction_enabled,
  124. automatic_correction_time_point);
  125. ASSERT(res == ResultSuccess);
  126. res = m_time_m->SetupEphemeralNetworkSystemClockCore();
  127. ASSERT(res == ResultSuccess);
  128. res = SetupTimeZoneServiceCore();
  129. ASSERT(res == ResultSuccess);
  130. s64 rtc_time_s{};
  131. res = m_steady_clock_resource.GetRtcTimeInSeconds(rtc_time_s);
  132. ASSERT(res == ResultSuccess);
  133. // TODO system report "launch"
  134. // "rtc_reset" = m_steady_clock_resource.m_rtc_reset
  135. // "rtc_value" = rtc_time_s
  136. m_worker.StartThread();
  137. m_file_timestamp_worker.m_initialized = true;
  138. s64 system_clock_time{};
  139. if (m_file_timestamp_worker.m_system_clock->GetCurrentTime(&system_clock_time) ==
  140. ResultSuccess) {
  141. Service::PSC::Time::CalendarTime calendar_time{};
  142. Service::PSC::Time::CalendarAdditionalInfo calendar_additional{};
  143. if (m_file_timestamp_worker.m_time_zone->ToCalendarTimeWithMyRule(
  144. &calendar_time, &calendar_additional, system_clock_time) == ResultSuccess) {
  145. // TODO IFileSystemProxy::SetCurrentPosixTime(system_clock_time,
  146. // calendar_additional.ut_offset)
  147. }
  148. }
  149. }
  150. Result TimeManager::SetupStandardSteadyClockCore() {
  151. Common::UUID external_clock_source_id{};
  152. auto res = m_set_sys->GetExternalSteadyClockSourceId(&external_clock_source_id);
  153. ASSERT(res == ResultSuccess);
  154. s64 external_steady_clock_internal_offset_s{};
  155. res = m_set_sys->GetExternalSteadyClockInternalOffset(&external_steady_clock_internal_offset_s);
  156. ASSERT(res == ResultSuccess);
  157. auto one_second_ns{
  158. std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::seconds(1)).count()};
  159. s64 external_steady_clock_internal_offset_ns{external_steady_clock_internal_offset_s *
  160. one_second_ns};
  161. s32 standard_steady_clock_test_offset_m{};
  162. m_set_sys->GetSettingsItemValueImpl<s32>(standard_steady_clock_test_offset_m, "time",
  163. "standard_steady_clock_test_offset_minutes");
  164. auto one_minute_ns{
  165. std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::minutes(1)).count()};
  166. s64 standard_steady_clock_test_offset_ns{standard_steady_clock_test_offset_m * one_minute_ns};
  167. auto reset_detected = m_steady_clock_resource.GetResetDetected();
  168. if (reset_detected) {
  169. external_clock_source_id = {};
  170. }
  171. Common::UUID clock_source_id{};
  172. m_steady_clock_resource.Initialize(&clock_source_id, &external_clock_source_id);
  173. if (clock_source_id != external_clock_source_id) {
  174. m_set_sys->SetExternalSteadyClockSourceId(clock_source_id);
  175. }
  176. res = m_time_m->SetupStandardSteadyClockCore(
  177. reset_detected, clock_source_id, m_steady_clock_resource.GetTime(),
  178. external_steady_clock_internal_offset_ns, standard_steady_clock_test_offset_ns);
  179. ASSERT(res == ResultSuccess);
  180. R_SUCCEED();
  181. }
  182. Result TimeManager::SetupTimeZoneServiceCore() {
  183. Service::PSC::Time::LocationName name{};
  184. auto res = m_set_sys->GetDeviceTimeZoneLocationName(&name);
  185. ASSERT(res == ResultSuccess);
  186. auto configured_zone = GetTimeZoneString(name);
  187. if (configured_zone != name) {
  188. m_set_sys->SetDeviceTimeZoneLocationName(configured_zone);
  189. name = configured_zone;
  190. std::shared_ptr<Service::PSC::Time::SystemClock> local_clock;
  191. m_time_sm->GetStandardLocalSystemClock(&local_clock);
  192. Service::PSC::Time::SystemClockContext context{};
  193. local_clock->GetSystemClockContext(&context);
  194. m_set_sys->SetDeviceTimeZoneLocationUpdatedTime(context.steady_time_point);
  195. }
  196. Service::PSC::Time::SteadyClockTimePoint time_point{};
  197. res = m_set_sys->GetDeviceTimeZoneLocationUpdatedTime(&time_point);
  198. ASSERT(res == ResultSuccess);
  199. auto location_count = GetTimeZoneCount();
  200. Service::PSC::Time::RuleVersion rule_version{};
  201. GetTimeZoneVersion(rule_version);
  202. std::span<const u8> rule_buffer{};
  203. size_t rule_size{};
  204. res = GetTimeZoneRule(rule_buffer, rule_size, name);
  205. ASSERT(res == ResultSuccess);
  206. res = m_time_m->SetupTimeZoneServiceCore(name, rule_version, location_count, time_point,
  207. rule_buffer);
  208. ASSERT(res == ResultSuccess);
  209. R_SUCCEED();
  210. }
  211. } // namespace Service::Glue::Time