Skip to content

Commit 693f5ca

Browse files
fvincenzoshuahkh
authored andcommitted
kselftest: Extend vDSO selftest
The current version of the multiarch vDSO selftest verifies only gettimeofday. Extend the vDSO selftest to the other library functions: - time - clock_getres - clock_gettime The extension has been used to verify the unified vdso library on the supported architectures. Cc: Shuah Khan <shuah@kernel.org> Signed-off-by: Vincenzo Frascino <vincenzo.frascino@arm.com> Acked-by: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Shuah Khan <skhan@linuxfoundation.org>
1 parent 4072341 commit 693f5ca

File tree

3 files changed

+336
-0
lines changed

3 files changed

+336
-0
lines changed

tools/testing/selftests/vDSO/Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ uname_M := $(shell uname -m 2>/dev/null || echo not)
55
ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/x86/ -e s/x86_64/x86/)
66

77
TEST_GEN_PROGS := $(OUTPUT)/vdso_test_gettimeofday $(OUTPUT)/vdso_test_getcpu
8+
TEST_GEN_PROGS += $(OUTPUT)/vdso_test_abi
89
ifeq ($(ARCH),x86)
910
TEST_GEN_PROGS += $(OUTPUT)/vdso_standalone_test_x86
1011
endif
@@ -18,6 +19,7 @@ endif
1819
all: $(TEST_GEN_PROGS)
1920
$(OUTPUT)/vdso_test_gettimeofday: parse_vdso.c vdso_test_gettimeofday.c
2021
$(OUTPUT)/vdso_test_getcpu: parse_vdso.c vdso_test_getcpu.c
22+
$(OUTPUT)/vdso_test_abi: parse_vdso.c vdso_test_abi.c
2123
$(OUTPUT)/vdso_standalone_test_x86: vdso_standalone_test_x86.c parse_vdso.c
2224
$(CC) $(CFLAGS) $(CFLAGS_vdso_standalone_test_x86) \
2325
vdso_standalone_test_x86.c parse_vdso.c \
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
/*
3+
* vdso_config.h: Configuration options for vDSO tests.
4+
* Copyright (c) 2019 Arm Ltd.
5+
*/
6+
#ifndef __VDSO_CONFIG_H__
7+
#define __VDSO_CONFIG_H__
8+
9+
/*
10+
* Each architecture exports its vDSO implementation with different names
11+
* and a different version from the others, so we need to handle it as a
12+
* special case.
13+
*/
14+
#if defined(__arm__)
15+
#define VDSO_VERSION 0
16+
#define VDSO_NAMES 1
17+
#define VDSO_32BIT 1
18+
#elif defined(__aarch64__)
19+
#define VDSO_VERSION 3
20+
#define VDSO_NAMES 0
21+
#elif defined(__powerpc__)
22+
#define VDSO_VERSION 1
23+
#define VDSO_NAMES 0
24+
#define VDSO_32BIT 1
25+
#elif defined(__powerpc64__)
26+
#define VDSO_VERSION 1
27+
#define VDSO_NAMES 0
28+
#elif defined (__s390__)
29+
#define VDSO_VERSION 2
30+
#define VDSO_NAMES 0
31+
#define VDSO_32BIT 1
32+
#elif defined (__s390X__)
33+
#define VDSO_VERSION 2
34+
#define VDSO_NAMES 0
35+
#elif defined(__mips__)
36+
#define VDSO_VERSION 0
37+
#define VDSO_NAMES 1
38+
#define VDSO_32BIT 1
39+
#elif defined(__sparc__)
40+
#define VDSO_VERSION 0
41+
#define VDSO_NAMES 1
42+
#define VDSO_32BIT 1
43+
#elif defined(__i386__)
44+
#define VDSO_VERSION 0
45+
#define VDSO_NAMES 1
46+
#define VDSO_32BIT 1
47+
#elif defined(__x86_64__)
48+
#define VDSO_VERSION 0
49+
#define VDSO_NAMES 1
50+
#elif defined(__riscv__)
51+
#define VDSO_VERSION 5
52+
#define VDSO_NAMES 1
53+
#define VDSO_32BIT 1
54+
#else /* nds32 */
55+
#define VDSO_VERSION 4
56+
#define VDSO_NAMES 1
57+
#define VDSO_32BIT 1
58+
#endif
59+
60+
static const char *versions[6] = {
61+
"LINUX_2.6",
62+
"LINUX_2.6.15",
63+
"LINUX_2.6.29",
64+
"LINUX_2.6.39",
65+
"LINUX_4",
66+
"LINUX_4.15",
67+
};
68+
69+
static const char *names[2][5] = {
70+
{
71+
"__kernel_gettimeofday",
72+
"__kernel_clock_gettime",
73+
"__kernel_time",
74+
"__kernel_clock_getres",
75+
#if defined(VDSO_32BIT)
76+
"__kernel_clock_gettime64",
77+
#endif
78+
},
79+
{
80+
"__vdso_gettimeofday",
81+
"__vdso_clock_gettime",
82+
"__vdso_time",
83+
"__vdso_clock_getres",
84+
#if defined(VDSO_32BIT)
85+
"__vdso_clock_gettime64",
86+
#endif
87+
},
88+
};
89+
90+
#endif /* __VDSO_CONFIG_H__ */
Lines changed: 244 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,244 @@
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+
static int vdso_test_gettimeofday(void)
37+
{
38+
/* Find gettimeofday. */
39+
vdso_gettimeofday_t vdso_gettimeofday =
40+
(vdso_gettimeofday_t)vdso_sym(version, name[0]);
41+
42+
if (!vdso_gettimeofday) {
43+
printf("Could not find %s\n", name[0]);
44+
return KSFT_SKIP;
45+
}
46+
47+
struct timeval tv;
48+
long ret = vdso_gettimeofday(&tv, 0);
49+
50+
if (ret == 0) {
51+
printf("The time is %lld.%06lld\n",
52+
(long long)tv.tv_sec, (long long)tv.tv_usec);
53+
} else {
54+
printf("%s failed\n", name[0]);
55+
return KSFT_FAIL;
56+
}
57+
58+
return KSFT_PASS;
59+
}
60+
61+
static int vdso_test_clock_gettime(clockid_t clk_id)
62+
{
63+
/* Find clock_gettime. */
64+
vdso_clock_gettime_t vdso_clock_gettime =
65+
(vdso_clock_gettime_t)vdso_sym(version, name[1]);
66+
67+
if (!vdso_clock_gettime) {
68+
printf("Could not find %s\n", name[1]);
69+
return KSFT_SKIP;
70+
}
71+
72+
struct timespec ts;
73+
long ret = vdso_clock_gettime(clk_id, &ts);
74+
75+
if (ret == 0) {
76+
printf("The time is %lld.%06lld\n",
77+
(long long)ts.tv_sec, (long long)ts.tv_nsec);
78+
} else {
79+
printf("%s failed\n", name[1]);
80+
return KSFT_FAIL;
81+
}
82+
83+
return KSFT_PASS;
84+
}
85+
86+
static int vdso_test_time(void)
87+
{
88+
/* Find time. */
89+
vdso_time_t vdso_time =
90+
(vdso_time_t)vdso_sym(version, name[2]);
91+
92+
if (!vdso_time) {
93+
printf("Could not find %s\n", name[2]);
94+
return KSFT_SKIP;
95+
}
96+
97+
long ret = vdso_time(NULL);
98+
99+
if (ret > 0) {
100+
printf("The time in hours since January 1, 1970 is %lld\n",
101+
(long long)(ret / 3600));
102+
} else {
103+
printf("%s failed\n", name[2]);
104+
return KSFT_FAIL;
105+
}
106+
107+
return KSFT_PASS;
108+
}
109+
110+
static int vdso_test_clock_getres(clockid_t clk_id)
111+
{
112+
/* Find clock_getres. */
113+
vdso_clock_getres_t vdso_clock_getres =
114+
(vdso_clock_getres_t)vdso_sym(version, name[3]);
115+
116+
if (!vdso_clock_getres) {
117+
printf("Could not find %s\n", name[3]);
118+
return KSFT_SKIP;
119+
}
120+
121+
struct timespec ts, sys_ts;
122+
long ret = vdso_clock_getres(clk_id, &ts);
123+
124+
if (ret == 0) {
125+
printf("The resolution is %lld %lld\n",
126+
(long long)ts.tv_sec, (long long)ts.tv_nsec);
127+
} else {
128+
printf("%s failed\n", name[3]);
129+
return KSFT_FAIL;
130+
}
131+
132+
ret = syscall(SYS_clock_getres, clk_id, &sys_ts);
133+
134+
if ((sys_ts.tv_sec != ts.tv_sec) || (sys_ts.tv_nsec != ts.tv_nsec)) {
135+
printf("%s failed\n", name[3]);
136+
return KSFT_FAIL;
137+
}
138+
139+
return KSFT_PASS;
140+
}
141+
142+
const char *vdso_clock_name[12] = {
143+
"CLOCK_REALTIME",
144+
"CLOCK_MONOTONIC",
145+
"CLOCK_PROCESS_CPUTIME_ID",
146+
"CLOCK_THREAD_CPUTIME_ID",
147+
"CLOCK_MONOTONIC_RAW",
148+
"CLOCK_REALTIME_COARSE",
149+
"CLOCK_MONOTONIC_COARSE",
150+
"CLOCK_BOOTTIME",
151+
"CLOCK_REALTIME_ALARM",
152+
"CLOCK_BOOTTIME_ALARM",
153+
"CLOCK_SGI_CYCLE",
154+
"CLOCK_TAI",
155+
};
156+
157+
/*
158+
* This function calls vdso_test_clock_gettime and vdso_test_clock_getres
159+
* with different values for clock_id.
160+
*/
161+
static inline int vdso_test_clock(clockid_t clock_id)
162+
{
163+
int ret0, ret1;
164+
165+
ret0 = vdso_test_clock_gettime(clock_id);
166+
/* A skipped test is considered passed */
167+
if (ret0 == KSFT_SKIP)
168+
ret0 = KSFT_PASS;
169+
170+
ret1 = vdso_test_clock_getres(clock_id);
171+
/* A skipped test is considered passed */
172+
if (ret1 == KSFT_SKIP)
173+
ret1 = KSFT_PASS;
174+
175+
ret0 += ret1;
176+
177+
printf("clock_id: %s", vdso_clock_name[clock_id]);
178+
179+
if (ret0 > 0)
180+
printf(" [FAIL]\n");
181+
else
182+
printf(" [PASS]\n");
183+
184+
return ret0;
185+
}
186+
187+
int main(int argc, char **argv)
188+
{
189+
unsigned long sysinfo_ehdr = getauxval(AT_SYSINFO_EHDR);
190+
int ret;
191+
192+
if (!sysinfo_ehdr) {
193+
printf("AT_SYSINFO_EHDR is not present!\n");
194+
return KSFT_SKIP;
195+
}
196+
197+
version = versions[VDSO_VERSION];
198+
name = (const char **)&names[VDSO_NAMES];
199+
200+
printf("[vDSO kselftest] VDSO_VERSION: %s\n", version);
201+
202+
vdso_init_from_sysinfo_ehdr(getauxval(AT_SYSINFO_EHDR));
203+
204+
ret = vdso_test_gettimeofday();
205+
206+
#if _POSIX_TIMERS > 0
207+
208+
#ifdef CLOCK_REALTIME
209+
ret += vdso_test_clock(CLOCK_REALTIME);
210+
#endif
211+
212+
#ifdef CLOCK_BOOTTIME
213+
ret += vdso_test_clock(CLOCK_BOOTTIME);
214+
#endif
215+
216+
#ifdef CLOCK_TAI
217+
ret += vdso_test_clock(CLOCK_TAI);
218+
#endif
219+
220+
#ifdef CLOCK_REALTIME_COARSE
221+
ret += vdso_test_clock(CLOCK_REALTIME_COARSE);
222+
#endif
223+
224+
#ifdef CLOCK_MONOTONIC
225+
ret += vdso_test_clock(CLOCK_MONOTONIC);
226+
#endif
227+
228+
#ifdef CLOCK_MONOTONIC_RAW
229+
ret += vdso_test_clock(CLOCK_MONOTONIC_RAW);
230+
#endif
231+
232+
#ifdef CLOCK_MONOTONIC_COARSE
233+
ret += vdso_test_clock(CLOCK_MONOTONIC_COARSE);
234+
#endif
235+
236+
#endif
237+
238+
ret += vdso_test_time();
239+
240+
if (ret > 0)
241+
return KSFT_FAIL;
242+
243+
return KSFT_PASS;
244+
}

0 commit comments

Comments
 (0)