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