1 // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
2 /*
3  * vdso_clock_getres.c: Sample code to test clock_getres.
4  * Copyright (c) 2019 Arm Ltd.
5  *
6  * Compile with:
7  * gcc -std=gnu99 vdso_clock_getres.c
8  *
9  * Tested on ARM, ARM64, MIPS32, x86 (32-bit and 64-bit),
10  * Power (32-bit and 64-bit), S390x (32-bit and 64-bit).
11  * Might work on other architectures.
12  */
13 
14 #define _GNU_SOURCE
15 #include <elf.h>
16 #include <fcntl.h>
17 #include <stdint.h>
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <time.h>
21 #include <sys/auxv.h>
22 #include <sys/mman.h>
23 #include <sys/time.h>
24 #include <unistd.h>
25 #include <sys/syscall.h>
26 
27 #include "../kselftest.h"
28 
syscall_clock_getres(clockid_t _clkid,struct timespec * _ts)29 static long syscall_clock_getres(clockid_t _clkid, struct timespec *_ts)
30 {
31 	long ret;
32 
33 	ret = syscall(SYS_clock_getres, _clkid, _ts);
34 
35 	return ret;
36 }
37 
38 const char *vdso_clock_name[12] = {
39 	"CLOCK_REALTIME",
40 	"CLOCK_MONOTONIC",
41 	"CLOCK_PROCESS_CPUTIME_ID",
42 	"CLOCK_THREAD_CPUTIME_ID",
43 	"CLOCK_MONOTONIC_RAW",
44 	"CLOCK_REALTIME_COARSE",
45 	"CLOCK_MONOTONIC_COARSE",
46 	"CLOCK_BOOTTIME",
47 	"CLOCK_REALTIME_ALARM",
48 	"CLOCK_BOOTTIME_ALARM",
49 	"CLOCK_SGI_CYCLE",
50 	"CLOCK_TAI",
51 };
52 
53 /*
54  * This function calls clock_getres in vdso and by system call
55  * with different values for clock_id.
56  *
57  * Example of output:
58  *
59  * clock_id: CLOCK_REALTIME [PASS]
60  * clock_id: CLOCK_BOOTTIME [PASS]
61  * clock_id: CLOCK_TAI [PASS]
62  * clock_id: CLOCK_REALTIME_COARSE [PASS]
63  * clock_id: CLOCK_MONOTONIC [PASS]
64  * clock_id: CLOCK_MONOTONIC_RAW [PASS]
65  * clock_id: CLOCK_MONOTONIC_COARSE [PASS]
66  */
vdso_test_clock(unsigned int clock_id)67 static inline int vdso_test_clock(unsigned int clock_id)
68 {
69 	struct timespec x, y;
70 
71 	printf("clock_id: %s", vdso_clock_name[clock_id]);
72 	clock_getres(clock_id, &x);
73 	syscall_clock_getres(clock_id, &y);
74 
75 	if ((x.tv_sec != y.tv_sec) || (x.tv_nsec != y.tv_nsec)) {
76 		printf(" [FAIL]\n");
77 		return KSFT_FAIL;
78 	}
79 
80 	printf(" [PASS]\n");
81 	return KSFT_PASS;
82 }
83 
main(int argc,char ** argv)84 int main(int argc, char **argv)
85 {
86 	int ret = 0;
87 
88 #if _POSIX_TIMERS > 0
89 
90 #ifdef CLOCK_REALTIME
91 	ret += vdso_test_clock(CLOCK_REALTIME);
92 #endif
93 
94 #ifdef CLOCK_BOOTTIME
95 	ret += vdso_test_clock(CLOCK_BOOTTIME);
96 #endif
97 
98 #ifdef CLOCK_TAI
99 	ret += vdso_test_clock(CLOCK_TAI);
100 #endif
101 
102 #ifdef CLOCK_REALTIME_COARSE
103 	ret += vdso_test_clock(CLOCK_REALTIME_COARSE);
104 #endif
105 
106 #ifdef CLOCK_MONOTONIC
107 	ret += vdso_test_clock(CLOCK_MONOTONIC);
108 #endif
109 
110 #ifdef CLOCK_MONOTONIC_RAW
111 	ret += vdso_test_clock(CLOCK_MONOTONIC_RAW);
112 #endif
113 
114 #ifdef CLOCK_MONOTONIC_COARSE
115 	ret += vdso_test_clock(CLOCK_MONOTONIC_COARSE);
116 #endif
117 
118 #endif
119 	if (ret > 0)
120 		return KSFT_FAIL;
121 
122 	return KSFT_PASS;
123 }
124