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 const 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 51 static void vdso_test_gettimeofday(void) 52 { 53 /* Find gettimeofday. */ 54 vdso_gettimeofday_t vdso_gettimeofday = 55 (vdso_gettimeofday_t)vdso_sym(version, name[0]); 56 57 if (!vdso_gettimeofday) { 58 ksft_print_msg("Couldn't find %s\n", name[0]); 59 ksft_test_result_skip("%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("The time is %lld.%06lld\n", 68 (long long)tv.tv_sec, (long long)tv.tv_usec); 69 ksft_test_result_pass("%s\n", name[0]); 70 } else { 71 ksft_test_result_fail("%s\n", name[0]); 72 } 73 } 74 75 static 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[1]); 80 81 if (!vdso_clock_gettime) { 82 ksft_print_msg("Couldn't find %s\n", name[1]); 83 ksft_test_result_skip("%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("The time is %lld.%06lld\n", 93 (long long)ts.tv_sec, (long long)ts.tv_nsec); 94 ksft_test_result_pass("%s %s\n", name[1], 95 vdso_clock_name[clk_id]); 96 } else { 97 ksft_test_result_fail("%s %s\n", name[1], 98 vdso_clock_name[clk_id]); 99 } 100 } 101 102 static 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("Couldn't find %s\n", name[2]); 110 ksft_test_result_skip("%s\n", name[2]); 111 return; 112 } 113 114 long ret = vdso_time(NULL); 115 116 if (ret > 0) { 117 ksft_print_msg("The time in hours since January 1, 1970 is %lld\n", 118 (long long)(ret / 3600)); 119 ksft_test_result_pass("%s\n", name[2]); 120 } else { 121 ksft_test_result_fail("%s\n", name[2]); 122 } 123 } 124 125 static 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[3]); 132 133 if (!vdso_clock_getres) { 134 ksft_print_msg("Couldn't find %s\n", name[3]); 135 ksft_test_result_skip("%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("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("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("%s %s\n", name[3], 160 vdso_clock_name[clk_id]); 161 } else { 162 ksft_test_result_pass("%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 */ 171 static inline void vdso_test_clock(clockid_t clock_id) 172 { 173 ksft_print_msg("\nclock_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 182 int 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 printf("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 printf("[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