time.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384
  1. // Copyright 2019 yuzu emulator team
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include "common/logging/log.h"
  5. #include "core/core.h"
  6. #include "core/core_timing.h"
  7. #include "core/core_timing_util.h"
  8. #include "core/hardware_properties.h"
  9. #include "core/hle/ipc_helpers.h"
  10. #include "core/hle/kernel/client_port.h"
  11. #include "core/hle/kernel/client_session.h"
  12. #include "core/hle/kernel/scheduler.h"
  13. #include "core/hle/service/time/interface.h"
  14. #include "core/hle/service/time/time.h"
  15. #include "core/hle/service/time/time_sharedmemory.h"
  16. #include "core/hle/service/time/time_zone_service.h"
  17. namespace Service::Time {
  18. class ISystemClock final : public ServiceFramework<ISystemClock> {
  19. public:
  20. explicit ISystemClock(Clock::SystemClockCore& clock_core, Core::System& system)
  21. : ServiceFramework("ISystemClock"), clock_core{clock_core}, system{system} {
  22. // clang-format off
  23. static const FunctionInfo functions[] = {
  24. {0, &ISystemClock::GetCurrentTime, "GetCurrentTime"},
  25. {1, nullptr, "SetCurrentTime"},
  26. {2, &ISystemClock::GetSystemClockContext, "GetSystemClockContext"},
  27. {3, nullptr, "SetSystemClockContext"},
  28. {4, nullptr, "GetOperationEventReadableHandle"},
  29. };
  30. // clang-format on
  31. RegisterHandlers(functions);
  32. }
  33. private:
  34. void GetCurrentTime(Kernel::HLERequestContext& ctx) {
  35. LOG_DEBUG(Service_Time, "called");
  36. if (!clock_core.IsInitialized()) {
  37. IPC::ResponseBuilder rb{ctx, 2};
  38. rb.Push(ERROR_UNINITIALIZED_CLOCK);
  39. return;
  40. }
  41. s64 posix_time{};
  42. if (const ResultCode result{clock_core.GetCurrentTime(system, posix_time)};
  43. result.IsError()) {
  44. IPC::ResponseBuilder rb{ctx, 2};
  45. rb.Push(result);
  46. return;
  47. }
  48. IPC::ResponseBuilder rb{ctx, 4};
  49. rb.Push(RESULT_SUCCESS);
  50. rb.Push<s64>(posix_time);
  51. }
  52. void GetSystemClockContext(Kernel::HLERequestContext& ctx) {
  53. LOG_DEBUG(Service_Time, "called");
  54. if (!clock_core.IsInitialized()) {
  55. IPC::ResponseBuilder rb{ctx, 2};
  56. rb.Push(ERROR_UNINITIALIZED_CLOCK);
  57. return;
  58. }
  59. Clock::SystemClockContext system_clock_context{};
  60. if (const ResultCode result{clock_core.GetClockContext(system, system_clock_context)};
  61. result.IsError()) {
  62. IPC::ResponseBuilder rb{ctx, 2};
  63. rb.Push(result);
  64. return;
  65. }
  66. IPC::ResponseBuilder rb{ctx, sizeof(Clock::SystemClockContext) / 4 + 2};
  67. rb.Push(RESULT_SUCCESS);
  68. rb.PushRaw(system_clock_context);
  69. }
  70. Clock::SystemClockCore& clock_core;
  71. Core::System& system;
  72. };
  73. class ISteadyClock final : public ServiceFramework<ISteadyClock> {
  74. public:
  75. explicit ISteadyClock(Clock::SteadyClockCore& clock_core, Core::System& system)
  76. : ServiceFramework("ISteadyClock"), clock_core{clock_core}, system{system} {
  77. static const FunctionInfo functions[] = {
  78. {0, &ISteadyClock::GetCurrentTimePoint, "GetCurrentTimePoint"},
  79. };
  80. RegisterHandlers(functions);
  81. }
  82. private:
  83. void GetCurrentTimePoint(Kernel::HLERequestContext& ctx) {
  84. LOG_DEBUG(Service_Time, "called");
  85. if (!clock_core.IsInitialized()) {
  86. IPC::ResponseBuilder rb{ctx, 2};
  87. rb.Push(ERROR_UNINITIALIZED_CLOCK);
  88. return;
  89. }
  90. const Clock::SteadyClockTimePoint time_point{clock_core.GetCurrentTimePoint(system)};
  91. IPC::ResponseBuilder rb{ctx, (sizeof(Clock::SteadyClockTimePoint) / 4) + 2};
  92. rb.Push(RESULT_SUCCESS);
  93. rb.PushRaw(time_point);
  94. }
  95. Clock::SteadyClockCore& clock_core;
  96. Core::System& system;
  97. };
  98. ResultCode Module::Interface::GetClockSnapshotFromSystemClockContextInternal(
  99. Kernel::Thread* thread, Clock::SystemClockContext user_context,
  100. Clock::SystemClockContext network_context, u8 type, Clock::ClockSnapshot& clock_snapshot) {
  101. auto& time_manager{module->GetTimeManager()};
  102. clock_snapshot.is_automatic_correction_enabled =
  103. time_manager.GetStandardUserSystemClockCore().IsAutomaticCorrectionEnabled();
  104. clock_snapshot.user_context = user_context;
  105. clock_snapshot.network_context = network_context;
  106. if (const ResultCode result{
  107. time_manager.GetTimeZoneContentManager().GetTimeZoneManager().GetDeviceLocationName(
  108. clock_snapshot.location_name)};
  109. result != RESULT_SUCCESS) {
  110. return result;
  111. }
  112. const auto current_time_point{
  113. time_manager.GetStandardSteadyClockCore().GetCurrentTimePoint(system)};
  114. if (const ResultCode result{Clock::ClockSnapshot::GetCurrentTime(
  115. clock_snapshot.user_time, current_time_point, clock_snapshot.user_context)};
  116. result != RESULT_SUCCESS) {
  117. return result;
  118. }
  119. TimeZone::CalendarInfo userCalendarInfo{};
  120. if (const ResultCode result{
  121. time_manager.GetTimeZoneContentManager().GetTimeZoneManager().ToCalendarTimeWithMyRules(
  122. clock_snapshot.user_time, userCalendarInfo)};
  123. result != RESULT_SUCCESS) {
  124. return result;
  125. }
  126. clock_snapshot.user_calendar_time = userCalendarInfo.time;
  127. clock_snapshot.user_calendar_additional_time = userCalendarInfo.additiona_info;
  128. if (Clock::ClockSnapshot::GetCurrentTime(clock_snapshot.network_time, current_time_point,
  129. clock_snapshot.network_context) != RESULT_SUCCESS) {
  130. clock_snapshot.network_time = 0;
  131. }
  132. TimeZone::CalendarInfo networkCalendarInfo{};
  133. if (const ResultCode result{
  134. time_manager.GetTimeZoneContentManager().GetTimeZoneManager().ToCalendarTimeWithMyRules(
  135. clock_snapshot.network_time, networkCalendarInfo)};
  136. result != RESULT_SUCCESS) {
  137. return result;
  138. }
  139. clock_snapshot.network_calendar_time = networkCalendarInfo.time;
  140. clock_snapshot.network_calendar_additional_time = networkCalendarInfo.additiona_info;
  141. clock_snapshot.type = type;
  142. return RESULT_SUCCESS;
  143. }
  144. void Module::Interface::GetStandardUserSystemClock(Kernel::HLERequestContext& ctx) {
  145. LOG_DEBUG(Service_Time, "called");
  146. IPC::ResponseBuilder rb{ctx, 2, 0, 1};
  147. rb.Push(RESULT_SUCCESS);
  148. rb.PushIpcInterface<ISystemClock>(module->GetTimeManager().GetStandardUserSystemClockCore(),
  149. system);
  150. }
  151. void Module::Interface::GetStandardNetworkSystemClock(Kernel::HLERequestContext& ctx) {
  152. LOG_DEBUG(Service_Time, "called");
  153. IPC::ResponseBuilder rb{ctx, 2, 0, 1};
  154. rb.Push(RESULT_SUCCESS);
  155. rb.PushIpcInterface<ISystemClock>(module->GetTimeManager().GetStandardNetworkSystemClockCore(),
  156. system);
  157. }
  158. void Module::Interface::GetStandardSteadyClock(Kernel::HLERequestContext& ctx) {
  159. LOG_DEBUG(Service_Time, "called");
  160. IPC::ResponseBuilder rb{ctx, 2, 0, 1};
  161. rb.Push(RESULT_SUCCESS);
  162. rb.PushIpcInterface<ISteadyClock>(module->GetTimeManager().GetStandardSteadyClockCore(),
  163. system);
  164. }
  165. void Module::Interface::GetTimeZoneService(Kernel::HLERequestContext& ctx) {
  166. LOG_DEBUG(Service_Time, "called");
  167. IPC::ResponseBuilder rb{ctx, 2, 0, 1};
  168. rb.Push(RESULT_SUCCESS);
  169. rb.PushIpcInterface<ITimeZoneService>(module->GetTimeManager().GetTimeZoneContentManager());
  170. }
  171. void Module::Interface::GetStandardLocalSystemClock(Kernel::HLERequestContext& ctx) {
  172. LOG_DEBUG(Service_Time, "called");
  173. IPC::ResponseBuilder rb{ctx, 2, 0, 1};
  174. rb.Push(RESULT_SUCCESS);
  175. rb.PushIpcInterface<ISystemClock>(module->GetTimeManager().GetStandardLocalSystemClockCore(),
  176. system);
  177. }
  178. void Module::Interface::IsStandardNetworkSystemClockAccuracySufficient(
  179. Kernel::HLERequestContext& ctx) {
  180. LOG_DEBUG(Service_Time, "called");
  181. auto& clock_core{module->GetTimeManager().GetStandardNetworkSystemClockCore()};
  182. IPC::ResponseBuilder rb{ctx, 3};
  183. rb.Push(RESULT_SUCCESS);
  184. rb.Push<u32>(clock_core.IsStandardNetworkSystemClockAccuracySufficient(system));
  185. }
  186. void Module::Interface::CalculateMonotonicSystemClockBaseTimePoint(Kernel::HLERequestContext& ctx) {
  187. LOG_DEBUG(Service_Time, "called");
  188. auto& steady_clock_core{module->GetTimeManager().GetStandardSteadyClockCore()};
  189. if (!steady_clock_core.IsInitialized()) {
  190. IPC::ResponseBuilder rb{ctx, 2};
  191. rb.Push(ERROR_UNINITIALIZED_CLOCK);
  192. return;
  193. }
  194. IPC::RequestParser rp{ctx};
  195. const auto context{rp.PopRaw<Clock::SystemClockContext>()};
  196. const auto current_time_point{steady_clock_core.GetCurrentTimePoint(system)};
  197. if (current_time_point.clock_source_id == context.steady_time_point.clock_source_id) {
  198. const auto ticks{Clock::TimeSpanType::FromTicks(
  199. Core::Timing::CpuCyclesToClockCycles(system.CoreTiming().GetTicks()),
  200. Core::Hardware::CNTFREQ)};
  201. const s64 base_time_point{context.offset + current_time_point.time_point -
  202. ticks.ToSeconds()};
  203. IPC::ResponseBuilder rb{ctx, (sizeof(s64) / 4) + 2};
  204. rb.Push(RESULT_SUCCESS);
  205. rb.PushRaw(base_time_point);
  206. return;
  207. }
  208. IPC::ResponseBuilder rb{ctx, 2};
  209. rb.Push(ERROR_TIME_MISMATCH);
  210. }
  211. void Module::Interface::GetClockSnapshot(Kernel::HLERequestContext& ctx) {
  212. LOG_DEBUG(Service_Time, "called");
  213. IPC::RequestParser rp{ctx};
  214. const auto type{rp.PopRaw<u8>()};
  215. Clock::SystemClockContext user_context{};
  216. if (const ResultCode result{
  217. module->GetTimeManager().GetStandardUserSystemClockCore().GetClockContext(
  218. system, user_context)};
  219. result.IsError()) {
  220. IPC::ResponseBuilder rb{ctx, 2};
  221. rb.Push(result);
  222. return;
  223. }
  224. Clock::SystemClockContext network_context{};
  225. if (const ResultCode result{
  226. module->GetTimeManager().GetStandardNetworkSystemClockCore().GetClockContext(
  227. system, network_context)};
  228. result.IsError()) {
  229. IPC::ResponseBuilder rb{ctx, 2};
  230. rb.Push(result);
  231. return;
  232. }
  233. Clock::ClockSnapshot clock_snapshot{};
  234. if (const ResultCode result{GetClockSnapshotFromSystemClockContextInternal(
  235. &ctx.GetThread(), user_context, network_context, type, clock_snapshot)};
  236. result.IsError()) {
  237. IPC::ResponseBuilder rb{ctx, 2};
  238. rb.Push(result);
  239. return;
  240. }
  241. IPC::ResponseBuilder rb{ctx, 2};
  242. rb.Push(RESULT_SUCCESS);
  243. ctx.WriteBuffer(&clock_snapshot, sizeof(Clock::ClockSnapshot));
  244. }
  245. void Module::Interface::GetClockSnapshotFromSystemClockContext(Kernel::HLERequestContext& ctx) {
  246. LOG_DEBUG(Service_Time, "called");
  247. IPC::RequestParser rp{ctx};
  248. const auto type{rp.PopRaw<u8>()};
  249. rp.AlignWithPadding();
  250. const Clock::SystemClockContext user_context{rp.PopRaw<Clock::SystemClockContext>()};
  251. const Clock::SystemClockContext network_context{rp.PopRaw<Clock::SystemClockContext>()};
  252. Clock::ClockSnapshot clock_snapshot{};
  253. if (const ResultCode result{GetClockSnapshotFromSystemClockContextInternal(
  254. &ctx.GetThread(), user_context, network_context, type, clock_snapshot)};
  255. result != RESULT_SUCCESS) {
  256. IPC::ResponseBuilder rb{ctx, 2};
  257. rb.Push(result);
  258. return;
  259. }
  260. IPC::ResponseBuilder rb{ctx, 2};
  261. rb.Push(RESULT_SUCCESS);
  262. ctx.WriteBuffer(&clock_snapshot, sizeof(Clock::ClockSnapshot));
  263. }
  264. void Module::Interface::CalculateStandardUserSystemClockDifferenceByUser(
  265. Kernel::HLERequestContext& ctx) {
  266. LOG_DEBUG(Service_Time, "called");
  267. IPC::RequestParser rp{ctx};
  268. const auto snapshot_a = rp.PopRaw<Clock::ClockSnapshot>();
  269. const auto snapshot_b = rp.PopRaw<Clock::ClockSnapshot>();
  270. auto time_span_type{Clock::TimeSpanType::FromSeconds(snapshot_b.user_context.offset -
  271. snapshot_a.user_context.offset)};
  272. if ((snapshot_b.user_context.steady_time_point.clock_source_id !=
  273. snapshot_a.user_context.steady_time_point.clock_source_id) ||
  274. (snapshot_b.is_automatic_correction_enabled &&
  275. snapshot_a.is_automatic_correction_enabled)) {
  276. time_span_type.nanoseconds = 0;
  277. }
  278. IPC::ResponseBuilder rb{ctx, (sizeof(s64) / 4) + 2};
  279. rb.Push(RESULT_SUCCESS);
  280. rb.PushRaw(time_span_type.nanoseconds);
  281. }
  282. void Module::Interface::CalculateSpanBetween(Kernel::HLERequestContext& ctx) {
  283. LOG_DEBUG(Service_Time, "called");
  284. IPC::RequestParser rp{ctx};
  285. const auto snapshot_a = rp.PopRaw<Clock::ClockSnapshot>();
  286. const auto snapshot_b = rp.PopRaw<Clock::ClockSnapshot>();
  287. Clock::TimeSpanType time_span_type{};
  288. s64 span{};
  289. if (const ResultCode result{snapshot_a.steady_clock_time_point.GetSpanBetween(
  290. snapshot_b.steady_clock_time_point, span)};
  291. result != RESULT_SUCCESS) {
  292. if (snapshot_a.network_time && snapshot_b.network_time) {
  293. time_span_type =
  294. Clock::TimeSpanType::FromSeconds(snapshot_b.network_time - snapshot_a.network_time);
  295. } else {
  296. IPC::ResponseBuilder rb{ctx, 2};
  297. rb.Push(ERROR_TIME_NOT_FOUND);
  298. return;
  299. }
  300. } else {
  301. time_span_type = Clock::TimeSpanType::FromSeconds(span);
  302. }
  303. IPC::ResponseBuilder rb{ctx, (sizeof(s64) / 4) + 2};
  304. rb.Push(RESULT_SUCCESS);
  305. rb.PushRaw(time_span_type.nanoseconds);
  306. }
  307. void Module::Interface::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) {
  308. LOG_DEBUG(Service_Time, "called");
  309. IPC::ResponseBuilder rb{ctx, 2, 1};
  310. rb.Push(RESULT_SUCCESS);
  311. rb.PushCopyObjects(module->GetTimeManager().GetSharedMemory().GetSharedMemoryHolder());
  312. }
  313. Module::Interface::Interface(std::shared_ptr<Module> module, Core::System& system, const char* name)
  314. : ServiceFramework(name), module{std::move(module)}, system{system} {}
  315. Module::Interface::~Interface() = default;
  316. void InstallInterfaces(Core::System& system) {
  317. auto module{std::make_shared<Module>(system)};
  318. std::make_shared<Time>(module, system, "time:a")->InstallAsService(system.ServiceManager());
  319. std::make_shared<Time>(module, system, "time:s")->InstallAsService(system.ServiceManager());
  320. std::make_shared<Time>(module, system, "time:u")->InstallAsService(system.ServiceManager());
  321. }
  322. } // namespace Service::Time