1/*
2 * Copyright 2014, Pawe�� Dziepak, pdziepak@quarnos.org.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7#include <OS.h>
8
9#include <stdint.h>
10
11#include <x86intrin.h>
12
13
14static uint64_t cv_factor;
15static uint64_t cv_factor_nsec;
16
17
18static int64_t
19__system_time_lfence()
20{
21	__builtin_ia32_lfence();
22	__uint128_t time = static_cast<__uint128_t>(__rdtsc()) * cv_factor;
23	return time >> 64;
24}
25
26
27static int64_t
28__system_time_rdtscp()
29{
30	uint32_t aux;
31	__uint128_t time = static_cast<__uint128_t>(__rdtscp(&aux)) * cv_factor;
32	return time >> 64;
33}
34
35
36static int64_t
37__system_time_nsecs_lfence()
38{
39	__builtin_ia32_lfence();
40	__uint128_t t = static_cast<__uint128_t>(__rdtsc()) * cv_factor_nsec;
41	return t >> 32;
42}
43
44
45static int64_t
46__system_time_nsecs_rdtscp()
47{
48	uint32_t aux;
49	__uint128_t t = static_cast<__uint128_t>(__rdtscp(&aux)) * cv_factor_nsec;
50	return t >> 32;
51}
52
53
54static int64_t (*sSystemTime)(void) = __system_time_lfence;
55static int64_t (*sSystemTimeNsecs)(void) = __system_time_nsecs_lfence;
56
57
58// from kernel/arch/x86/arch_cpu.h
59#define IA32_FEATURE_AMD_EXT_RDTSCP		(1 << 27) // rdtscp instruction
60
61
62extern "C" void
63__x86_setup_system_time(uint64_t cv, uint64_t cv_nsec)
64{
65	cv_factor = cv;
66	cv_factor_nsec = cv_nsec;
67
68	cpuid_info cpuInfo;
69	get_cpuid(&cpuInfo, 0x80000000, 0);
70	if (cpuInfo.eax_0.max_eax >= 0x80000001) {
71		get_cpuid(&cpuInfo, 0x80000001, 0);
72		if ((cpuInfo.regs.edx & IA32_FEATURE_AMD_EXT_RDTSCP)!= 0) {
73			sSystemTime = __system_time_rdtscp;
74			sSystemTimeNsecs = __system_time_nsecs_rdtscp;
75		}
76	}
77}
78
79
80extern "C" int64_t
81system_time()
82{
83	return sSystemTime();
84}
85
86
87
88extern "C" int64_t
89system_time_nsecs()
90{
91	return sSystemTimeNsecs();
92}
93
94