0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #include <stdint.h>
0012 #include <elf.h>
0013 #include <stdio.h>
0014 #include <time.h>
0015 #include <sys/auxv.h>
0016 #include <sys/time.h>
0017 #define _GNU_SOURCE
0018 #include <unistd.h>
0019 #include <sys/syscall.h>
0020
0021 #include "../kselftest.h"
0022 #include "vdso_config.h"
0023
0024 extern void *vdso_sym(const char *version, const char *name);
0025 extern void vdso_init_from_sysinfo_ehdr(uintptr_t base);
0026 extern void vdso_init_from_auxv(void *auxv);
0027
0028 static const char *version;
0029 static const char **name;
0030
0031 typedef long (*vdso_gettimeofday_t)(struct timeval *tv, struct timezone *tz);
0032 typedef long (*vdso_clock_gettime_t)(clockid_t clk_id, struct timespec *ts);
0033 typedef long (*vdso_clock_getres_t)(clockid_t clk_id, struct timespec *ts);
0034 typedef time_t (*vdso_time_t)(time_t *t);
0035
0036 #define VDSO_TEST_PASS_MSG() "\n%s(): PASS\n", __func__
0037 #define VDSO_TEST_FAIL_MSG(x) "\n%s(): %s FAIL\n", __func__, x
0038 #define VDSO_TEST_SKIP_MSG(x) "\n%s(): SKIP: Could not find %s\n", __func__, x
0039
0040 static void vdso_test_gettimeofday(void)
0041 {
0042
0043 vdso_gettimeofday_t vdso_gettimeofday =
0044 (vdso_gettimeofday_t)vdso_sym(version, name[0]);
0045
0046 if (!vdso_gettimeofday) {
0047 ksft_test_result_skip(VDSO_TEST_SKIP_MSG(name[0]));
0048 return;
0049 }
0050
0051 struct timeval tv;
0052 long ret = vdso_gettimeofday(&tv, 0);
0053
0054 if (ret == 0) {
0055 ksft_print_msg("The time is %lld.%06lld\n",
0056 (long long)tv.tv_sec, (long long)tv.tv_usec);
0057 ksft_test_result_pass(VDSO_TEST_PASS_MSG());
0058 } else {
0059 ksft_test_result_fail(VDSO_TEST_FAIL_MSG(name[0]));
0060 }
0061 }
0062
0063 static void vdso_test_clock_gettime(clockid_t clk_id)
0064 {
0065
0066 vdso_clock_gettime_t vdso_clock_gettime =
0067 (vdso_clock_gettime_t)vdso_sym(version, name[1]);
0068
0069 if (!vdso_clock_gettime) {
0070 ksft_test_result_skip(VDSO_TEST_SKIP_MSG(name[1]));
0071 return;
0072 }
0073
0074 struct timespec ts;
0075 long ret = vdso_clock_gettime(clk_id, &ts);
0076
0077 if (ret == 0) {
0078 ksft_print_msg("The time is %lld.%06lld\n",
0079 (long long)ts.tv_sec, (long long)ts.tv_nsec);
0080 ksft_test_result_pass(VDSO_TEST_PASS_MSG());
0081 } else {
0082 ksft_test_result_fail(VDSO_TEST_FAIL_MSG(name[1]));
0083 }
0084 }
0085
0086 static void vdso_test_time(void)
0087 {
0088
0089 vdso_time_t vdso_time =
0090 (vdso_time_t)vdso_sym(version, name[2]);
0091
0092 if (!vdso_time) {
0093 ksft_test_result_skip(VDSO_TEST_SKIP_MSG(name[2]));
0094 return;
0095 }
0096
0097 long ret = vdso_time(NULL);
0098
0099 if (ret > 0) {
0100 ksft_print_msg("The time in hours since January 1, 1970 is %lld\n",
0101 (long long)(ret / 3600));
0102 ksft_test_result_pass(VDSO_TEST_PASS_MSG());
0103 } else {
0104 ksft_test_result_fail(VDSO_TEST_FAIL_MSG(name[2]));
0105 }
0106 }
0107
0108 static void vdso_test_clock_getres(clockid_t clk_id)
0109 {
0110 int clock_getres_fail = 0;
0111
0112
0113 vdso_clock_getres_t vdso_clock_getres =
0114 (vdso_clock_getres_t)vdso_sym(version, name[3]);
0115
0116 if (!vdso_clock_getres) {
0117 ksft_test_result_skip(VDSO_TEST_SKIP_MSG(name[3]));
0118 return;
0119 }
0120
0121 struct timespec ts, sys_ts;
0122 long ret = vdso_clock_getres(clk_id, &ts);
0123
0124 if (ret == 0) {
0125 ksft_print_msg("The vdso resolution is %lld %lld\n",
0126 (long long)ts.tv_sec, (long long)ts.tv_nsec);
0127 } else {
0128 clock_getres_fail++;
0129 }
0130
0131 ret = syscall(SYS_clock_getres, clk_id, &sys_ts);
0132
0133 ksft_print_msg("The syscall resolution is %lld %lld\n",
0134 (long long)sys_ts.tv_sec, (long long)sys_ts.tv_nsec);
0135
0136 if ((sys_ts.tv_sec != ts.tv_sec) || (sys_ts.tv_nsec != ts.tv_nsec))
0137 clock_getres_fail++;
0138
0139 if (clock_getres_fail > 0) {
0140 ksft_test_result_fail(VDSO_TEST_FAIL_MSG(name[3]));
0141 } else {
0142 ksft_test_result_pass(VDSO_TEST_PASS_MSG());
0143 }
0144 }
0145
0146 const char *vdso_clock_name[12] = {
0147 "CLOCK_REALTIME",
0148 "CLOCK_MONOTONIC",
0149 "CLOCK_PROCESS_CPUTIME_ID",
0150 "CLOCK_THREAD_CPUTIME_ID",
0151 "CLOCK_MONOTONIC_RAW",
0152 "CLOCK_REALTIME_COARSE",
0153 "CLOCK_MONOTONIC_COARSE",
0154 "CLOCK_BOOTTIME",
0155 "CLOCK_REALTIME_ALARM",
0156 "CLOCK_BOOTTIME_ALARM",
0157 "CLOCK_SGI_CYCLE",
0158 "CLOCK_TAI",
0159 };
0160
0161
0162
0163
0164
0165 static inline void vdso_test_clock(clockid_t clock_id)
0166 {
0167 ksft_print_msg("\nclock_id: %s\n", vdso_clock_name[clock_id]);
0168
0169 vdso_test_clock_gettime(clock_id);
0170
0171 vdso_test_clock_getres(clock_id);
0172 }
0173
0174 #define VDSO_TEST_PLAN 16
0175
0176 int main(int argc, char **argv)
0177 {
0178 unsigned long sysinfo_ehdr = getauxval(AT_SYSINFO_EHDR);
0179
0180 ksft_print_header();
0181 ksft_set_plan(VDSO_TEST_PLAN);
0182
0183 if (!sysinfo_ehdr) {
0184 printf("AT_SYSINFO_EHDR is not present!\n");
0185 return KSFT_SKIP;
0186 }
0187
0188 version = versions[VDSO_VERSION];
0189 name = (const char **)&names[VDSO_NAMES];
0190
0191 printf("[vDSO kselftest] VDSO_VERSION: %s\n", version);
0192
0193 vdso_init_from_sysinfo_ehdr(getauxval(AT_SYSINFO_EHDR));
0194
0195 vdso_test_gettimeofday();
0196
0197 #if _POSIX_TIMERS > 0
0198
0199 #ifdef CLOCK_REALTIME
0200 vdso_test_clock(CLOCK_REALTIME);
0201 #endif
0202
0203 #ifdef CLOCK_BOOTTIME
0204 vdso_test_clock(CLOCK_BOOTTIME);
0205 #endif
0206
0207 #ifdef CLOCK_TAI
0208 vdso_test_clock(CLOCK_TAI);
0209 #endif
0210
0211 #ifdef CLOCK_REALTIME_COARSE
0212 vdso_test_clock(CLOCK_REALTIME_COARSE);
0213 #endif
0214
0215 #ifdef CLOCK_MONOTONIC
0216 vdso_test_clock(CLOCK_MONOTONIC);
0217 #endif
0218
0219 #ifdef CLOCK_MONOTONIC_RAW
0220 vdso_test_clock(CLOCK_MONOTONIC_RAW);
0221 #endif
0222
0223 #ifdef CLOCK_MONOTONIC_COARSE
0224 vdso_test_clock(CLOCK_MONOTONIC_COARSE);
0225 #endif
0226
0227 #endif
0228
0229 vdso_test_time();
0230
0231 ksft_print_cnts();
0232 return ksft_get_fail_cnt() == 0 ? KSFT_PASS : KSFT_FAIL;
0233 }