From b18ae1c884c2339481dc9b077dcb33b496c80d99 Mon Sep 17 00:00:00 2001 From: fincs Date: Fri, 10 Apr 2020 19:42:31 +0200 Subject: [PATCH] time: Add timeGetStandardSteadyClockTimePoint (uses sharedmem on 6.x+, ISteadyClock prior to 6.x) --- nx/include/switch/services/time.h | 13 +++++++++- nx/source/services/time.c | 43 +++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/nx/include/switch/services/time.h b/nx/include/switch/services/time.h index b37847ae..e48d0f45 100644 --- a/nx/include/switch/services/time.h +++ b/nx/include/switch/services/time.h @@ -53,7 +53,7 @@ typedef struct { } TimeLocationName; typedef struct { - s64 time_point; ///< A point in time. + s64 time_point; ///< Monotonic count in seconds. Uuid source_id; ///< An ID representing the clock source. } TimeSteadyClockTimePoint; @@ -74,12 +74,23 @@ Service* timeGetServiceSession(void); /// Gets the Service object for ISystemClock with the specified \ref TimeType. This will return NULL when the type is invalid. Service* timeGetServiceSession_SystemClock(TimeType type); +/// Gets the Service object for ISteadyClock. +Service* timeGetServiceSession_SteadyClock(void); + /// Gets the Service object for ITimeZoneService. Service* timeGetServiceSession_TimeZoneService(void); /// [6.0.0+] Gets the address of the SharedMemory. void* timeGetSharedmemAddr(void); +/** + * @brief Gets the timepoint for the standard steady clock. + * @param[out] out Output timepoint (see \ref TimeSteadyClockTimePoint) + * @remark The standard steady clock counts time since the RTC was configured (usually this happens during manufacturing). + * @return Result code. + */ +Result timeGetStandardSteadyClockTimePoint(TimeSteadyClockTimePoint *out); + /** * @brief Gets the time for the specified clock. * @param[in] type Clock to use. diff --git a/nx/source/services/time.c b/nx/source/services/time.c index 1ac49bea..510f200d 100644 --- a/nx/source/services/time.c +++ b/nx/source/services/time.c @@ -1,5 +1,8 @@ #define NX_SERVICE_ASSUME_NON_DOMAIN +#include +#include #include "service_guard.h" +#include "arm/counter.h" #include "kernel/shmem.h" #include "services/time.h" #include "runtime/hosversion.h" @@ -9,6 +12,7 @@ __attribute__((weak)) TimeServiceType __nx_time_service_type = TimeServiceType_U static Service g_timeSrv; static Service g_timeUserSystemClock; static Service g_timeNetworkSystemClock; +static Service g_timeSteadyClock; static Service g_timeTimeZoneService; static Service g_timeLocalSystemClock; @@ -16,6 +20,7 @@ static SharedMemory g_timeSharedmem; static Result _timeCmdGetSession(Service* srv, Service* srv_out, u32 cmd_id); static Result _timeGetSharedMemoryNativeHandle(Service* srv, Handle* out); +static void _timeReadSharedmemObj(void* out, size_t offset, size_t size); NX_GENERATE_SERVICE_GUARD(time); @@ -51,6 +56,9 @@ Result _timeInitialize(void) { if (R_SUCCEEDED(rc)) rc = _timeCmdGetSession(&g_timeSrv, &g_timeNetworkSystemClock, 1); + if (R_SUCCEEDED(rc)) + rc = _timeCmdGetSession(&g_timeSrv, &g_timeSteadyClock, 2); + if (R_SUCCEEDED(rc)) rc = _timeCmdGetSession(&g_timeSrv, &g_timeTimeZoneService, 3); @@ -73,6 +81,7 @@ void _timeCleanup(void) { shmemClose(&g_timeSharedmem); serviceClose(&g_timeLocalSystemClock); serviceClose(&g_timeTimeZoneService); + serviceClose(&g_timeSteadyClock); serviceClose(&g_timeNetworkSystemClock); serviceClose(&g_timeUserSystemClock); serviceClose(&g_timeSrv); @@ -97,6 +106,10 @@ Service* timeGetServiceSession_SystemClock(TimeType type) { } } +Service* timeGetServiceSession_SteadyClock(void) { + return &g_timeSteadyClock; +} + Service* timeGetServiceSession_TimeZoneService(void) { return &g_timeTimeZoneService; } @@ -105,6 +118,20 @@ void* timeGetSharedmemAddr(void) { return shmemGetAddr(&g_timeSharedmem); } +void _timeReadSharedmemObj(void* out, size_t offset, size_t size) { + void* addr = (u8*)shmemGetAddr(&g_timeSharedmem) + offset; + + vu32* counter = (vu32*)addr; + void* data = (u8*)addr + 8; + + u32 cur_counter; + do { + cur_counter = *counter; + memcpy(out, (u8*)data + (cur_counter&1)*size, size); + atomic_thread_fence(memory_order_consume); + } while (cur_counter != *counter); +} + static Result _timeCmdGetSession(Service* srv, Service* srv_out, u32 cmd_id) { return serviceDispatch(srv, cmd_id, .out_num_objects = 1, @@ -131,6 +158,22 @@ static Result _appletCmdNoInOutU32(Service* srv, u32 *out, u32 cmd_id) { return serviceDispatchOut(srv, cmd_id, *out); } +Result timeGetStandardSteadyClockTimePoint(TimeSteadyClockTimePoint *out) { + if (!shmemGetAddr(&g_timeSharedmem)) { + return serviceDispatchOut(&g_timeSteadyClock, 0, *out); + } + + struct { // SteadyClockContext + u64 internal_offset; + Uuid source_id; + } context; + + _timeReadSharedmemObj(&context, 0x00, sizeof(context)); + out->time_point = (context.internal_offset + armTicksToNs(armGetSystemTick())) / 1000000000UL; + out->source_id = context.source_id; + return 0; +} + Result timeGetCurrentTime(TimeType type, u64 *timestamp) { Service *srv = timeGetServiceSession_SystemClock(type);