xref: /linux/tools/testing/selftests/vDSO/vdso_test_abi.c (revision e63e1354125f923f1f5a393dd63c074427382e7e)
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 
3660e76e7aSMark Brown const char *vdso_clock_name[12] = {
3760e76e7aSMark Brown 	"CLOCK_REALTIME",
3860e76e7aSMark Brown 	"CLOCK_MONOTONIC",
3960e76e7aSMark Brown 	"CLOCK_PROCESS_CPUTIME_ID",
4060e76e7aSMark Brown 	"CLOCK_THREAD_CPUTIME_ID",
4160e76e7aSMark Brown 	"CLOCK_MONOTONIC_RAW",
4260e76e7aSMark Brown 	"CLOCK_REALTIME_COARSE",
4360e76e7aSMark Brown 	"CLOCK_MONOTONIC_COARSE",
4460e76e7aSMark Brown 	"CLOCK_BOOTTIME",
4560e76e7aSMark Brown 	"CLOCK_REALTIME_ALARM",
4660e76e7aSMark Brown 	"CLOCK_BOOTTIME_ALARM",
4760e76e7aSMark Brown 	"CLOCK_SGI_CYCLE",
4860e76e7aSMark Brown 	"CLOCK_TAI",
4960e76e7aSMark Brown };
50ec049891SVincenzo Frascino 
51ec049891SVincenzo Frascino static void vdso_test_gettimeofday(void)
52693f5ca0SVincenzo Frascino {
53693f5ca0SVincenzo Frascino 	/* Find gettimeofday. */
54693f5ca0SVincenzo Frascino 	vdso_gettimeofday_t vdso_gettimeofday =
55693f5ca0SVincenzo Frascino 		(vdso_gettimeofday_t)vdso_sym(version, name[0]);
56693f5ca0SVincenzo Frascino 
57693f5ca0SVincenzo Frascino 	if (!vdso_gettimeofday) {
5860e76e7aSMark Brown 		ksft_print_msg("Couldn't find %s\n", name[0]);
5960e76e7aSMark Brown 		ksft_test_result_skip("%s\n", name[0]);
60ec049891SVincenzo Frascino 		return;
61693f5ca0SVincenzo Frascino 	}
62693f5ca0SVincenzo Frascino 
63693f5ca0SVincenzo Frascino 	struct timeval tv;
64693f5ca0SVincenzo Frascino 	long ret = vdso_gettimeofday(&tv, 0);
65693f5ca0SVincenzo Frascino 
66693f5ca0SVincenzo Frascino 	if (ret == 0) {
67ec049891SVincenzo Frascino 		ksft_print_msg("The time is %lld.%06lld\n",
68693f5ca0SVincenzo Frascino 			       (long long)tv.tv_sec, (long long)tv.tv_usec);
6960e76e7aSMark Brown 		ksft_test_result_pass("%s\n", name[0]);
70693f5ca0SVincenzo Frascino 	} else {
7160e76e7aSMark Brown 		ksft_test_result_fail("%s\n", name[0]);
72ec049891SVincenzo Frascino 	}
73693f5ca0SVincenzo Frascino }
74693f5ca0SVincenzo Frascino 
75ec049891SVincenzo Frascino static void vdso_test_clock_gettime(clockid_t clk_id)
76693f5ca0SVincenzo Frascino {
77693f5ca0SVincenzo Frascino 	/* Find clock_gettime. */
78693f5ca0SVincenzo Frascino 	vdso_clock_gettime_t vdso_clock_gettime =
79693f5ca0SVincenzo Frascino 		(vdso_clock_gettime_t)vdso_sym(version, name[1]);
80693f5ca0SVincenzo Frascino 
81693f5ca0SVincenzo Frascino 	if (!vdso_clock_gettime) {
8260e76e7aSMark Brown 		ksft_print_msg("Couldn't find %s\n", name[1]);
8360e76e7aSMark Brown 		ksft_test_result_skip("%s %s\n", name[1],
8460e76e7aSMark Brown 				      vdso_clock_name[clk_id]);
85ec049891SVincenzo Frascino 		return;
86693f5ca0SVincenzo Frascino 	}
87693f5ca0SVincenzo Frascino 
88693f5ca0SVincenzo Frascino 	struct timespec ts;
89693f5ca0SVincenzo Frascino 	long ret = vdso_clock_gettime(clk_id, &ts);
90693f5ca0SVincenzo Frascino 
91693f5ca0SVincenzo Frascino 	if (ret == 0) {
92ec049891SVincenzo Frascino 		ksft_print_msg("The time is %lld.%06lld\n",
93693f5ca0SVincenzo Frascino 			       (long long)ts.tv_sec, (long long)ts.tv_nsec);
9460e76e7aSMark Brown 		ksft_test_result_pass("%s %s\n", name[1],
9560e76e7aSMark Brown 				      vdso_clock_name[clk_id]);
96693f5ca0SVincenzo Frascino 	} else {
9760e76e7aSMark Brown 		ksft_test_result_fail("%s %s\n", name[1],
9860e76e7aSMark Brown 				      vdso_clock_name[clk_id]);
99ec049891SVincenzo Frascino 	}
100693f5ca0SVincenzo Frascino }
101693f5ca0SVincenzo Frascino 
102ec049891SVincenzo Frascino static void vdso_test_time(void)
103693f5ca0SVincenzo Frascino {
104693f5ca0SVincenzo Frascino 	/* Find time. */
105693f5ca0SVincenzo Frascino 	vdso_time_t vdso_time =
106693f5ca0SVincenzo Frascino 		(vdso_time_t)vdso_sym(version, name[2]);
107693f5ca0SVincenzo Frascino 
108693f5ca0SVincenzo Frascino 	if (!vdso_time) {
10960e76e7aSMark Brown 		ksft_print_msg("Couldn't find %s\n", name[2]);
11060e76e7aSMark Brown 		ksft_test_result_skip("%s\n", name[2]);
111ec049891SVincenzo Frascino 		return;
112693f5ca0SVincenzo Frascino 	}
113693f5ca0SVincenzo Frascino 
114693f5ca0SVincenzo Frascino 	long ret = vdso_time(NULL);
115693f5ca0SVincenzo Frascino 
116693f5ca0SVincenzo Frascino 	if (ret > 0) {
117ec049891SVincenzo Frascino 		ksft_print_msg("The time in hours since January 1, 1970 is %lld\n",
118693f5ca0SVincenzo Frascino 				(long long)(ret / 3600));
11960e76e7aSMark Brown 		ksft_test_result_pass("%s\n", name[2]);
120693f5ca0SVincenzo Frascino 	} else {
12160e76e7aSMark Brown 		ksft_test_result_fail("%s\n", name[2]);
122ec049891SVincenzo Frascino 	}
123693f5ca0SVincenzo Frascino }
124693f5ca0SVincenzo Frascino 
125ec049891SVincenzo Frascino static void vdso_test_clock_getres(clockid_t clk_id)
126693f5ca0SVincenzo Frascino {
127ec049891SVincenzo Frascino 	int clock_getres_fail = 0;
128ec049891SVincenzo Frascino 
129693f5ca0SVincenzo Frascino 	/* Find clock_getres. */
130693f5ca0SVincenzo Frascino 	vdso_clock_getres_t vdso_clock_getres =
131693f5ca0SVincenzo Frascino 		(vdso_clock_getres_t)vdso_sym(version, name[3]);
132693f5ca0SVincenzo Frascino 
133693f5ca0SVincenzo Frascino 	if (!vdso_clock_getres) {
13460e76e7aSMark Brown 		ksft_print_msg("Couldn't find %s\n", name[3]);
13560e76e7aSMark Brown 		ksft_test_result_skip("%s %s\n", name[3],
13660e76e7aSMark Brown 				      vdso_clock_name[clk_id]);
137ec049891SVincenzo Frascino 		return;
138693f5ca0SVincenzo Frascino 	}
139693f5ca0SVincenzo Frascino 
140693f5ca0SVincenzo Frascino 	struct timespec ts, sys_ts;
141693f5ca0SVincenzo Frascino 	long ret = vdso_clock_getres(clk_id, &ts);
142693f5ca0SVincenzo Frascino 
143693f5ca0SVincenzo Frascino 	if (ret == 0) {
144ec049891SVincenzo Frascino 		ksft_print_msg("The vdso resolution is %lld %lld\n",
145693f5ca0SVincenzo Frascino 			       (long long)ts.tv_sec, (long long)ts.tv_nsec);
146693f5ca0SVincenzo Frascino 	} else {
147ec049891SVincenzo Frascino 		clock_getres_fail++;
148693f5ca0SVincenzo Frascino 	}
149693f5ca0SVincenzo Frascino 
150693f5ca0SVincenzo Frascino 	ret = syscall(SYS_clock_getres, clk_id, &sys_ts);
151693f5ca0SVincenzo Frascino 
152ec049891SVincenzo Frascino 	ksft_print_msg("The syscall resolution is %lld %lld\n",
153ec049891SVincenzo Frascino 			(long long)sys_ts.tv_sec, (long long)sys_ts.tv_nsec);
154693f5ca0SVincenzo Frascino 
155ec049891SVincenzo Frascino 	if ((sys_ts.tv_sec != ts.tv_sec) || (sys_ts.tv_nsec != ts.tv_nsec))
156ec049891SVincenzo Frascino 		clock_getres_fail++;
157ec049891SVincenzo Frascino 
158ec049891SVincenzo Frascino 	if (clock_getres_fail > 0) {
15960e76e7aSMark Brown 		ksft_test_result_fail("%s %s\n", name[3],
16060e76e7aSMark Brown 				      vdso_clock_name[clk_id]);
161ec049891SVincenzo Frascino 	} else {
16260e76e7aSMark Brown 		ksft_test_result_pass("%s %s\n", name[3],
16360e76e7aSMark Brown 				      vdso_clock_name[clk_id]);
164ec049891SVincenzo Frascino 	}
165693f5ca0SVincenzo Frascino }
166693f5ca0SVincenzo Frascino 
167693f5ca0SVincenzo Frascino /*
168693f5ca0SVincenzo Frascino  * This function calls vdso_test_clock_gettime and vdso_test_clock_getres
169693f5ca0SVincenzo Frascino  * with different values for clock_id.
170693f5ca0SVincenzo Frascino  */
171ec049891SVincenzo Frascino static inline void vdso_test_clock(clockid_t clock_id)
172693f5ca0SVincenzo Frascino {
173*e63e1354SMark Brown 	ksft_print_msg("clock_id: %s\n", vdso_clock_name[clock_id]);
174693f5ca0SVincenzo Frascino 
175ec049891SVincenzo Frascino 	vdso_test_clock_gettime(clock_id);
176693f5ca0SVincenzo Frascino 
177ec049891SVincenzo Frascino 	vdso_test_clock_getres(clock_id);
178693f5ca0SVincenzo Frascino }
179693f5ca0SVincenzo Frascino 
180ec049891SVincenzo Frascino #define VDSO_TEST_PLAN	16
181ec049891SVincenzo Frascino 
182693f5ca0SVincenzo Frascino int main(int argc, char **argv)
183693f5ca0SVincenzo Frascino {
184693f5ca0SVincenzo Frascino 	unsigned long sysinfo_ehdr = getauxval(AT_SYSINFO_EHDR);
185ec049891SVincenzo Frascino 
186ec049891SVincenzo Frascino 	ksft_print_header();
187ec049891SVincenzo Frascino 	ksft_set_plan(VDSO_TEST_PLAN);
188693f5ca0SVincenzo Frascino 
189693f5ca0SVincenzo Frascino 	if (!sysinfo_ehdr) {
190693f5ca0SVincenzo Frascino 		printf("AT_SYSINFO_EHDR is not present!\n");
191693f5ca0SVincenzo Frascino 		return KSFT_SKIP;
192693f5ca0SVincenzo Frascino 	}
193693f5ca0SVincenzo Frascino 
194693f5ca0SVincenzo Frascino 	version = versions[VDSO_VERSION];
195693f5ca0SVincenzo Frascino 	name = (const char **)&names[VDSO_NAMES];
196693f5ca0SVincenzo Frascino 
197693f5ca0SVincenzo Frascino 	printf("[vDSO kselftest] VDSO_VERSION: %s\n", version);
198693f5ca0SVincenzo Frascino 
199693f5ca0SVincenzo Frascino 	vdso_init_from_sysinfo_ehdr(getauxval(AT_SYSINFO_EHDR));
200693f5ca0SVincenzo Frascino 
201ec049891SVincenzo Frascino 	vdso_test_gettimeofday();
202693f5ca0SVincenzo Frascino 
203693f5ca0SVincenzo Frascino #if _POSIX_TIMERS > 0
204693f5ca0SVincenzo Frascino 
205693f5ca0SVincenzo Frascino #ifdef CLOCK_REALTIME
206ec049891SVincenzo Frascino 	vdso_test_clock(CLOCK_REALTIME);
207693f5ca0SVincenzo Frascino #endif
208693f5ca0SVincenzo Frascino 
209693f5ca0SVincenzo Frascino #ifdef CLOCK_BOOTTIME
210ec049891SVincenzo Frascino 	vdso_test_clock(CLOCK_BOOTTIME);
211693f5ca0SVincenzo Frascino #endif
212693f5ca0SVincenzo Frascino 
213693f5ca0SVincenzo Frascino #ifdef CLOCK_TAI
214ec049891SVincenzo Frascino 	vdso_test_clock(CLOCK_TAI);
215693f5ca0SVincenzo Frascino #endif
216693f5ca0SVincenzo Frascino 
217693f5ca0SVincenzo Frascino #ifdef CLOCK_REALTIME_COARSE
218ec049891SVincenzo Frascino 	vdso_test_clock(CLOCK_REALTIME_COARSE);
219693f5ca0SVincenzo Frascino #endif
220693f5ca0SVincenzo Frascino 
221693f5ca0SVincenzo Frascino #ifdef CLOCK_MONOTONIC
222ec049891SVincenzo Frascino 	vdso_test_clock(CLOCK_MONOTONIC);
223693f5ca0SVincenzo Frascino #endif
224693f5ca0SVincenzo Frascino 
225693f5ca0SVincenzo Frascino #ifdef CLOCK_MONOTONIC_RAW
226ec049891SVincenzo Frascino 	vdso_test_clock(CLOCK_MONOTONIC_RAW);
227693f5ca0SVincenzo Frascino #endif
228693f5ca0SVincenzo Frascino 
229693f5ca0SVincenzo Frascino #ifdef CLOCK_MONOTONIC_COARSE
230ec049891SVincenzo Frascino 	vdso_test_clock(CLOCK_MONOTONIC_COARSE);
231693f5ca0SVincenzo Frascino #endif
232693f5ca0SVincenzo Frascino 
233693f5ca0SVincenzo Frascino #endif
234693f5ca0SVincenzo Frascino 
235ec049891SVincenzo Frascino 	vdso_test_time();
236693f5ca0SVincenzo Frascino 
237ec049891SVincenzo Frascino 	ksft_print_cnts();
238ec049891SVincenzo Frascino 	return ksft_get_fail_cnt() == 0 ? KSFT_PASS : KSFT_FAIL;
239693f5ca0SVincenzo Frascino }
240