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