time: Add timeGetStandardSteadyClockTimePoint (uses sharedmem on 6.x+, ISteadyClock prior to 6.x)

This commit is contained in:
fincs 2020-04-10 19:42:31 +02:00
parent 2edfb7cc56
commit b18ae1c884
No known key found for this signature in database
GPG Key ID: 62C7609ADA219C60
2 changed files with 55 additions and 1 deletions

View File

@ -53,7 +53,7 @@ typedef struct {
} TimeLocationName; } TimeLocationName;
typedef struct { 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. Uuid source_id; ///< An ID representing the clock source.
} TimeSteadyClockTimePoint; } 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. /// 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); Service* timeGetServiceSession_SystemClock(TimeType type);
/// Gets the Service object for ISteadyClock.
Service* timeGetServiceSession_SteadyClock(void);
/// Gets the Service object for ITimeZoneService. /// Gets the Service object for ITimeZoneService.
Service* timeGetServiceSession_TimeZoneService(void); Service* timeGetServiceSession_TimeZoneService(void);
/// [6.0.0+] Gets the address of the SharedMemory. /// [6.0.0+] Gets the address of the SharedMemory.
void* timeGetSharedmemAddr(void); 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. * @brief Gets the time for the specified clock.
* @param[in] type Clock to use. * @param[in] type Clock to use.

View File

@ -1,5 +1,8 @@
#define NX_SERVICE_ASSUME_NON_DOMAIN #define NX_SERVICE_ASSUME_NON_DOMAIN
#include <string.h>
#include <stdatomic.h>
#include "service_guard.h" #include "service_guard.h"
#include "arm/counter.h"
#include "kernel/shmem.h" #include "kernel/shmem.h"
#include "services/time.h" #include "services/time.h"
#include "runtime/hosversion.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_timeSrv;
static Service g_timeUserSystemClock; static Service g_timeUserSystemClock;
static Service g_timeNetworkSystemClock; static Service g_timeNetworkSystemClock;
static Service g_timeSteadyClock;
static Service g_timeTimeZoneService; static Service g_timeTimeZoneService;
static Service g_timeLocalSystemClock; 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 _timeCmdGetSession(Service* srv, Service* srv_out, u32 cmd_id);
static Result _timeGetSharedMemoryNativeHandle(Service* srv, Handle* out); static Result _timeGetSharedMemoryNativeHandle(Service* srv, Handle* out);
static void _timeReadSharedmemObj(void* out, size_t offset, size_t size);
NX_GENERATE_SERVICE_GUARD(time); NX_GENERATE_SERVICE_GUARD(time);
@ -51,6 +56,9 @@ Result _timeInitialize(void) {
if (R_SUCCEEDED(rc)) if (R_SUCCEEDED(rc))
rc = _timeCmdGetSession(&g_timeSrv, &g_timeNetworkSystemClock, 1); rc = _timeCmdGetSession(&g_timeSrv, &g_timeNetworkSystemClock, 1);
if (R_SUCCEEDED(rc))
rc = _timeCmdGetSession(&g_timeSrv, &g_timeSteadyClock, 2);
if (R_SUCCEEDED(rc)) if (R_SUCCEEDED(rc))
rc = _timeCmdGetSession(&g_timeSrv, &g_timeTimeZoneService, 3); rc = _timeCmdGetSession(&g_timeSrv, &g_timeTimeZoneService, 3);
@ -73,6 +81,7 @@ void _timeCleanup(void) {
shmemClose(&g_timeSharedmem); shmemClose(&g_timeSharedmem);
serviceClose(&g_timeLocalSystemClock); serviceClose(&g_timeLocalSystemClock);
serviceClose(&g_timeTimeZoneService); serviceClose(&g_timeTimeZoneService);
serviceClose(&g_timeSteadyClock);
serviceClose(&g_timeNetworkSystemClock); serviceClose(&g_timeNetworkSystemClock);
serviceClose(&g_timeUserSystemClock); serviceClose(&g_timeUserSystemClock);
serviceClose(&g_timeSrv); serviceClose(&g_timeSrv);
@ -97,6 +106,10 @@ Service* timeGetServiceSession_SystemClock(TimeType type) {
} }
} }
Service* timeGetServiceSession_SteadyClock(void) {
return &g_timeSteadyClock;
}
Service* timeGetServiceSession_TimeZoneService(void) { Service* timeGetServiceSession_TimeZoneService(void) {
return &g_timeTimeZoneService; return &g_timeTimeZoneService;
} }
@ -105,6 +118,20 @@ void* timeGetSharedmemAddr(void) {
return shmemGetAddr(&g_timeSharedmem); 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) { static Result _timeCmdGetSession(Service* srv, Service* srv_out, u32 cmd_id) {
return serviceDispatch(srv, cmd_id, return serviceDispatch(srv, cmd_id,
.out_num_objects = 1, .out_num_objects = 1,
@ -131,6 +158,22 @@ static Result _appletCmdNoInOutU32(Service* srv, u32 *out, u32 cmd_id) {
return serviceDispatchOut(srv, cmd_id, *out); 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) { Result timeGetCurrentTime(TimeType type, u64 *timestamp) {
Service *srv = timeGetServiceSession_SystemClock(type); Service *srv = timeGetServiceSession_SystemClock(type);