time.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  1. // Copyright 2018 yuzu emulator team
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <chrono>
  5. #include <ctime>
  6. #include "common/logging/log.h"
  7. #include "core/core_timing.h"
  8. #include "core/core_timing_util.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/service/time/interface.h"
  13. #include "core/hle/service/time/time.h"
  14. namespace Service::Time {
  15. static void PosixToCalendar(u64 posix_time, CalendarTime& calendar_time,
  16. CalendarAdditionalInfo& additional_info,
  17. [[maybe_unused]] const TimeZoneRule& /*rule*/) {
  18. const std::time_t time(posix_time);
  19. const std::tm* tm = std::localtime(&time);
  20. if (tm == nullptr) {
  21. calendar_time = {};
  22. additional_info = {};
  23. return;
  24. }
  25. calendar_time.year = tm->tm_year + 1900;
  26. calendar_time.month = tm->tm_mon + 1;
  27. calendar_time.day = tm->tm_mday;
  28. calendar_time.hour = tm->tm_hour;
  29. calendar_time.minute = tm->tm_min;
  30. calendar_time.second = tm->tm_sec;
  31. additional_info.day_of_week = tm->tm_wday;
  32. additional_info.day_of_year = tm->tm_yday;
  33. std::memcpy(additional_info.name.data(), "UTC", sizeof("UTC"));
  34. additional_info.utc_offset = 0;
  35. }
  36. static u64 CalendarToPosix(const CalendarTime& calendar_time,
  37. [[maybe_unused]] const TimeZoneRule& /*rule*/) {
  38. std::tm time{};
  39. time.tm_year = calendar_time.year - 1900;
  40. time.tm_mon = calendar_time.month - 1;
  41. time.tm_mday = calendar_time.day;
  42. time.tm_hour = calendar_time.hour;
  43. time.tm_min = calendar_time.minute;
  44. time.tm_sec = calendar_time.second;
  45. std::time_t epoch_time = std::mktime(&time);
  46. return static_cast<u64>(epoch_time);
  47. }
  48. class ISystemClock final : public ServiceFramework<ISystemClock> {
  49. public:
  50. ISystemClock() : ServiceFramework("ISystemClock") {
  51. static const FunctionInfo functions[] = {
  52. {0, &ISystemClock::GetCurrentTime, "GetCurrentTime"},
  53. {1, nullptr, "SetCurrentTime"},
  54. {2, &ISystemClock::GetSystemClockContext, "GetSystemClockContext"},
  55. {3, nullptr, "SetSystemClockContext"},
  56. };
  57. RegisterHandlers(functions);
  58. }
  59. private:
  60. void GetCurrentTime(Kernel::HLERequestContext& ctx) {
  61. const s64 time_since_epoch{std::chrono::duration_cast<std::chrono::seconds>(
  62. std::chrono::system_clock::now().time_since_epoch())
  63. .count()};
  64. LOG_DEBUG(Service_Time, "called");
  65. IPC::ResponseBuilder rb{ctx, 4};
  66. rb.Push(RESULT_SUCCESS);
  67. rb.Push<u64>(time_since_epoch);
  68. }
  69. void GetSystemClockContext(Kernel::HLERequestContext& ctx) {
  70. LOG_WARNING(Service_Time, "(STUBBED) called");
  71. SystemClockContext system_clock_ontext{};
  72. IPC::ResponseBuilder rb{ctx, (sizeof(SystemClockContext) / 4) + 2};
  73. rb.Push(RESULT_SUCCESS);
  74. rb.PushRaw(system_clock_ontext);
  75. }
  76. };
  77. class ISteadyClock final : public ServiceFramework<ISteadyClock> {
  78. public:
  79. ISteadyClock() : ServiceFramework("ISteadyClock") {
  80. static const FunctionInfo functions[] = {
  81. {0, &ISteadyClock::GetCurrentTimePoint, "GetCurrentTimePoint"},
  82. };
  83. RegisterHandlers(functions);
  84. }
  85. private:
  86. void GetCurrentTimePoint(Kernel::HLERequestContext& ctx) {
  87. LOG_DEBUG(Service_Time, "called");
  88. SteadyClockTimePoint steady_clock_time_point{
  89. CoreTiming::cyclesToMs(CoreTiming::GetTicks()) / 1000};
  90. IPC::ResponseBuilder rb{ctx, (sizeof(SteadyClockTimePoint) / 4) + 2};
  91. rb.Push(RESULT_SUCCESS);
  92. rb.PushRaw(steady_clock_time_point);
  93. }
  94. };
  95. class ITimeZoneService final : public ServiceFramework<ITimeZoneService> {
  96. public:
  97. ITimeZoneService() : ServiceFramework("ITimeZoneService") {
  98. static const FunctionInfo functions[] = {
  99. {0, &ITimeZoneService::GetDeviceLocationName, "GetDeviceLocationName"},
  100. {1, nullptr, "SetDeviceLocationName"},
  101. {2, &ITimeZoneService::GetTotalLocationNameCount, "GetTotalLocationNameCount"},
  102. {3, nullptr, "LoadLocationNameList"},
  103. {4, &ITimeZoneService::LoadTimeZoneRule, "LoadTimeZoneRule"},
  104. {5, nullptr, "GetTimeZoneRuleVersion"},
  105. {100, &ITimeZoneService::ToCalendarTime, "ToCalendarTime"},
  106. {101, &ITimeZoneService::ToCalendarTimeWithMyRule, "ToCalendarTimeWithMyRule"},
  107. {201, &ITimeZoneService::ToPosixTime, "ToPosixTime"},
  108. {202, &ITimeZoneService::ToPosixTimeWithMyRule, "ToPosixTimeWithMyRule"},
  109. };
  110. RegisterHandlers(functions);
  111. }
  112. private:
  113. LocationName location_name{"UTC"};
  114. TimeZoneRule my_time_zone_rule{};
  115. void GetDeviceLocationName(Kernel::HLERequestContext& ctx) {
  116. LOG_DEBUG(Service_Time, "called");
  117. IPC::ResponseBuilder rb{ctx, (sizeof(LocationName) / 4) + 2};
  118. rb.Push(RESULT_SUCCESS);
  119. rb.PushRaw(location_name);
  120. }
  121. void GetTotalLocationNameCount(Kernel::HLERequestContext& ctx) {
  122. LOG_WARNING(Service_Time, "(STUBBED) called");
  123. IPC::ResponseBuilder rb{ctx, 3};
  124. rb.Push(RESULT_SUCCESS);
  125. rb.Push<u32>(0);
  126. }
  127. void LoadTimeZoneRule(Kernel::HLERequestContext& ctx) {
  128. LOG_WARNING(Service_Time, "(STUBBED) called");
  129. ctx.WriteBuffer(&my_time_zone_rule, sizeof(TimeZoneRule));
  130. IPC::ResponseBuilder rb{ctx, 2};
  131. rb.Push(RESULT_SUCCESS);
  132. }
  133. void ToCalendarTime(Kernel::HLERequestContext& ctx) {
  134. IPC::RequestParser rp{ctx};
  135. const u64 posix_time = rp.Pop<u64>();
  136. LOG_WARNING(Service_Time, "(STUBBED) called, posix_time=0x{:016X}", posix_time);
  137. TimeZoneRule time_zone_rule{};
  138. auto buffer = ctx.ReadBuffer();
  139. std::memcpy(&time_zone_rule, buffer.data(), buffer.size());
  140. CalendarTime calendar_time{2018, 1, 1, 0, 0, 0};
  141. CalendarAdditionalInfo additional_info{};
  142. PosixToCalendar(posix_time, calendar_time, additional_info, time_zone_rule);
  143. IPC::ResponseBuilder rb{ctx, 10};
  144. rb.Push(RESULT_SUCCESS);
  145. rb.PushRaw(calendar_time);
  146. rb.PushRaw(additional_info);
  147. }
  148. void ToCalendarTimeWithMyRule(Kernel::HLERequestContext& ctx) {
  149. IPC::RequestParser rp{ctx};
  150. const u64 posix_time = rp.Pop<u64>();
  151. LOG_WARNING(Service_Time, "(STUBBED) called, posix_time=0x{:016X}", posix_time);
  152. CalendarTime calendar_time{2018, 1, 1, 0, 0, 0};
  153. CalendarAdditionalInfo additional_info{};
  154. PosixToCalendar(posix_time, calendar_time, additional_info, my_time_zone_rule);
  155. IPC::ResponseBuilder rb{ctx, 10};
  156. rb.Push(RESULT_SUCCESS);
  157. rb.PushRaw(calendar_time);
  158. rb.PushRaw(additional_info);
  159. }
  160. void ToPosixTime(Kernel::HLERequestContext& ctx) {
  161. // TODO(ogniK): Figure out how to handle multiple times
  162. LOG_WARNING(Service_Time, "(STUBBED) called");
  163. IPC::RequestParser rp{ctx};
  164. auto calendar_time = rp.PopRaw<CalendarTime>();
  165. auto posix_time = CalendarToPosix(calendar_time, {});
  166. IPC::ResponseBuilder rb{ctx, 3};
  167. rb.Push(RESULT_SUCCESS);
  168. rb.PushRaw<u32>(1); // Amount of times we're returning
  169. ctx.WriteBuffer(&posix_time, sizeof(u64));
  170. }
  171. void ToPosixTimeWithMyRule(Kernel::HLERequestContext& ctx) {
  172. LOG_WARNING(Service_Time, "(STUBBED) called");
  173. IPC::RequestParser rp{ctx};
  174. auto calendar_time = rp.PopRaw<CalendarTime>();
  175. auto posix_time = CalendarToPosix(calendar_time, {});
  176. IPC::ResponseBuilder rb{ctx, 3};
  177. rb.Push(RESULT_SUCCESS);
  178. rb.PushRaw<u32>(1); // Amount of times we're returning
  179. ctx.WriteBuffer(&posix_time, sizeof(u64));
  180. }
  181. };
  182. void Module::Interface::GetStandardUserSystemClock(Kernel::HLERequestContext& ctx) {
  183. LOG_DEBUG(Service_Time, "called");
  184. IPC::ResponseBuilder rb{ctx, 2, 0, 1};
  185. rb.Push(RESULT_SUCCESS);
  186. rb.PushIpcInterface<ISystemClock>();
  187. }
  188. void Module::Interface::GetStandardNetworkSystemClock(Kernel::HLERequestContext& ctx) {
  189. LOG_DEBUG(Service_Time, "called");
  190. IPC::ResponseBuilder rb{ctx, 2, 0, 1};
  191. rb.Push(RESULT_SUCCESS);
  192. rb.PushIpcInterface<ISystemClock>();
  193. }
  194. void Module::Interface::GetStandardSteadyClock(Kernel::HLERequestContext& ctx) {
  195. LOG_DEBUG(Service_Time, "called");
  196. IPC::ResponseBuilder rb{ctx, 2, 0, 1};
  197. rb.Push(RESULT_SUCCESS);
  198. rb.PushIpcInterface<ISteadyClock>();
  199. }
  200. void Module::Interface::GetTimeZoneService(Kernel::HLERequestContext& ctx) {
  201. LOG_DEBUG(Service_Time, "called");
  202. IPC::ResponseBuilder rb{ctx, 2, 0, 1};
  203. rb.Push(RESULT_SUCCESS);
  204. rb.PushIpcInterface<ITimeZoneService>();
  205. }
  206. void Module::Interface::GetStandardLocalSystemClock(Kernel::HLERequestContext& ctx) {
  207. LOG_DEBUG(Service_Time, "called");
  208. IPC::ResponseBuilder rb{ctx, 2, 0, 1};
  209. rb.Push(RESULT_SUCCESS);
  210. rb.PushIpcInterface<ISystemClock>();
  211. }
  212. void Module::Interface::GetClockSnapshot(Kernel::HLERequestContext& ctx) {
  213. LOG_DEBUG(Service_Time, "called");
  214. IPC::RequestParser rp{ctx};
  215. auto unknown_u8 = rp.PopRaw<u8>();
  216. ClockSnapshot clock_snapshot{};
  217. const s64 time_since_epoch{std::chrono::duration_cast<std::chrono::seconds>(
  218. std::chrono::system_clock::now().time_since_epoch())
  219. .count()};
  220. CalendarTime calendar_time{};
  221. const std::time_t time(time_since_epoch);
  222. const std::tm* tm = std::localtime(&time);
  223. if (tm == nullptr) {
  224. LOG_ERROR(Service_Time, "tm is a nullptr");
  225. IPC::ResponseBuilder rb{ctx, 2};
  226. rb.Push(ResultCode(-1)); // TODO(ogniK): Find appropriate error code
  227. return;
  228. }
  229. SteadyClockTimePoint steady_clock_time_point{CoreTiming::cyclesToMs(CoreTiming::GetTicks()) /
  230. 1000};
  231. LocationName location_name{"UTC"};
  232. calendar_time.year = tm->tm_year + 1900;
  233. calendar_time.month = tm->tm_mon + 1;
  234. calendar_time.day = tm->tm_mday;
  235. calendar_time.hour = tm->tm_hour;
  236. calendar_time.minute = tm->tm_min;
  237. calendar_time.second = tm->tm_sec;
  238. clock_snapshot.system_posix_time = time_since_epoch;
  239. clock_snapshot.network_posix_time = time_since_epoch;
  240. clock_snapshot.system_calendar_time = calendar_time;
  241. clock_snapshot.network_calendar_time = calendar_time;
  242. CalendarAdditionalInfo additional_info{};
  243. PosixToCalendar(time_since_epoch, calendar_time, additional_info, {});
  244. clock_snapshot.system_calendar_info = additional_info;
  245. clock_snapshot.network_calendar_info = additional_info;
  246. clock_snapshot.steady_clock_timepoint = steady_clock_time_point;
  247. clock_snapshot.location_name = location_name;
  248. clock_snapshot.clock_auto_adjustment_enabled = 1;
  249. clock_snapshot.ipc_u8 = unknown_u8;
  250. IPC::ResponseBuilder rb{ctx, 2};
  251. rb.Push(RESULT_SUCCESS);
  252. ctx.WriteBuffer(&clock_snapshot, sizeof(ClockSnapshot));
  253. }
  254. void Module::Interface::CalculateStandardUserSystemClockDifferenceByUser(
  255. Kernel::HLERequestContext& ctx) {
  256. LOG_DEBUG(Service_Time, "called");
  257. IPC::RequestParser rp{ctx};
  258. const auto snapshot_a = rp.PopRaw<ClockSnapshot>();
  259. const auto snapshot_b = rp.PopRaw<ClockSnapshot>();
  260. const u64 difference =
  261. snapshot_b.user_clock_context.offset - snapshot_a.user_clock_context.offset;
  262. IPC::ResponseBuilder rb{ctx, 4};
  263. rb.Push(RESULT_SUCCESS);
  264. rb.PushRaw<u64>(difference);
  265. }
  266. Module::Interface::Interface(std::shared_ptr<Module> time, const char* name)
  267. : ServiceFramework(name), time(std::move(time)) {}
  268. Module::Interface::~Interface() = default;
  269. void InstallInterfaces(SM::ServiceManager& service_manager) {
  270. auto time = std::make_shared<Module>();
  271. std::make_shared<Time>(time, "time:a")->InstallAsService(service_manager);
  272. std::make_shared<Time>(time, "time:s")->InstallAsService(service_manager);
  273. std::make_shared<Time>(time, "time:u")->InstallAsService(service_manager);
  274. }
  275. } // namespace Service::Time