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 /* The same as struct __kernel_timespec */ 30 struct vdso_timespec64 { 31 uint64_t tv_sec; 32 uint64_t tv_nsec; 33 }; 34 35 typedef long (*vdso_gettimeofday_t)(struct timeval *tv, struct timezone *tz); 36 typedef long (*vdso_clock_gettime_t)(clockid_t clk_id, struct timespec *ts); 37 typedef long (*vdso_clock_gettime64_t)(clockid_t clk_id, struct vdso_timespec64 *ts); 38 typedef long (*vdso_clock_getres_t)(clockid_t clk_id, struct timespec *ts); 39 typedef long (*vdso_clock_getres_time64_t)(clockid_t clk_id, struct vdso_timespec64 *ts); 40 typedef time_t (*vdso_time_t)(time_t *t); 41 42 static const char * const vdso_clock_name[] = { 43 [CLOCK_REALTIME] = "CLOCK_REALTIME", 44 [CLOCK_MONOTONIC] = "CLOCK_MONOTONIC", 45 [CLOCK_PROCESS_CPUTIME_ID] = "CLOCK_PROCESS_CPUTIME_ID", 46 [CLOCK_THREAD_CPUTIME_ID] = "CLOCK_THREAD_CPUTIME_ID", 47 [CLOCK_MONOTONIC_RAW] = "CLOCK_MONOTONIC_RAW", 48 [CLOCK_REALTIME_COARSE] = "CLOCK_REALTIME_COARSE", 49 [CLOCK_MONOTONIC_COARSE] = "CLOCK_MONOTONIC_COARSE", 50 [CLOCK_BOOTTIME] = "CLOCK_BOOTTIME", 51 [CLOCK_REALTIME_ALARM] = "CLOCK_REALTIME_ALARM", 52 [CLOCK_BOOTTIME_ALARM] = "CLOCK_BOOTTIME_ALARM", 53 [10 /* CLOCK_SGI_CYCLE */] = "CLOCK_SGI_CYCLE", 54 [CLOCK_TAI] = "CLOCK_TAI", 55 }; 56 57 static void vdso_test_gettimeofday(void) 58 { 59 /* Find gettimeofday. */ 60 vdso_gettimeofday_t vdso_gettimeofday = 61 (vdso_gettimeofday_t)vdso_sym(version, name[0]); 62 63 if (!vdso_gettimeofday) { 64 ksft_print_msg("Couldn't find %s\n", name[0]); 65 ksft_test_result_skip("%s\n", name[0]); 66 return; 67 } 68 69 struct timeval tv; 70 long ret = VDSO_CALL(vdso_gettimeofday, 2, &tv, 0); 71 72 if (ret == 0) { 73 ksft_print_msg("The time is %lld.%06lld\n", 74 (long long)tv.tv_sec, (long long)tv.tv_usec); 75 ksft_test_result_pass("%s\n", name[0]); 76 } else { 77 ksft_test_result_fail("%s\n", name[0]); 78 } 79 } 80 81 static void vdso_test_clock_gettime64(clockid_t clk_id) 82 { 83 /* Find clock_gettime64. */ 84 vdso_clock_gettime64_t vdso_clock_gettime64 = 85 (vdso_clock_gettime64_t)vdso_sym(version, name[5]); 86 87 if (!vdso_clock_gettime64) { 88 ksft_print_msg("Couldn't find %s\n", name[5]); 89 ksft_test_result_skip("%s %s\n", name[5], 90 vdso_clock_name[clk_id]); 91 return; 92 } 93 94 struct vdso_timespec64 ts; 95 long ret = VDSO_CALL(vdso_clock_gettime64, 2, clk_id, &ts); 96 97 if (ret == 0) { 98 ksft_print_msg("The time is %lld.%06lld\n", 99 (long long)ts.tv_sec, (long long)ts.tv_nsec); 100 ksft_test_result_pass("%s %s\n", name[5], 101 vdso_clock_name[clk_id]); 102 } else { 103 ksft_test_result_fail("%s %s\n", name[5], 104 vdso_clock_name[clk_id]); 105 } 106 } 107 108 static void vdso_test_clock_gettime(clockid_t clk_id) 109 { 110 /* Find clock_gettime. */ 111 vdso_clock_gettime_t vdso_clock_gettime = 112 (vdso_clock_gettime_t)vdso_sym(version, name[1]); 113 114 if (!vdso_clock_gettime) { 115 ksft_print_msg("Couldn't find %s\n", name[1]); 116 ksft_test_result_skip("%s %s\n", name[1], 117 vdso_clock_name[clk_id]); 118 return; 119 } 120 121 struct timespec ts; 122 long ret = VDSO_CALL(vdso_clock_gettime, 2, clk_id, &ts); 123 124 if (ret == 0) { 125 ksft_print_msg("The time is %lld.%06lld\n", 126 (long long)ts.tv_sec, (long long)ts.tv_nsec); 127 ksft_test_result_pass("%s %s\n", name[1], 128 vdso_clock_name[clk_id]); 129 } else { 130 ksft_test_result_fail("%s %s\n", name[1], 131 vdso_clock_name[clk_id]); 132 } 133 } 134 135 static void vdso_test_time(void) 136 { 137 /* Find time. */ 138 vdso_time_t vdso_time = 139 (vdso_time_t)vdso_sym(version, name[2]); 140 141 if (!vdso_time) { 142 ksft_print_msg("Couldn't find %s\n", name[2]); 143 ksft_test_result_skip("%s\n", name[2]); 144 return; 145 } 146 147 long ret = VDSO_CALL(vdso_time, 1, NULL); 148 149 if (ret > 0) { 150 ksft_print_msg("The time in hours since January 1, 1970 is %lld\n", 151 (long long)(ret / 3600)); 152 ksft_test_result_pass("%s\n", name[2]); 153 } else { 154 ksft_test_result_fail("%s\n", name[2]); 155 } 156 } 157 158 static void vdso_test_clock_getres(clockid_t clk_id) 159 { 160 int clock_getres_fail = 0; 161 162 /* Find clock_getres. */ 163 vdso_clock_getres_t vdso_clock_getres = 164 (vdso_clock_getres_t)vdso_sym(version, name[3]); 165 166 if (!vdso_clock_getres) { 167 ksft_print_msg("Couldn't find %s\n", name[3]); 168 ksft_test_result_skip("%s %s\n", name[3], 169 vdso_clock_name[clk_id]); 170 return; 171 } 172 173 struct timespec ts, sys_ts; 174 long ret = VDSO_CALL(vdso_clock_getres, 2, clk_id, &ts); 175 176 if (ret == 0) { 177 ksft_print_msg("The vdso resolution is %lld %lld\n", 178 (long long)ts.tv_sec, (long long)ts.tv_nsec); 179 } else { 180 clock_getres_fail++; 181 } 182 183 ret = syscall(__NR_clock_getres, clk_id, &sys_ts); 184 185 ksft_print_msg("The syscall resolution is %lld %lld\n", 186 (long long)sys_ts.tv_sec, (long long)sys_ts.tv_nsec); 187 188 if ((sys_ts.tv_sec != ts.tv_sec) || (sys_ts.tv_nsec != ts.tv_nsec)) 189 clock_getres_fail++; 190 191 if (clock_getres_fail > 0) { 192 ksft_test_result_fail("%s %s\n", name[3], 193 vdso_clock_name[clk_id]); 194 } else { 195 ksft_test_result_pass("%s %s\n", name[3], 196 vdso_clock_name[clk_id]); 197 } 198 } 199 200 #ifdef __NR_clock_getres_time64 201 static void vdso_test_clock_getres_time64(clockid_t clk_id) 202 { 203 int clock_getres_fail = 0; 204 205 /* Find clock_getres. */ 206 vdso_clock_getres_time64_t vdso_clock_getres_time64 = 207 (vdso_clock_getres_time64_t)vdso_sym(version, name[7]); 208 209 if (!vdso_clock_getres_time64) { 210 ksft_print_msg("Couldn't find %s\n", name[7]); 211 ksft_test_result_skip("%s %s\n", name[7], 212 vdso_clock_name[clk_id]); 213 return; 214 } 215 216 struct vdso_timespec64 ts, sys_ts; 217 long ret = VDSO_CALL(vdso_clock_getres_time64, 2, clk_id, &ts); 218 219 if (ret == 0) { 220 ksft_print_msg("The vdso resolution is %lld %lld\n", 221 (long long)ts.tv_sec, (long long)ts.tv_nsec); 222 } else { 223 clock_getres_fail++; 224 } 225 226 ret = syscall(__NR_clock_getres_time64, clk_id, &sys_ts); 227 228 ksft_print_msg("The syscall resolution is %lld %lld\n", 229 (long long)sys_ts.tv_sec, (long long)sys_ts.tv_nsec); 230 231 if ((sys_ts.tv_sec != ts.tv_sec) || (sys_ts.tv_nsec != ts.tv_nsec)) 232 clock_getres_fail++; 233 234 if (clock_getres_fail > 0) { 235 ksft_test_result_fail("%s %s\n", name[7], 236 vdso_clock_name[clk_id]); 237 } else { 238 ksft_test_result_pass("%s %s\n", name[7], 239 vdso_clock_name[clk_id]); 240 } 241 } 242 #else /* !__NR_clock_getres_time64 */ 243 static void vdso_test_clock_getres_time64(clockid_t clk_id) 244 { 245 ksft_test_result_skip("%s %s\n", name[7], vdso_clock_name[clk_id]); 246 } 247 #endif /* __NR_clock_getres_time64 */ 248 249 /* 250 * This function calls vdso_test_clock_gettime and vdso_test_clock_getres 251 * with different values for clock_id. 252 */ 253 static inline void vdso_test_clock(clockid_t clock_id) 254 { 255 ksft_print_msg("clock_id: %s\n", vdso_clock_name[clock_id]); 256 257 vdso_test_clock_gettime(clock_id); 258 vdso_test_clock_gettime64(clock_id); 259 260 vdso_test_clock_getres(clock_id); 261 vdso_test_clock_getres_time64(clock_id); 262 } 263 264 #define VDSO_TEST_PLAN 38 265 266 int main(int argc, char **argv) 267 { 268 unsigned long sysinfo_ehdr = getauxval(AT_SYSINFO_EHDR); 269 270 ksft_print_header(); 271 272 if (!sysinfo_ehdr) 273 ksft_exit_skip("AT_SYSINFO_EHDR is not present!\n"); 274 275 ksft_set_plan(VDSO_TEST_PLAN); 276 277 version = versions[VDSO_VERSION]; 278 name = (const char **)&names[VDSO_NAMES]; 279 280 ksft_print_msg("[vDSO kselftest] VDSO_VERSION: %s\n", version); 281 282 vdso_init_from_sysinfo_ehdr(getauxval(AT_SYSINFO_EHDR)); 283 284 vdso_test_gettimeofday(); 285 286 vdso_test_clock(CLOCK_REALTIME); 287 vdso_test_clock(CLOCK_BOOTTIME); 288 vdso_test_clock(CLOCK_TAI); 289 vdso_test_clock(CLOCK_REALTIME_COARSE); 290 vdso_test_clock(CLOCK_MONOTONIC); 291 vdso_test_clock(CLOCK_MONOTONIC_RAW); 292 vdso_test_clock(CLOCK_MONOTONIC_COARSE); 293 vdso_test_clock(CLOCK_PROCESS_CPUTIME_ID); 294 vdso_test_clock(CLOCK_THREAD_CPUTIME_ID); 295 296 vdso_test_time(); 297 298 ksft_finished(); 299 } 300