xref: /linux/tools/testing/selftests/vDSO/vdso_test_abi.c (revision ab27740f76654ed58dd32ac0ba0031c18a6dea3b)
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 
24 extern void *vdso_sym(const char *version, const char *name);
25 extern void vdso_init_from_sysinfo_ehdr(uintptr_t base);
26 extern void vdso_init_from_auxv(void *auxv);
27 
28 static const char *version;
29 static const char **name;
30 
31 typedef long (*vdso_gettimeofday_t)(struct timeval *tv, struct timezone *tz);
32 typedef long (*vdso_clock_gettime_t)(clockid_t clk_id, struct timespec *ts);
33 typedef long (*vdso_clock_getres_t)(clockid_t clk_id, struct timespec *ts);
34 typedef time_t (*vdso_time_t)(time_t *t);
35 
36 const 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 
51 static 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 
75 static 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 
102 static 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 
125 static 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  */
171 static 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 
182 int 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