1693f5ca0SVincenzo Frascino // SPDX-License-Identifier: GPL-2.0 2693f5ca0SVincenzo Frascino /* 3693f5ca0SVincenzo Frascino * vdso_full_test.c: Sample code to test all the timers. 4693f5ca0SVincenzo Frascino * Copyright (c) 2019 Arm Ltd. 5693f5ca0SVincenzo Frascino * 6693f5ca0SVincenzo Frascino * Compile with: 7693f5ca0SVincenzo Frascino * gcc -std=gnu99 vdso_full_test.c parse_vdso.c 8693f5ca0SVincenzo Frascino * 9693f5ca0SVincenzo Frascino */ 10693f5ca0SVincenzo Frascino 11693f5ca0SVincenzo Frascino #include <stdint.h> 12693f5ca0SVincenzo Frascino #include <elf.h> 13693f5ca0SVincenzo Frascino #include <stdio.h> 14693f5ca0SVincenzo Frascino #include <time.h> 15693f5ca0SVincenzo Frascino #include <sys/auxv.h> 16693f5ca0SVincenzo Frascino #include <sys/time.h> 17693f5ca0SVincenzo Frascino #define _GNU_SOURCE 18693f5ca0SVincenzo Frascino #include <unistd.h> 19693f5ca0SVincenzo Frascino #include <sys/syscall.h> 20693f5ca0SVincenzo Frascino 21693f5ca0SVincenzo Frascino #include "../kselftest.h" 22693f5ca0SVincenzo Frascino #include "vdso_config.h" 236eda706aSChristophe Leroy #include "vdso_call.h" 24*f0d0dbbcSChristophe Leroy #include "parse_vdso.h" 25693f5ca0SVincenzo Frascino 26693f5ca0SVincenzo Frascino static const char *version; 27693f5ca0SVincenzo Frascino static const char **name; 28693f5ca0SVincenzo Frascino 29693f5ca0SVincenzo Frascino typedef long (*vdso_gettimeofday_t)(struct timeval *tv, struct timezone *tz); 30693f5ca0SVincenzo Frascino typedef long (*vdso_clock_gettime_t)(clockid_t clk_id, struct timespec *ts); 31693f5ca0SVincenzo Frascino typedef long (*vdso_clock_getres_t)(clockid_t clk_id, struct timespec *ts); 32693f5ca0SVincenzo Frascino typedef time_t (*vdso_time_t)(time_t *t); 33693f5ca0SVincenzo Frascino 3460e76e7aSMark Brown const char *vdso_clock_name[12] = { 3560e76e7aSMark Brown "CLOCK_REALTIME", 3660e76e7aSMark Brown "CLOCK_MONOTONIC", 3760e76e7aSMark Brown "CLOCK_PROCESS_CPUTIME_ID", 3860e76e7aSMark Brown "CLOCK_THREAD_CPUTIME_ID", 3960e76e7aSMark Brown "CLOCK_MONOTONIC_RAW", 4060e76e7aSMark Brown "CLOCK_REALTIME_COARSE", 4160e76e7aSMark Brown "CLOCK_MONOTONIC_COARSE", 4260e76e7aSMark Brown "CLOCK_BOOTTIME", 4360e76e7aSMark Brown "CLOCK_REALTIME_ALARM", 4460e76e7aSMark Brown "CLOCK_BOOTTIME_ALARM", 4560e76e7aSMark Brown "CLOCK_SGI_CYCLE", 4660e76e7aSMark Brown "CLOCK_TAI", 4760e76e7aSMark Brown }; 48ec049891SVincenzo Frascino 49ec049891SVincenzo Frascino static void vdso_test_gettimeofday(void) 50693f5ca0SVincenzo Frascino { 51693f5ca0SVincenzo Frascino /* Find gettimeofday. */ 52693f5ca0SVincenzo Frascino vdso_gettimeofday_t vdso_gettimeofday = 53693f5ca0SVincenzo Frascino (vdso_gettimeofday_t)vdso_sym(version, name[0]); 54693f5ca0SVincenzo Frascino 55693f5ca0SVincenzo Frascino if (!vdso_gettimeofday) { 5660e76e7aSMark Brown ksft_print_msg("Couldn't find %s\n", name[0]); 5760e76e7aSMark Brown ksft_test_result_skip("%s\n", name[0]); 58ec049891SVincenzo Frascino return; 59693f5ca0SVincenzo Frascino } 60693f5ca0SVincenzo Frascino 61693f5ca0SVincenzo Frascino struct timeval tv; 626eda706aSChristophe Leroy long ret = VDSO_CALL(vdso_gettimeofday, 2, &tv, 0); 63693f5ca0SVincenzo Frascino 64693f5ca0SVincenzo Frascino if (ret == 0) { 65ec049891SVincenzo Frascino ksft_print_msg("The time is %lld.%06lld\n", 66693f5ca0SVincenzo Frascino (long long)tv.tv_sec, (long long)tv.tv_usec); 6760e76e7aSMark Brown ksft_test_result_pass("%s\n", name[0]); 68693f5ca0SVincenzo Frascino } else { 6960e76e7aSMark Brown ksft_test_result_fail("%s\n", name[0]); 70ec049891SVincenzo Frascino } 71693f5ca0SVincenzo Frascino } 72693f5ca0SVincenzo Frascino 73ec049891SVincenzo Frascino static void vdso_test_clock_gettime(clockid_t clk_id) 74693f5ca0SVincenzo Frascino { 75693f5ca0SVincenzo Frascino /* Find clock_gettime. */ 76693f5ca0SVincenzo Frascino vdso_clock_gettime_t vdso_clock_gettime = 77693f5ca0SVincenzo Frascino (vdso_clock_gettime_t)vdso_sym(version, name[1]); 78693f5ca0SVincenzo Frascino 79693f5ca0SVincenzo Frascino if (!vdso_clock_gettime) { 8060e76e7aSMark Brown ksft_print_msg("Couldn't find %s\n", name[1]); 8160e76e7aSMark Brown ksft_test_result_skip("%s %s\n", name[1], 8260e76e7aSMark Brown vdso_clock_name[clk_id]); 83ec049891SVincenzo Frascino return; 84693f5ca0SVincenzo Frascino } 85693f5ca0SVincenzo Frascino 86693f5ca0SVincenzo Frascino struct timespec ts; 876eda706aSChristophe Leroy long ret = VDSO_CALL(vdso_clock_gettime, 2, clk_id, &ts); 88693f5ca0SVincenzo Frascino 89693f5ca0SVincenzo Frascino if (ret == 0) { 90ec049891SVincenzo Frascino ksft_print_msg("The time is %lld.%06lld\n", 91693f5ca0SVincenzo Frascino (long long)ts.tv_sec, (long long)ts.tv_nsec); 9260e76e7aSMark Brown ksft_test_result_pass("%s %s\n", name[1], 9360e76e7aSMark Brown vdso_clock_name[clk_id]); 94693f5ca0SVincenzo Frascino } else { 9560e76e7aSMark Brown ksft_test_result_fail("%s %s\n", name[1], 9660e76e7aSMark Brown vdso_clock_name[clk_id]); 97ec049891SVincenzo Frascino } 98693f5ca0SVincenzo Frascino } 99693f5ca0SVincenzo Frascino 100ec049891SVincenzo Frascino static void vdso_test_time(void) 101693f5ca0SVincenzo Frascino { 102693f5ca0SVincenzo Frascino /* Find time. */ 103693f5ca0SVincenzo Frascino vdso_time_t vdso_time = 104693f5ca0SVincenzo Frascino (vdso_time_t)vdso_sym(version, name[2]); 105693f5ca0SVincenzo Frascino 106693f5ca0SVincenzo Frascino if (!vdso_time) { 10760e76e7aSMark Brown ksft_print_msg("Couldn't find %s\n", name[2]); 10860e76e7aSMark Brown ksft_test_result_skip("%s\n", name[2]); 109ec049891SVincenzo Frascino return; 110693f5ca0SVincenzo Frascino } 111693f5ca0SVincenzo Frascino 1126eda706aSChristophe Leroy long ret = VDSO_CALL(vdso_time, 1, NULL); 113693f5ca0SVincenzo Frascino 114693f5ca0SVincenzo Frascino if (ret > 0) { 115ec049891SVincenzo Frascino ksft_print_msg("The time in hours since January 1, 1970 is %lld\n", 116693f5ca0SVincenzo Frascino (long long)(ret / 3600)); 11760e76e7aSMark Brown ksft_test_result_pass("%s\n", name[2]); 118693f5ca0SVincenzo Frascino } else { 11960e76e7aSMark Brown ksft_test_result_fail("%s\n", name[2]); 120ec049891SVincenzo Frascino } 121693f5ca0SVincenzo Frascino } 122693f5ca0SVincenzo Frascino 123ec049891SVincenzo Frascino static void vdso_test_clock_getres(clockid_t clk_id) 124693f5ca0SVincenzo Frascino { 125ec049891SVincenzo Frascino int clock_getres_fail = 0; 126ec049891SVincenzo Frascino 127693f5ca0SVincenzo Frascino /* Find clock_getres. */ 128693f5ca0SVincenzo Frascino vdso_clock_getres_t vdso_clock_getres = 129693f5ca0SVincenzo Frascino (vdso_clock_getres_t)vdso_sym(version, name[3]); 130693f5ca0SVincenzo Frascino 131693f5ca0SVincenzo Frascino if (!vdso_clock_getres) { 13260e76e7aSMark Brown ksft_print_msg("Couldn't find %s\n", name[3]); 13360e76e7aSMark Brown ksft_test_result_skip("%s %s\n", name[3], 13460e76e7aSMark Brown vdso_clock_name[clk_id]); 135ec049891SVincenzo Frascino return; 136693f5ca0SVincenzo Frascino } 137693f5ca0SVincenzo Frascino 138693f5ca0SVincenzo Frascino struct timespec ts, sys_ts; 1396eda706aSChristophe Leroy long ret = VDSO_CALL(vdso_clock_getres, 2, clk_id, &ts); 140693f5ca0SVincenzo Frascino 141693f5ca0SVincenzo Frascino if (ret == 0) { 142ec049891SVincenzo Frascino ksft_print_msg("The vdso resolution is %lld %lld\n", 143693f5ca0SVincenzo Frascino (long long)ts.tv_sec, (long long)ts.tv_nsec); 144693f5ca0SVincenzo Frascino } else { 145ec049891SVincenzo Frascino clock_getres_fail++; 146693f5ca0SVincenzo Frascino } 147693f5ca0SVincenzo Frascino 148693f5ca0SVincenzo Frascino ret = syscall(SYS_clock_getres, clk_id, &sys_ts); 149693f5ca0SVincenzo Frascino 150ec049891SVincenzo Frascino ksft_print_msg("The syscall resolution is %lld %lld\n", 151ec049891SVincenzo Frascino (long long)sys_ts.tv_sec, (long long)sys_ts.tv_nsec); 152693f5ca0SVincenzo Frascino 153ec049891SVincenzo Frascino if ((sys_ts.tv_sec != ts.tv_sec) || (sys_ts.tv_nsec != ts.tv_nsec)) 154ec049891SVincenzo Frascino clock_getres_fail++; 155ec049891SVincenzo Frascino 156ec049891SVincenzo Frascino if (clock_getres_fail > 0) { 15760e76e7aSMark Brown ksft_test_result_fail("%s %s\n", name[3], 15860e76e7aSMark Brown vdso_clock_name[clk_id]); 159ec049891SVincenzo Frascino } else { 16060e76e7aSMark Brown ksft_test_result_pass("%s %s\n", name[3], 16160e76e7aSMark Brown vdso_clock_name[clk_id]); 162ec049891SVincenzo Frascino } 163693f5ca0SVincenzo Frascino } 164693f5ca0SVincenzo Frascino 165693f5ca0SVincenzo Frascino /* 166693f5ca0SVincenzo Frascino * This function calls vdso_test_clock_gettime and vdso_test_clock_getres 167693f5ca0SVincenzo Frascino * with different values for clock_id. 168693f5ca0SVincenzo Frascino */ 169ec049891SVincenzo Frascino static inline void vdso_test_clock(clockid_t clock_id) 170693f5ca0SVincenzo Frascino { 171e63e1354SMark Brown ksft_print_msg("clock_id: %s\n", vdso_clock_name[clock_id]); 172693f5ca0SVincenzo Frascino 173ec049891SVincenzo Frascino vdso_test_clock_gettime(clock_id); 174693f5ca0SVincenzo Frascino 175ec049891SVincenzo Frascino vdso_test_clock_getres(clock_id); 176693f5ca0SVincenzo Frascino } 177693f5ca0SVincenzo Frascino 178ec049891SVincenzo Frascino #define VDSO_TEST_PLAN 16 179ec049891SVincenzo Frascino 180693f5ca0SVincenzo Frascino int main(int argc, char **argv) 181693f5ca0SVincenzo Frascino { 182693f5ca0SVincenzo Frascino unsigned long sysinfo_ehdr = getauxval(AT_SYSINFO_EHDR); 183ec049891SVincenzo Frascino 184ec049891SVincenzo Frascino ksft_print_header(); 185ec049891SVincenzo Frascino ksft_set_plan(VDSO_TEST_PLAN); 186693f5ca0SVincenzo Frascino 187693f5ca0SVincenzo Frascino if (!sysinfo_ehdr) { 18825cfe960SMark Brown ksft_print_msg("AT_SYSINFO_EHDR is not present!\n"); 189693f5ca0SVincenzo Frascino return KSFT_SKIP; 190693f5ca0SVincenzo Frascino } 191693f5ca0SVincenzo Frascino 192693f5ca0SVincenzo Frascino version = versions[VDSO_VERSION]; 193693f5ca0SVincenzo Frascino name = (const char **)&names[VDSO_NAMES]; 194693f5ca0SVincenzo Frascino 19525cfe960SMark Brown ksft_print_msg("[vDSO kselftest] VDSO_VERSION: %s\n", version); 196693f5ca0SVincenzo Frascino 197693f5ca0SVincenzo Frascino vdso_init_from_sysinfo_ehdr(getauxval(AT_SYSINFO_EHDR)); 198693f5ca0SVincenzo Frascino 199ec049891SVincenzo Frascino vdso_test_gettimeofday(); 200693f5ca0SVincenzo Frascino 201693f5ca0SVincenzo Frascino #if _POSIX_TIMERS > 0 202693f5ca0SVincenzo Frascino 203693f5ca0SVincenzo Frascino #ifdef CLOCK_REALTIME 204ec049891SVincenzo Frascino vdso_test_clock(CLOCK_REALTIME); 205693f5ca0SVincenzo Frascino #endif 206693f5ca0SVincenzo Frascino 207693f5ca0SVincenzo Frascino #ifdef CLOCK_BOOTTIME 208ec049891SVincenzo Frascino vdso_test_clock(CLOCK_BOOTTIME); 209693f5ca0SVincenzo Frascino #endif 210693f5ca0SVincenzo Frascino 211693f5ca0SVincenzo Frascino #ifdef CLOCK_TAI 212ec049891SVincenzo Frascino vdso_test_clock(CLOCK_TAI); 213693f5ca0SVincenzo Frascino #endif 214693f5ca0SVincenzo Frascino 215693f5ca0SVincenzo Frascino #ifdef CLOCK_REALTIME_COARSE 216ec049891SVincenzo Frascino vdso_test_clock(CLOCK_REALTIME_COARSE); 217693f5ca0SVincenzo Frascino #endif 218693f5ca0SVincenzo Frascino 219693f5ca0SVincenzo Frascino #ifdef CLOCK_MONOTONIC 220ec049891SVincenzo Frascino vdso_test_clock(CLOCK_MONOTONIC); 221693f5ca0SVincenzo Frascino #endif 222693f5ca0SVincenzo Frascino 223693f5ca0SVincenzo Frascino #ifdef CLOCK_MONOTONIC_RAW 224ec049891SVincenzo Frascino vdso_test_clock(CLOCK_MONOTONIC_RAW); 225693f5ca0SVincenzo Frascino #endif 226693f5ca0SVincenzo Frascino 227693f5ca0SVincenzo Frascino #ifdef CLOCK_MONOTONIC_COARSE 228ec049891SVincenzo Frascino vdso_test_clock(CLOCK_MONOTONIC_COARSE); 229693f5ca0SVincenzo Frascino #endif 230693f5ca0SVincenzo Frascino 231693f5ca0SVincenzo Frascino #endif 232693f5ca0SVincenzo Frascino 233ec049891SVincenzo Frascino vdso_test_time(); 234693f5ca0SVincenzo Frascino 235ec049891SVincenzo Frascino ksft_print_cnts(); 236ec049891SVincenzo Frascino return ksft_get_fail_cnt() == 0 ? KSFT_PASS : KSFT_FAIL; 237693f5ca0SVincenzo Frascino } 238