1693f5ca0SVincenzo Frascino // SPDX-License-Identifier: GPL-2.0
2693f5ca0SVincenzo Frascino /*
3693f5ca0SVincenzo Frascino  * vdso_full_test.c: Sample code to test all the timers.
4693f5ca0SVincenzo Frascino  * Copyright (c) 2019 Arm Ltd.
5693f5ca0SVincenzo Frascino  *
6693f5ca0SVincenzo Frascino  * Compile with:
7693f5ca0SVincenzo Frascino  * gcc -std=gnu99 vdso_full_test.c parse_vdso.c
8693f5ca0SVincenzo Frascino  *
9693f5ca0SVincenzo Frascino  */
10693f5ca0SVincenzo Frascino 
11693f5ca0SVincenzo Frascino #include <stdint.h>
12693f5ca0SVincenzo Frascino #include <elf.h>
13693f5ca0SVincenzo Frascino #include <stdio.h>
14693f5ca0SVincenzo Frascino #include <time.h>
15693f5ca0SVincenzo Frascino #include <sys/auxv.h>
16693f5ca0SVincenzo Frascino #include <sys/time.h>
17693f5ca0SVincenzo Frascino #define _GNU_SOURCE
18693f5ca0SVincenzo Frascino #include <unistd.h>
19693f5ca0SVincenzo Frascino #include <sys/syscall.h>
20693f5ca0SVincenzo Frascino 
21693f5ca0SVincenzo Frascino #include "../kselftest.h"
22693f5ca0SVincenzo Frascino #include "vdso_config.h"
23693f5ca0SVincenzo Frascino 
24693f5ca0SVincenzo Frascino extern void *vdso_sym(const char *version, const char *name);
25693f5ca0SVincenzo Frascino extern void vdso_init_from_sysinfo_ehdr(uintptr_t base);
26693f5ca0SVincenzo Frascino extern void vdso_init_from_auxv(void *auxv);
27693f5ca0SVincenzo Frascino 
28693f5ca0SVincenzo Frascino static const char *version;
29693f5ca0SVincenzo Frascino static const char **name;
30693f5ca0SVincenzo Frascino 
31693f5ca0SVincenzo Frascino typedef long (*vdso_gettimeofday_t)(struct timeval *tv, struct timezone *tz);
32693f5ca0SVincenzo Frascino typedef long (*vdso_clock_gettime_t)(clockid_t clk_id, struct timespec *ts);
33693f5ca0SVincenzo Frascino typedef long (*vdso_clock_getres_t)(clockid_t clk_id, struct timespec *ts);
34693f5ca0SVincenzo Frascino typedef time_t (*vdso_time_t)(time_t *t);
35693f5ca0SVincenzo Frascino 
36*46756cc8SVincenzo Frascino #define VDSO_TEST_PASS_MSG()	"\n%s(): PASS\n", __func__
37*46756cc8SVincenzo Frascino #define VDSO_TEST_FAIL_MSG(x)	"\n%s(): %s FAIL\n", __func__, x
38*46756cc8SVincenzo Frascino #define VDSO_TEST_SKIP_MSG(x)	"\n%s(): SKIP: Could not find %s\n", __func__, x
39*46756cc8SVincenzo Frascino 
vdso_test_gettimeofday(void)40*46756cc8SVincenzo Frascino static void vdso_test_gettimeofday(void)
41693f5ca0SVincenzo Frascino {
42693f5ca0SVincenzo Frascino 	/* Find gettimeofday. */
43693f5ca0SVincenzo Frascino 	vdso_gettimeofday_t vdso_gettimeofday =
44693f5ca0SVincenzo Frascino 		(vdso_gettimeofday_t)vdso_sym(version, name[0]);
45693f5ca0SVincenzo Frascino 
46693f5ca0SVincenzo Frascino 	if (!vdso_gettimeofday) {
47*46756cc8SVincenzo Frascino 		ksft_test_result_skip(VDSO_TEST_SKIP_MSG(name[0]));
48*46756cc8SVincenzo Frascino 		return;
49693f5ca0SVincenzo Frascino 	}
50693f5ca0SVincenzo Frascino 
51693f5ca0SVincenzo Frascino 	struct timeval tv;
52693f5ca0SVincenzo Frascino 	long ret = vdso_gettimeofday(&tv, 0);
53693f5ca0SVincenzo Frascino 
54693f5ca0SVincenzo Frascino 	if (ret == 0) {
55*46756cc8SVincenzo Frascino 		ksft_print_msg("The time is %lld.%06lld\n",
56693f5ca0SVincenzo Frascino 			       (long long)tv.tv_sec, (long long)tv.tv_usec);
57*46756cc8SVincenzo Frascino 		ksft_test_result_pass(VDSO_TEST_PASS_MSG());
58693f5ca0SVincenzo Frascino 	} else {
59*46756cc8SVincenzo Frascino 		ksft_test_result_fail(VDSO_TEST_FAIL_MSG(name[0]));
60*46756cc8SVincenzo Frascino 	}
61693f5ca0SVincenzo Frascino }
62693f5ca0SVincenzo Frascino 
vdso_test_clock_gettime(clockid_t clk_id)63*46756cc8SVincenzo Frascino static void vdso_test_clock_gettime(clockid_t clk_id)
64693f5ca0SVincenzo Frascino {
65693f5ca0SVincenzo Frascino 	/* Find clock_gettime. */
66693f5ca0SVincenzo Frascino 	vdso_clock_gettime_t vdso_clock_gettime =
67693f5ca0SVincenzo Frascino 		(vdso_clock_gettime_t)vdso_sym(version, name[1]);
68693f5ca0SVincenzo Frascino 
69693f5ca0SVincenzo Frascino 	if (!vdso_clock_gettime) {
70*46756cc8SVincenzo Frascino 		ksft_test_result_skip(VDSO_TEST_SKIP_MSG(name[1]));
71*46756cc8SVincenzo Frascino 		return;
72693f5ca0SVincenzo Frascino 	}
73693f5ca0SVincenzo Frascino 
74693f5ca0SVincenzo Frascino 	struct timespec ts;
75693f5ca0SVincenzo Frascino 	long ret = vdso_clock_gettime(clk_id, &ts);
76693f5ca0SVincenzo Frascino 
77693f5ca0SVincenzo Frascino 	if (ret == 0) {
78*46756cc8SVincenzo Frascino 		ksft_print_msg("The time is %lld.%06lld\n",
79693f5ca0SVincenzo Frascino 			       (long long)ts.tv_sec, (long long)ts.tv_nsec);
80*46756cc8SVincenzo Frascino 		ksft_test_result_pass(VDSO_TEST_PASS_MSG());
81693f5ca0SVincenzo Frascino 	} else {
82*46756cc8SVincenzo Frascino 		ksft_test_result_fail(VDSO_TEST_FAIL_MSG(name[1]));
83*46756cc8SVincenzo Frascino 	}
84693f5ca0SVincenzo Frascino }
85693f5ca0SVincenzo Frascino 
vdso_test_time(void)86*46756cc8SVincenzo Frascino static void vdso_test_time(void)
87693f5ca0SVincenzo Frascino {
88693f5ca0SVincenzo Frascino 	/* Find time. */
89693f5ca0SVincenzo Frascino 	vdso_time_t vdso_time =
90693f5ca0SVincenzo Frascino 		(vdso_time_t)vdso_sym(version, name[2]);
91693f5ca0SVincenzo Frascino 
92693f5ca0SVincenzo Frascino 	if (!vdso_time) {
93*46756cc8SVincenzo Frascino 		ksft_test_result_skip(VDSO_TEST_SKIP_MSG(name[2]));
94*46756cc8SVincenzo Frascino 		return;
95693f5ca0SVincenzo Frascino 	}
96693f5ca0SVincenzo Frascino 
97693f5ca0SVincenzo Frascino 	long ret = vdso_time(NULL);
98693f5ca0SVincenzo Frascino 
99693f5ca0SVincenzo Frascino 	if (ret > 0) {
100*46756cc8SVincenzo Frascino 		ksft_print_msg("The time in hours since January 1, 1970 is %lld\n",
101693f5ca0SVincenzo Frascino 				(long long)(ret / 3600));
102*46756cc8SVincenzo Frascino 		ksft_test_result_pass(VDSO_TEST_PASS_MSG());
103693f5ca0SVincenzo Frascino 	} else {
104*46756cc8SVincenzo Frascino 		ksft_test_result_fail(VDSO_TEST_FAIL_MSG(name[2]));
105*46756cc8SVincenzo Frascino 	}
106693f5ca0SVincenzo Frascino }
107693f5ca0SVincenzo Frascino 
vdso_test_clock_getres(clockid_t clk_id)108*46756cc8SVincenzo Frascino static void vdso_test_clock_getres(clockid_t clk_id)
109693f5ca0SVincenzo Frascino {
110*46756cc8SVincenzo Frascino 	int clock_getres_fail = 0;
111*46756cc8SVincenzo Frascino 
112693f5ca0SVincenzo Frascino 	/* Find clock_getres. */
113693f5ca0SVincenzo Frascino 	vdso_clock_getres_t vdso_clock_getres =
114693f5ca0SVincenzo Frascino 		(vdso_clock_getres_t)vdso_sym(version, name[3]);
115693f5ca0SVincenzo Frascino 
116693f5ca0SVincenzo Frascino 	if (!vdso_clock_getres) {
117*46756cc8SVincenzo Frascino 		ksft_test_result_skip(VDSO_TEST_SKIP_MSG(name[3]));
118*46756cc8SVincenzo Frascino 		return;
119693f5ca0SVincenzo Frascino 	}
120693f5ca0SVincenzo Frascino 
121693f5ca0SVincenzo Frascino 	struct timespec ts, sys_ts;
122693f5ca0SVincenzo Frascino 	long ret = vdso_clock_getres(clk_id, &ts);
123693f5ca0SVincenzo Frascino 
124693f5ca0SVincenzo Frascino 	if (ret == 0) {
125*46756cc8SVincenzo Frascino 		ksft_print_msg("The vdso resolution is %lld %lld\n",
126693f5ca0SVincenzo Frascino 			       (long long)ts.tv_sec, (long long)ts.tv_nsec);
127693f5ca0SVincenzo Frascino 	} else {
128*46756cc8SVincenzo Frascino 		clock_getres_fail++;
129693f5ca0SVincenzo Frascino 	}
130693f5ca0SVincenzo Frascino 
131693f5ca0SVincenzo Frascino 	ret = syscall(SYS_clock_getres, clk_id, &sys_ts);
132693f5ca0SVincenzo Frascino 
133*46756cc8SVincenzo Frascino 	ksft_print_msg("The syscall resolution is %lld %lld\n",
134*46756cc8SVincenzo Frascino 			(long long)sys_ts.tv_sec, (long long)sys_ts.tv_nsec);
135693f5ca0SVincenzo Frascino 
136*46756cc8SVincenzo Frascino 	if ((sys_ts.tv_sec != ts.tv_sec) || (sys_ts.tv_nsec != ts.tv_nsec))
137*46756cc8SVincenzo Frascino 		clock_getres_fail++;
138*46756cc8SVincenzo Frascino 
139*46756cc8SVincenzo Frascino 	if (clock_getres_fail > 0) {
140*46756cc8SVincenzo Frascino 		ksft_test_result_fail(VDSO_TEST_FAIL_MSG(name[3]));
141*46756cc8SVincenzo Frascino 	} else {
142*46756cc8SVincenzo Frascino 		ksft_test_result_pass(VDSO_TEST_PASS_MSG());
143*46756cc8SVincenzo Frascino 	}
144693f5ca0SVincenzo Frascino }
145693f5ca0SVincenzo Frascino 
146693f5ca0SVincenzo Frascino const char *vdso_clock_name[12] = {
147693f5ca0SVincenzo Frascino 	"CLOCK_REALTIME",
148693f5ca0SVincenzo Frascino 	"CLOCK_MONOTONIC",
149693f5ca0SVincenzo Frascino 	"CLOCK_PROCESS_CPUTIME_ID",
150693f5ca0SVincenzo Frascino 	"CLOCK_THREAD_CPUTIME_ID",
151693f5ca0SVincenzo Frascino 	"CLOCK_MONOTONIC_RAW",
152693f5ca0SVincenzo Frascino 	"CLOCK_REALTIME_COARSE",
153693f5ca0SVincenzo Frascino 	"CLOCK_MONOTONIC_COARSE",
154693f5ca0SVincenzo Frascino 	"CLOCK_BOOTTIME",
155693f5ca0SVincenzo Frascino 	"CLOCK_REALTIME_ALARM",
156693f5ca0SVincenzo Frascino 	"CLOCK_BOOTTIME_ALARM",
157693f5ca0SVincenzo Frascino 	"CLOCK_SGI_CYCLE",
158693f5ca0SVincenzo Frascino 	"CLOCK_TAI",
159693f5ca0SVincenzo Frascino };
160693f5ca0SVincenzo Frascino 
161693f5ca0SVincenzo Frascino /*
162693f5ca0SVincenzo Frascino  * This function calls vdso_test_clock_gettime and vdso_test_clock_getres
163693f5ca0SVincenzo Frascino  * with different values for clock_id.
164693f5ca0SVincenzo Frascino  */
vdso_test_clock(clockid_t clock_id)165*46756cc8SVincenzo Frascino static inline void vdso_test_clock(clockid_t clock_id)
166693f5ca0SVincenzo Frascino {
167*46756cc8SVincenzo Frascino 	ksft_print_msg("\nclock_id: %s\n", vdso_clock_name[clock_id]);
168693f5ca0SVincenzo Frascino 
169*46756cc8SVincenzo Frascino 	vdso_test_clock_gettime(clock_id);
170693f5ca0SVincenzo Frascino 
171*46756cc8SVincenzo Frascino 	vdso_test_clock_getres(clock_id);
172693f5ca0SVincenzo Frascino }
173693f5ca0SVincenzo Frascino 
174*46756cc8SVincenzo Frascino #define VDSO_TEST_PLAN	16
175*46756cc8SVincenzo Frascino 
main(int argc,char ** argv)176693f5ca0SVincenzo Frascino int main(int argc, char **argv)
177693f5ca0SVincenzo Frascino {
178693f5ca0SVincenzo Frascino 	unsigned long sysinfo_ehdr = getauxval(AT_SYSINFO_EHDR);
179*46756cc8SVincenzo Frascino 
180*46756cc8SVincenzo Frascino 	ksft_print_header();
181*46756cc8SVincenzo Frascino 	ksft_set_plan(VDSO_TEST_PLAN);
182693f5ca0SVincenzo Frascino 
183693f5ca0SVincenzo Frascino 	if (!sysinfo_ehdr) {
184693f5ca0SVincenzo Frascino 		printf("AT_SYSINFO_EHDR is not present!\n");
185693f5ca0SVincenzo Frascino 		return KSFT_SKIP;
186693f5ca0SVincenzo Frascino 	}
187693f5ca0SVincenzo Frascino 
188693f5ca0SVincenzo Frascino 	version = versions[VDSO_VERSION];
189693f5ca0SVincenzo Frascino 	name = (const char **)&names[VDSO_NAMES];
190693f5ca0SVincenzo Frascino 
191693f5ca0SVincenzo Frascino 	printf("[vDSO kselftest] VDSO_VERSION: %s\n", version);
192693f5ca0SVincenzo Frascino 
193693f5ca0SVincenzo Frascino 	vdso_init_from_sysinfo_ehdr(getauxval(AT_SYSINFO_EHDR));
194693f5ca0SVincenzo Frascino 
195*46756cc8SVincenzo Frascino 	vdso_test_gettimeofday();
196693f5ca0SVincenzo Frascino 
197693f5ca0SVincenzo Frascino #if _POSIX_TIMERS > 0
198693f5ca0SVincenzo Frascino 
199693f5ca0SVincenzo Frascino #ifdef CLOCK_REALTIME
200*46756cc8SVincenzo Frascino 	vdso_test_clock(CLOCK_REALTIME);
201693f5ca0SVincenzo Frascino #endif
202693f5ca0SVincenzo Frascino 
203693f5ca0SVincenzo Frascino #ifdef CLOCK_BOOTTIME
204*46756cc8SVincenzo Frascino 	vdso_test_clock(CLOCK_BOOTTIME);
205693f5ca0SVincenzo Frascino #endif
206693f5ca0SVincenzo Frascino 
207693f5ca0SVincenzo Frascino #ifdef CLOCK_TAI
208*46756cc8SVincenzo Frascino 	vdso_test_clock(CLOCK_TAI);
209693f5ca0SVincenzo Frascino #endif
210693f5ca0SVincenzo Frascino 
211693f5ca0SVincenzo Frascino #ifdef CLOCK_REALTIME_COARSE
212*46756cc8SVincenzo Frascino 	vdso_test_clock(CLOCK_REALTIME_COARSE);
213693f5ca0SVincenzo Frascino #endif
214693f5ca0SVincenzo Frascino 
215693f5ca0SVincenzo Frascino #ifdef CLOCK_MONOTONIC
216*46756cc8SVincenzo Frascino 	vdso_test_clock(CLOCK_MONOTONIC);
217693f5ca0SVincenzo Frascino #endif
218693f5ca0SVincenzo Frascino 
219693f5ca0SVincenzo Frascino #ifdef CLOCK_MONOTONIC_RAW
220*46756cc8SVincenzo Frascino 	vdso_test_clock(CLOCK_MONOTONIC_RAW);
221693f5ca0SVincenzo Frascino #endif
222693f5ca0SVincenzo Frascino 
223693f5ca0SVincenzo Frascino #ifdef CLOCK_MONOTONIC_COARSE
224*46756cc8SVincenzo Frascino 	vdso_test_clock(CLOCK_MONOTONIC_COARSE);
225693f5ca0SVincenzo Frascino #endif
226693f5ca0SVincenzo Frascino 
227693f5ca0SVincenzo Frascino #endif
228693f5ca0SVincenzo Frascino 
229*46756cc8SVincenzo Frascino 	vdso_test_time();
230693f5ca0SVincenzo Frascino 
231*46756cc8SVincenzo Frascino 	ksft_print_cnts();
232*46756cc8SVincenzo Frascino 	return ksft_get_fail_cnt() == 0 ? KSFT_PASS : KSFT_FAIL;
233693f5ca0SVincenzo Frascino }
234