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 <err.h>
17 #include <fcntl.h>
18 #include <stdint.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <time.h>
22 #include <sys/auxv.h>
23 #include <sys/mman.h>
24 #include <sys/time.h>
25 #include <unistd.h>
26 #include <sys/syscall.h>
27 
28 #include "../kselftest.h"
29 
30 static long syscall_clock_getres(clockid_t _clkid, struct timespec *_ts)
31 {
32 	long ret;
33 
34 	ret = syscall(SYS_clock_getres, _clkid, _ts);
35 
36 	return ret;
37 }
38 
39 const char *vdso_clock_name[12] = {
40 	"CLOCK_REALTIME",
41 	"CLOCK_MONOTONIC",
42 	"CLOCK_PROCESS_CPUTIME_ID",
43 	"CLOCK_THREAD_CPUTIME_ID",
44 	"CLOCK_MONOTONIC_RAW",
45 	"CLOCK_REALTIME_COARSE",
46 	"CLOCK_MONOTONIC_COARSE",
47 	"CLOCK_BOOTTIME",
48 	"CLOCK_REALTIME_ALARM",
49 	"CLOCK_BOOTTIME_ALARM",
50 	"CLOCK_SGI_CYCLE",
51 	"CLOCK_TAI",
52 };
53 
54 /*
55  * This function calls clock_getres in vdso and by system call
56  * with different values for clock_id.
57  *
58  * Example of output:
59  *
60  * clock_id: CLOCK_REALTIME [PASS]
61  * clock_id: CLOCK_BOOTTIME [PASS]
62  * clock_id: CLOCK_TAI [PASS]
63  * clock_id: CLOCK_REALTIME_COARSE [PASS]
64  * clock_id: CLOCK_MONOTONIC [PASS]
65  * clock_id: CLOCK_MONOTONIC_RAW [PASS]
66  * clock_id: CLOCK_MONOTONIC_COARSE [PASS]
67  */
68 static inline int vdso_test_clock(unsigned int clock_id)
69 {
70 	struct timespec x, y;
71 
72 	printf("clock_id: %s", vdso_clock_name[clock_id]);
73 	clock_getres(clock_id, &x);
74 	syscall_clock_getres(clock_id, &y);
75 
76 	if ((x.tv_sec != y.tv_sec) || (x.tv_nsec != y.tv_nsec)) {
77 		printf(" [FAIL]\n");
78 		return KSFT_FAIL;
79 	}
80 
81 	printf(" [PASS]\n");
82 	return KSFT_PASS;
83 }
84 
85 int main(int argc, char **argv)
86 {
87 	int ret = 0;
88 
89 #if _POSIX_TIMERS > 0
90 
91 #ifdef CLOCK_REALTIME
92 	ret += vdso_test_clock(CLOCK_REALTIME);
93 #endif
94 
95 #ifdef CLOCK_BOOTTIME
96 	ret += vdso_test_clock(CLOCK_BOOTTIME);
97 #endif
98 
99 #ifdef CLOCK_TAI
100 	ret += vdso_test_clock(CLOCK_TAI);
101 #endif
102 
103 #ifdef CLOCK_REALTIME_COARSE
104 	ret += vdso_test_clock(CLOCK_REALTIME_COARSE);
105 #endif
106 
107 #ifdef CLOCK_MONOTONIC
108 	ret += vdso_test_clock(CLOCK_MONOTONIC);
109 #endif
110 
111 #ifdef CLOCK_MONOTONIC_RAW
112 	ret += vdso_test_clock(CLOCK_MONOTONIC_RAW);
113 #endif
114 
115 #ifdef CLOCK_MONOTONIC_COARSE
116 	ret += vdso_test_clock(CLOCK_MONOTONIC_COARSE);
117 #endif
118 
119 #endif
120 	if (ret > 0)
121 		return KSFT_FAIL;
122 
123 	return KSFT_PASS;
124 }
125