static.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342
  1. // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include "common/scope_exit.h"
  4. #include "core/core.h"
  5. #include "core/core_timing.h"
  6. #include "core/hle/kernel/k_shared_memory.h"
  7. #include "core/hle/service/cmif_serialization.h"
  8. #include "core/hle/service/psc/time/clocks/ephemeral_network_system_clock_core.h"
  9. #include "core/hle/service/psc/time/clocks/standard_local_system_clock_core.h"
  10. #include "core/hle/service/psc/time/clocks/standard_network_system_clock_core.h"
  11. #include "core/hle/service/psc/time/clocks/standard_user_system_clock_core.h"
  12. #include "core/hle/service/psc/time/manager.h"
  13. #include "core/hle/service/psc/time/shared_memory.h"
  14. #include "core/hle/service/psc/time/static.h"
  15. #include "core/hle/service/psc/time/steady_clock.h"
  16. #include "core/hle/service/psc/time/system_clock.h"
  17. #include "core/hle/service/psc/time/time_zone.h"
  18. #include "core/hle/service/psc/time/time_zone_service.h"
  19. namespace Service::PSC::Time {
  20. namespace {
  21. constexpr Result GetTimeFromTimePointAndContext(s64* out_time, SteadyClockTimePoint& time_point,
  22. SystemClockContext& context) {
  23. R_UNLESS(out_time != nullptr, ResultInvalidArgument);
  24. R_UNLESS(time_point.IdMatches(context.steady_time_point), ResultClockMismatch);
  25. *out_time = context.offset + time_point.time_point;
  26. R_SUCCEED();
  27. }
  28. } // namespace
  29. StaticService::StaticService(Core::System& system_, StaticServiceSetupInfo setup_info,
  30. std::shared_ptr<TimeManager> time, const char* name)
  31. : ServiceFramework{system_, name}, m_system{system}, m_setup_info{setup_info}, m_time{time},
  32. m_local_system_clock{m_time->m_standard_local_system_clock},
  33. m_user_system_clock{m_time->m_standard_user_system_clock},
  34. m_network_system_clock{m_time->m_standard_network_system_clock},
  35. m_time_zone{m_time->m_time_zone},
  36. m_ephemeral_network_clock{m_time->m_ephemeral_network_clock}, m_shared_memory{
  37. m_time->m_shared_memory} {
  38. // clang-format off
  39. static const FunctionInfo functions[] = {
  40. {0, D<&StaticService::GetStandardUserSystemClock>, "GetStandardUserSystemClock"},
  41. {1, D<&StaticService::GetStandardNetworkSystemClock>, "GetStandardNetworkSystemClock"},
  42. {2, D<&StaticService::GetStandardSteadyClock>, "GetStandardSteadyClock"},
  43. {3, D<&StaticService::GetTimeZoneService>, "GetTimeZoneService"},
  44. {4, D<&StaticService::GetStandardLocalSystemClock>, "GetStandardLocalSystemClock"},
  45. {5, D<&StaticService::GetEphemeralNetworkSystemClock>, "GetEphemeralNetworkSystemClock"},
  46. {20, D<&StaticService::GetSharedMemoryNativeHandle>, "GetSharedMemoryNativeHandle"},
  47. {50, D<&StaticService::SetStandardSteadyClockInternalOffset>, "SetStandardSteadyClockInternalOffset"},
  48. {51, D<&StaticService::GetStandardSteadyClockRtcValue>, "GetStandardSteadyClockRtcValue"},
  49. {100, D<&StaticService::IsStandardUserSystemClockAutomaticCorrectionEnabled>, "IsStandardUserSystemClockAutomaticCorrectionEnabled"},
  50. {101, D<&StaticService::SetStandardUserSystemClockAutomaticCorrectionEnabled>, "SetStandardUserSystemClockAutomaticCorrectionEnabled"},
  51. {102, D<&StaticService::GetStandardUserSystemClockInitialYear>, "GetStandardUserSystemClockInitialYear"},
  52. {200, D<&StaticService::IsStandardNetworkSystemClockAccuracySufficient>, "IsStandardNetworkSystemClockAccuracySufficient"},
  53. {201, D<&StaticService::GetStandardUserSystemClockAutomaticCorrectionUpdatedTime>, "GetStandardUserSystemClockAutomaticCorrectionUpdatedTime"},
  54. {300, D<&StaticService::CalculateMonotonicSystemClockBaseTimePoint>, "CalculateMonotonicSystemClockBaseTimePoint"},
  55. {400, D<&StaticService::GetClockSnapshot>, "GetClockSnapshot"},
  56. {401, D<&StaticService::GetClockSnapshotFromSystemClockContext>, "GetClockSnapshotFromSystemClockContext"},
  57. {500, D<&StaticService::CalculateStandardUserSystemClockDifferenceByUser>, "CalculateStandardUserSystemClockDifferenceByUser"},
  58. {501, D<&StaticService::CalculateSpanBetween>, "CalculateSpanBetween"},
  59. };
  60. // clang-format on
  61. RegisterHandlers(functions);
  62. }
  63. Result StaticService::GetStandardUserSystemClock(OutInterface<SystemClock> out_service) {
  64. LOG_DEBUG(Service_Time, "called.");
  65. *out_service = std::make_shared<SystemClock>(m_system, m_user_system_clock,
  66. m_setup_info.can_write_user_clock,
  67. m_setup_info.can_write_uninitialized_clock);
  68. R_SUCCEED();
  69. }
  70. Result StaticService::GetStandardNetworkSystemClock(OutInterface<SystemClock> out_service) {
  71. LOG_DEBUG(Service_Time, "called.");
  72. *out_service = std::make_shared<SystemClock>(m_system, m_network_system_clock,
  73. m_setup_info.can_write_network_clock,
  74. m_setup_info.can_write_uninitialized_clock);
  75. R_SUCCEED();
  76. }
  77. Result StaticService::GetStandardSteadyClock(OutInterface<SteadyClock> out_service) {
  78. LOG_DEBUG(Service_Time, "called.");
  79. *out_service =
  80. std::make_shared<SteadyClock>(m_system, m_time, m_setup_info.can_write_steady_clock,
  81. m_setup_info.can_write_uninitialized_clock);
  82. R_SUCCEED();
  83. }
  84. Result StaticService::GetTimeZoneService(OutInterface<TimeZoneService> out_service) {
  85. LOG_DEBUG(Service_Time, "called.");
  86. *out_service =
  87. std::make_shared<TimeZoneService>(m_system, m_time->m_standard_steady_clock, m_time_zone,
  88. m_setup_info.can_write_timezone_device_location);
  89. R_SUCCEED();
  90. }
  91. Result StaticService::GetStandardLocalSystemClock(OutInterface<SystemClock> out_service) {
  92. LOG_DEBUG(Service_Time, "called.");
  93. *out_service = std::make_shared<SystemClock>(m_system, m_local_system_clock,
  94. m_setup_info.can_write_local_clock,
  95. m_setup_info.can_write_uninitialized_clock);
  96. R_SUCCEED();
  97. }
  98. Result StaticService::GetEphemeralNetworkSystemClock(OutInterface<SystemClock> out_service) {
  99. LOG_DEBUG(Service_Time, "called.");
  100. *out_service = std::make_shared<SystemClock>(m_system, m_ephemeral_network_clock,
  101. m_setup_info.can_write_network_clock,
  102. m_setup_info.can_write_uninitialized_clock);
  103. R_SUCCEED();
  104. }
  105. Result StaticService::GetSharedMemoryNativeHandle(
  106. OutCopyHandle<Kernel::KSharedMemory> out_shared_memory) {
  107. LOG_DEBUG(Service_Time, "called.");
  108. *out_shared_memory = &m_shared_memory.GetKSharedMemory();
  109. R_SUCCEED();
  110. }
  111. Result StaticService::SetStandardSteadyClockInternalOffset(s64 offset_ns) {
  112. LOG_DEBUG(Service_Time, "called. This function is not implemented!");
  113. R_UNLESS(m_setup_info.can_write_steady_clock, ResultPermissionDenied);
  114. R_RETURN(ResultNotImplemented);
  115. }
  116. Result StaticService::GetStandardSteadyClockRtcValue(Out<s64> out_rtc_value) {
  117. LOG_DEBUG(Service_Time, "called. This function is not implemented!");
  118. R_RETURN(ResultNotImplemented);
  119. }
  120. Result StaticService::IsStandardUserSystemClockAutomaticCorrectionEnabled(
  121. Out<bool> out_is_enabled) {
  122. SCOPE_EXIT {
  123. LOG_DEBUG(Service_Time, "called. out_is_enabled={}", *out_is_enabled);
  124. };
  125. R_UNLESS(m_user_system_clock.IsInitialized(), ResultClockUninitialized);
  126. *out_is_enabled = m_user_system_clock.GetAutomaticCorrection();
  127. R_SUCCEED();
  128. }
  129. Result StaticService::SetStandardUserSystemClockAutomaticCorrectionEnabled(
  130. bool automatic_correction) {
  131. LOG_DEBUG(Service_Time, "called. automatic_correction={}", automatic_correction);
  132. R_UNLESS(m_user_system_clock.IsInitialized() && m_time->m_standard_steady_clock.IsInitialized(),
  133. ResultClockUninitialized);
  134. R_UNLESS(m_setup_info.can_write_user_clock, ResultPermissionDenied);
  135. R_TRY(m_user_system_clock.SetAutomaticCorrection(automatic_correction));
  136. m_shared_memory.SetAutomaticCorrection(automatic_correction);
  137. SteadyClockTimePoint time_point{};
  138. R_TRY(m_time->m_standard_steady_clock.GetCurrentTimePoint(time_point));
  139. m_user_system_clock.SetTimePointAndSignal(time_point);
  140. m_user_system_clock.GetEvent().Signal();
  141. R_SUCCEED();
  142. }
  143. Result StaticService::GetStandardUserSystemClockInitialYear(Out<s32> out_year) {
  144. LOG_DEBUG(Service_Time, "called. This function is not implemented!");
  145. R_RETURN(ResultNotImplemented);
  146. }
  147. Result StaticService::IsStandardNetworkSystemClockAccuracySufficient(Out<bool> out_is_sufficient) {
  148. SCOPE_EXIT {
  149. LOG_DEBUG(Service_Time, "called. out_is_sufficient={}", *out_is_sufficient);
  150. };
  151. *out_is_sufficient = m_network_system_clock.IsAccuracySufficient();
  152. R_SUCCEED();
  153. }
  154. Result StaticService::GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(
  155. Out<SteadyClockTimePoint> out_time_point) {
  156. SCOPE_EXIT {
  157. LOG_DEBUG(Service_Time, "called. out_time_point={}", *out_time_point);
  158. };
  159. R_UNLESS(m_user_system_clock.IsInitialized(), ResultClockUninitialized);
  160. m_user_system_clock.GetTimePoint(*out_time_point);
  161. R_SUCCEED();
  162. }
  163. Result StaticService::CalculateMonotonicSystemClockBaseTimePoint(
  164. Out<s64> out_time, const SystemClockContext& context) {
  165. SCOPE_EXIT {
  166. LOG_DEBUG(Service_Time, "called. context={} out_time={}", context, *out_time);
  167. };
  168. R_UNLESS(m_time->m_standard_steady_clock.IsInitialized(), ResultClockUninitialized);
  169. SteadyClockTimePoint time_point{};
  170. R_TRY(m_time->m_standard_steady_clock.GetCurrentTimePoint(time_point));
  171. R_UNLESS(time_point.IdMatches(context.steady_time_point), ResultClockMismatch);
  172. auto one_second_ns{
  173. std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::seconds(1)).count()};
  174. auto ticks{m_system.CoreTiming().GetClockTicks()};
  175. auto current_time_ns{ConvertToTimeSpan(ticks).count()};
  176. *out_time = ((context.offset + time_point.time_point) - (current_time_ns / one_second_ns));
  177. R_SUCCEED();
  178. }
  179. Result StaticService::GetClockSnapshot(OutClockSnapshot out_snapshot, TimeType type) {
  180. SCOPE_EXIT {
  181. LOG_DEBUG(Service_Time, "called. type={} out_snapshot={}", type, *out_snapshot);
  182. };
  183. SystemClockContext user_context{};
  184. R_TRY(m_user_system_clock.GetContext(user_context));
  185. SystemClockContext network_context{};
  186. R_TRY(m_network_system_clock.GetContext(network_context));
  187. R_RETURN(GetClockSnapshotImpl(out_snapshot, user_context, network_context, type));
  188. }
  189. Result StaticService::GetClockSnapshotFromSystemClockContext(
  190. TimeType type, OutClockSnapshot out_snapshot, const SystemClockContext& user_context,
  191. const SystemClockContext& network_context) {
  192. SCOPE_EXIT {
  193. LOG_DEBUG(Service_Time,
  194. "called. type={} user_context={} network_context={} out_snapshot={}", type,
  195. user_context, network_context, *out_snapshot);
  196. };
  197. R_RETURN(GetClockSnapshotImpl(out_snapshot, user_context, network_context, type));
  198. }
  199. Result StaticService::CalculateStandardUserSystemClockDifferenceByUser(Out<s64> out_difference,
  200. InClockSnapshot a,
  201. InClockSnapshot b) {
  202. SCOPE_EXIT {
  203. LOG_DEBUG(Service_Time, "called. a={} b={} out_difference={}", *a, *b, *out_difference);
  204. };
  205. auto diff_s =
  206. std::chrono::seconds(b->user_context.offset) - std::chrono::seconds(a->user_context.offset);
  207. if (a->user_context == b->user_context ||
  208. !a->user_context.steady_time_point.IdMatches(b->user_context.steady_time_point)) {
  209. *out_difference = 0;
  210. R_SUCCEED();
  211. }
  212. if (!a->is_automatic_correction_enabled || !b->is_automatic_correction_enabled) {
  213. *out_difference = std::chrono::duration_cast<std::chrono::nanoseconds>(diff_s).count();
  214. R_SUCCEED();
  215. }
  216. if (a->network_context.steady_time_point.IdMatches(a->steady_clock_time_point) ||
  217. b->network_context.steady_time_point.IdMatches(b->steady_clock_time_point)) {
  218. *out_difference = 0;
  219. R_SUCCEED();
  220. }
  221. *out_difference = std::chrono::duration_cast<std::chrono::nanoseconds>(diff_s).count();
  222. R_SUCCEED();
  223. }
  224. Result StaticService::CalculateSpanBetween(Out<s64> out_time, InClockSnapshot a,
  225. InClockSnapshot b) {
  226. SCOPE_EXIT {
  227. LOG_DEBUG(Service_Time, "called. a={} b={} out_time={}", *a, *b, *out_time);
  228. };
  229. s64 time_s{};
  230. auto res =
  231. GetSpanBetweenTimePoints(&time_s, a->steady_clock_time_point, b->steady_clock_time_point);
  232. if (res != ResultSuccess) {
  233. R_UNLESS(a->network_time != 0 && b->network_time != 0, ResultTimeNotFound);
  234. time_s = b->network_time - a->network_time;
  235. }
  236. *out_time =
  237. std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::seconds(time_s)).count();
  238. R_SUCCEED();
  239. }
  240. Result StaticService::GetClockSnapshotImpl(OutClockSnapshot out_snapshot,
  241. const SystemClockContext& user_context,
  242. const SystemClockContext& network_context,
  243. TimeType type) {
  244. out_snapshot->user_context = user_context;
  245. out_snapshot->network_context = network_context;
  246. R_TRY(
  247. m_time->m_standard_steady_clock.GetCurrentTimePoint(out_snapshot->steady_clock_time_point));
  248. out_snapshot->is_automatic_correction_enabled = m_user_system_clock.GetAutomaticCorrection();
  249. R_TRY(m_time_zone.GetLocationName(out_snapshot->location_name));
  250. R_TRY(GetTimeFromTimePointAndContext(&out_snapshot->user_time,
  251. out_snapshot->steady_clock_time_point,
  252. out_snapshot->user_context));
  253. R_TRY(m_time_zone.ToCalendarTimeWithMyRule(out_snapshot->user_calendar_time,
  254. out_snapshot->user_calendar_additional_time,
  255. out_snapshot->user_time));
  256. if (GetTimeFromTimePointAndContext(&out_snapshot->network_time,
  257. out_snapshot->steady_clock_time_point,
  258. out_snapshot->network_context) != ResultSuccess) {
  259. out_snapshot->network_time = 0;
  260. }
  261. R_TRY(m_time_zone.ToCalendarTimeWithMyRule(out_snapshot->network_calendar_time,
  262. out_snapshot->network_calendar_additional_time,
  263. out_snapshot->network_time));
  264. out_snapshot->type = type;
  265. out_snapshot->unk_CE = 0;
  266. R_SUCCEED();
  267. }
  268. } // namespace Service::PSC::Time