mach_continuous_time.c [plain text]
#include <stddef.h>
#include <stdbool.h>
#include <sys/types.h>
#include <machine/cpu_capabilities.h>
#include <mach/mach_time.h>
__attribute__((visibility("hidden")))
uint64_t
_mach_continuous_time_base(void)
{
#if !defined(__x86_64__) && !defined(__arm64__)
while(1) {
volatile uint64_t *base_ptr = (volatile uint64_t*)_COMM_PAGE_CONT_TIMEBASE;
uint64_t read1, read2;
read1 = *base_ptr;
#if defined(__arm__)
__asm__ volatile("dsb sy" ::: "memory");
#elif defined(__i386__)
__asm__ volatile("lfence" ::: "memory");
#else
#error "unsupported arch"
#endif
read2 = *base_ptr;
if(__builtin_expect((read1 == read2), 1))
return read1;
}
#else // 64-bit
return *(volatile uint64_t*)_COMM_PAGE_CONT_TIMEBASE;
#endif // 64-bit
}
__attribute__((visibility("hidden")))
kern_return_t
_mach_continuous_hwclock(uint64_t *cont_time __unused)
{
#if defined(__arm64__)
uint8_t cont_hwclock = *((uint8_t*)_COMM_PAGE_CONT_HWCLOCK);
uint64_t timebase;
if (cont_hwclock) {
__asm__ volatile("isb\n" "mrs %0, CNTPCT_EL0" : "=r"(timebase));
*cont_time = timebase;
return KERN_SUCCESS;
}
#endif
return KERN_NOT_SUPPORTED;
}
__attribute__((visibility("hidden")))
kern_return_t
_mach_continuous_time(uint64_t* absolute_time, uint64_t* cont_time)
{
volatile uint64_t *base_ptr = (volatile uint64_t*)_COMM_PAGE_CONT_TIMEBASE;
volatile uint64_t read1, read2;
volatile uint64_t absolute;
do {
read1 = *base_ptr;
absolute = mach_absolute_time();
#if defined(__arm__) || defined(__arm64__)
#endif
read2 = *base_ptr;
} while (__builtin_expect((read1 != read2), 0));
if (absolute_time) *absolute_time = absolute;
if (cont_time) *cont_time = absolute + read1;
return KERN_SUCCESS;
}
uint64_t
mach_continuous_time(void)
{
uint64_t cont_time;
if (_mach_continuous_hwclock(&cont_time) != KERN_SUCCESS)
_mach_continuous_time(NULL, &cont_time);
return cont_time;
}
uint64_t
mach_continuous_approximate_time(void)
{
volatile register uint64_t time_base = _mach_continuous_time_base();
return time_base + mach_approximate_time();
}