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