1// SPDX-License-Identifier: GPL-2.0
2/*
3 * vdso_full_test.c: Sample code to test all the timers.
4 * Copyright (c) 2019 Arm Ltd.
5 *
6 * Compile with:
7 * gcc -std=gnu99 vdso_full_test.c parse_vdso.c
8 *
9 */
10
11#include <stdint.h>
12#include <elf.h>
13#include <stdio.h>
14#include <time.h>
15#include <sys/auxv.h>
16#include <sys/time.h>
17#define _GNU_SOURCE
18#include <unistd.h>
19#include <sys/syscall.h>
20
21#include "../kselftest.h"
22#include "vdso_config.h"
23
24extern void *vdso_sym(const char *version, const char *name);
25extern void vdso_init_from_sysinfo_ehdr(uintptr_t base);
26extern void vdso_init_from_auxv(void *auxv);
27
28static const char *version;
29static const char **name;
30
31typedef long (*vdso_gettimeofday_t)(struct timeval *tv, struct timezone *tz);
32typedef long (*vdso_clock_gettime_t)(clockid_t clk_id, struct timespec *ts);
33typedef long (*vdso_clock_getres_t)(clockid_t clk_id, struct timespec *ts);
34typedef time_t (*vdso_time_t)(time_t *t);
35
36const char *vdso_clock_name[12] = {
37	"CLOCK_REALTIME",
38	"CLOCK_MONOTONIC",
39	"CLOCK_PROCESS_CPUTIME_ID",
40	"CLOCK_THREAD_CPUTIME_ID",
41	"CLOCK_MONOTONIC_RAW",
42	"CLOCK_REALTIME_COARSE",
43	"CLOCK_MONOTONIC_COARSE",
44	"CLOCK_BOOTTIME",
45	"CLOCK_REALTIME_ALARM",
46	"CLOCK_BOOTTIME_ALARM",
47	"CLOCK_SGI_CYCLE",
48	"CLOCK_TAI",
49};
50
51static void vdso_test_gettimeofday(void)
52{
53	/* Find gettimeofday. */
54	vdso_gettimeofday_t vdso_gettimeofday =
55		(vdso_gettimeofday_t)vdso_sym(version, name[0]);
56
57	if (!vdso_gettimeofday) {
58		ksft_print_msg("Couldn't find %s\n", name[0]);
59		ksft_test_result_skip("%s\n", name[0]);
60		return;
61	}
62
63	struct timeval tv;
64	long ret = vdso_gettimeofday(&tv, 0);
65
66	if (ret == 0) {
67		ksft_print_msg("The time is %lld.%06lld\n",
68			       (long long)tv.tv_sec, (long long)tv.tv_usec);
69		ksft_test_result_pass("%s\n", name[0]);
70	} else {
71		ksft_test_result_fail("%s\n", name[0]);
72	}
73}
74
75static void vdso_test_clock_gettime(clockid_t clk_id)
76{
77	/* Find clock_gettime. */
78	vdso_clock_gettime_t vdso_clock_gettime =
79		(vdso_clock_gettime_t)vdso_sym(version, name[1]);
80
81	if (!vdso_clock_gettime) {
82		ksft_print_msg("Couldn't find %s\n", name[1]);
83		ksft_test_result_skip("%s %s\n", name[1],
84				      vdso_clock_name[clk_id]);
85		return;
86	}
87
88	struct timespec ts;
89	long ret = vdso_clock_gettime(clk_id, &ts);
90
91	if (ret == 0) {
92		ksft_print_msg("The time is %lld.%06lld\n",
93			       (long long)ts.tv_sec, (long long)ts.tv_nsec);
94		ksft_test_result_pass("%s %s\n", name[1],
95				      vdso_clock_name[clk_id]);
96	} else {
97		ksft_test_result_fail("%s %s\n", name[1],
98				      vdso_clock_name[clk_id]);
99	}
100}
101
102static void vdso_test_time(void)
103{
104	/* Find time. */
105	vdso_time_t vdso_time =
106		(vdso_time_t)vdso_sym(version, name[2]);
107
108	if (!vdso_time) {
109		ksft_print_msg("Couldn't find %s\n", name[2]);
110		ksft_test_result_skip("%s\n", name[2]);
111		return;
112	}
113
114	long ret = vdso_time(NULL);
115
116	if (ret > 0) {
117		ksft_print_msg("The time in hours since January 1, 1970 is %lld\n",
118				(long long)(ret / 3600));
119		ksft_test_result_pass("%s\n", name[2]);
120	} else {
121		ksft_test_result_fail("%s\n", name[2]);
122	}
123}
124
125static void vdso_test_clock_getres(clockid_t clk_id)
126{
127	int clock_getres_fail = 0;
128
129	/* Find clock_getres. */
130	vdso_clock_getres_t vdso_clock_getres =
131		(vdso_clock_getres_t)vdso_sym(version, name[3]);
132
133	if (!vdso_clock_getres) {
134		ksft_print_msg("Couldn't find %s\n", name[3]);
135		ksft_test_result_skip("%s %s\n", name[3],
136				      vdso_clock_name[clk_id]);
137		return;
138	}
139
140	struct timespec ts, sys_ts;
141	long ret = vdso_clock_getres(clk_id, &ts);
142
143	if (ret == 0) {
144		ksft_print_msg("The vdso resolution is %lld %lld\n",
145			       (long long)ts.tv_sec, (long long)ts.tv_nsec);
146	} else {
147		clock_getres_fail++;
148	}
149
150	ret = syscall(SYS_clock_getres, clk_id, &sys_ts);
151
152	ksft_print_msg("The syscall resolution is %lld %lld\n",
153			(long long)sys_ts.tv_sec, (long long)sys_ts.tv_nsec);
154
155	if ((sys_ts.tv_sec != ts.tv_sec) || (sys_ts.tv_nsec != ts.tv_nsec))
156		clock_getres_fail++;
157
158	if (clock_getres_fail > 0) {
159		ksft_test_result_fail("%s %s\n", name[3],
160				      vdso_clock_name[clk_id]);
161	} else {
162		ksft_test_result_pass("%s %s\n", name[3],
163				      vdso_clock_name[clk_id]);
164	}
165}
166
167/*
168 * This function calls vdso_test_clock_gettime and vdso_test_clock_getres
169 * with different values for clock_id.
170 */
171static inline void vdso_test_clock(clockid_t clock_id)
172{
173	ksft_print_msg("clock_id: %s\n", vdso_clock_name[clock_id]);
174
175	vdso_test_clock_gettime(clock_id);
176
177	vdso_test_clock_getres(clock_id);
178}
179
180#define VDSO_TEST_PLAN	16
181
182int main(int argc, char **argv)
183{
184	unsigned long sysinfo_ehdr = getauxval(AT_SYSINFO_EHDR);
185
186	ksft_print_header();
187	ksft_set_plan(VDSO_TEST_PLAN);
188
189	if (!sysinfo_ehdr) {
190		ksft_print_msg("AT_SYSINFO_EHDR is not present!\n");
191		return KSFT_SKIP;
192	}
193
194	version = versions[VDSO_VERSION];
195	name = (const char **)&names[VDSO_NAMES];
196
197	ksft_print_msg("[vDSO kselftest] VDSO_VERSION: %s\n", version);
198
199	vdso_init_from_sysinfo_ehdr(getauxval(AT_SYSINFO_EHDR));
200
201	vdso_test_gettimeofday();
202
203#if _POSIX_TIMERS > 0
204
205#ifdef CLOCK_REALTIME
206	vdso_test_clock(CLOCK_REALTIME);
207#endif
208
209#ifdef CLOCK_BOOTTIME
210	vdso_test_clock(CLOCK_BOOTTIME);
211#endif
212
213#ifdef CLOCK_TAI
214	vdso_test_clock(CLOCK_TAI);
215#endif
216
217#ifdef CLOCK_REALTIME_COARSE
218	vdso_test_clock(CLOCK_REALTIME_COARSE);
219#endif
220
221#ifdef CLOCK_MONOTONIC
222	vdso_test_clock(CLOCK_MONOTONIC);
223#endif
224
225#ifdef CLOCK_MONOTONIC_RAW
226	vdso_test_clock(CLOCK_MONOTONIC_RAW);
227#endif
228
229#ifdef CLOCK_MONOTONIC_COARSE
230	vdso_test_clock(CLOCK_MONOTONIC_COARSE);
231#endif
232
233#endif
234
235	vdso_test_time();
236
237	ksft_print_cnts();
238	return ksft_get_fail_cnt() == 0 ? KSFT_PASS : KSFT_FAIL;
239}
240