manager.cpp 11 KB

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