manager.cpp 11 KB

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