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: name[0]);
56
57 if (!vdso_gettimeofday) {
58 ksft_print_msg(msg: "Couldn't find %s\n", name[0]);
59 ksft_test_result_skip(msg: "%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(msg: "The time is %lld.%06lld\n",
68 (long long)tv.tv_sec, (long long)tv.tv_usec);
69 ksft_test_result_pass(msg: "%s\n", name[0]);
70 } else {
71 ksft_test_result_fail(msg: "%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: name[1]);
80
81 if (!vdso_clock_gettime) {
82 ksft_print_msg(msg: "Couldn't find %s\n", name[1]);
83 ksft_test_result_skip(msg: "%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(msg: "The time is %lld.%06lld\n",
93 (long long)ts.tv_sec, (long long)ts.tv_nsec);
94 ksft_test_result_pass(msg: "%s %s\n", name[1],
95 vdso_clock_name[clk_id]);
96 } else {
97 ksft_test_result_fail(msg: "%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(msg: "Couldn't find %s\n", name[2]);
110 ksft_test_result_skip(msg: "%s\n", name[2]);
111 return;
112 }
113
114 long ret = vdso_time(NULL);
115
116 if (ret > 0) {
117 ksft_print_msg(msg: "The time in hours since January 1, 1970 is %lld\n",
118 (long long)(ret / 3600));
119 ksft_test_result_pass(msg: "%s\n", name[2]);
120 } else {
121 ksft_test_result_fail(msg: "%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: name[3]);
132
133 if (!vdso_clock_getres) {
134 ksft_print_msg(msg: "Couldn't find %s\n", name[3]);
135 ksft_test_result_skip(msg: "%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(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(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(msg: "%s %s\n", name[3],
160 vdso_clock_name[clk_id]);
161 } else {
162 ksft_test_result_pass(msg: "%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(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(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(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

source code of linux/tools/testing/selftests/vDSO/vdso_test_abi.c