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" 23693f5ca0SVincenzo Frascino 24693f5ca0SVincenzo Frascino extern void *vdso_sym(const char *version, const char *name); 25693f5ca0SVincenzo Frascino extern void vdso_init_from_sysinfo_ehdr(uintptr_t base); 26693f5ca0SVincenzo Frascino extern void vdso_init_from_auxv(void *auxv); 27693f5ca0SVincenzo Frascino 28693f5ca0SVincenzo Frascino static const char *version; 29693f5ca0SVincenzo Frascino static const char **name; 30693f5ca0SVincenzo Frascino 31693f5ca0SVincenzo Frascino typedef long (*vdso_gettimeofday_t)(struct timeval *tv, struct timezone *tz); 32693f5ca0SVincenzo Frascino typedef long (*vdso_clock_gettime_t)(clockid_t clk_id, struct timespec *ts); 33693f5ca0SVincenzo Frascino typedef long (*vdso_clock_getres_t)(clockid_t clk_id, struct timespec *ts); 34693f5ca0SVincenzo Frascino typedef time_t (*vdso_time_t)(time_t *t); 35693f5ca0SVincenzo Frascino 3660e76e7aSMark Brown const char *vdso_clock_name[12] = { 3760e76e7aSMark Brown "CLOCK_REALTIME", 3860e76e7aSMark Brown "CLOCK_MONOTONIC", 3960e76e7aSMark Brown "CLOCK_PROCESS_CPUTIME_ID", 4060e76e7aSMark Brown "CLOCK_THREAD_CPUTIME_ID", 4160e76e7aSMark Brown "CLOCK_MONOTONIC_RAW", 4260e76e7aSMark Brown "CLOCK_REALTIME_COARSE", 4360e76e7aSMark Brown "CLOCK_MONOTONIC_COARSE", 4460e76e7aSMark Brown "CLOCK_BOOTTIME", 4560e76e7aSMark Brown "CLOCK_REALTIME_ALARM", 4660e76e7aSMark Brown "CLOCK_BOOTTIME_ALARM", 4760e76e7aSMark Brown "CLOCK_SGI_CYCLE", 4860e76e7aSMark Brown "CLOCK_TAI", 4960e76e7aSMark Brown }; 50ec049891SVincenzo Frascino 51ec049891SVincenzo Frascino static void vdso_test_gettimeofday(void) 52693f5ca0SVincenzo Frascino { 53693f5ca0SVincenzo Frascino /* Find gettimeofday. */ 54693f5ca0SVincenzo Frascino vdso_gettimeofday_t vdso_gettimeofday = 55693f5ca0SVincenzo Frascino (vdso_gettimeofday_t)vdso_sym(version, name[0]); 56693f5ca0SVincenzo Frascino 57693f5ca0SVincenzo Frascino if (!vdso_gettimeofday) { 5860e76e7aSMark Brown ksft_print_msg("Couldn't find %s\n", name[0]); 5960e76e7aSMark Brown ksft_test_result_skip("%s\n", name[0]); 60ec049891SVincenzo Frascino return; 61693f5ca0SVincenzo Frascino } 62693f5ca0SVincenzo Frascino 63693f5ca0SVincenzo Frascino struct timeval tv; 64693f5ca0SVincenzo Frascino long ret = vdso_gettimeofday(&tv, 0); 65693f5ca0SVincenzo Frascino 66693f5ca0SVincenzo Frascino if (ret == 0) { 67ec049891SVincenzo Frascino ksft_print_msg("The time is %lld.%06lld\n", 68693f5ca0SVincenzo Frascino (long long)tv.tv_sec, (long long)tv.tv_usec); 6960e76e7aSMark Brown ksft_test_result_pass("%s\n", name[0]); 70693f5ca0SVincenzo Frascino } else { 7160e76e7aSMark Brown ksft_test_result_fail("%s\n", name[0]); 72ec049891SVincenzo Frascino } 73693f5ca0SVincenzo Frascino } 74693f5ca0SVincenzo Frascino 75ec049891SVincenzo Frascino static void vdso_test_clock_gettime(clockid_t clk_id) 76693f5ca0SVincenzo Frascino { 77693f5ca0SVincenzo Frascino /* Find clock_gettime. */ 78693f5ca0SVincenzo Frascino vdso_clock_gettime_t vdso_clock_gettime = 79693f5ca0SVincenzo Frascino (vdso_clock_gettime_t)vdso_sym(version, name[1]); 80693f5ca0SVincenzo Frascino 81693f5ca0SVincenzo Frascino if (!vdso_clock_gettime) { 8260e76e7aSMark Brown ksft_print_msg("Couldn't find %s\n", name[1]); 8360e76e7aSMark Brown ksft_test_result_skip("%s %s\n", name[1], 8460e76e7aSMark Brown vdso_clock_name[clk_id]); 85ec049891SVincenzo Frascino return; 86693f5ca0SVincenzo Frascino } 87693f5ca0SVincenzo Frascino 88693f5ca0SVincenzo Frascino struct timespec ts; 89693f5ca0SVincenzo Frascino long ret = vdso_clock_gettime(clk_id, &ts); 90693f5ca0SVincenzo Frascino 91693f5ca0SVincenzo Frascino if (ret == 0) { 92ec049891SVincenzo Frascino ksft_print_msg("The time is %lld.%06lld\n", 93693f5ca0SVincenzo Frascino (long long)ts.tv_sec, (long long)ts.tv_nsec); 9460e76e7aSMark Brown ksft_test_result_pass("%s %s\n", name[1], 9560e76e7aSMark Brown vdso_clock_name[clk_id]); 96693f5ca0SVincenzo Frascino } else { 9760e76e7aSMark Brown ksft_test_result_fail("%s %s\n", name[1], 9860e76e7aSMark Brown vdso_clock_name[clk_id]); 99ec049891SVincenzo Frascino } 100693f5ca0SVincenzo Frascino } 101693f5ca0SVincenzo Frascino 102ec049891SVincenzo Frascino static void vdso_test_time(void) 103693f5ca0SVincenzo Frascino { 104693f5ca0SVincenzo Frascino /* Find time. */ 105693f5ca0SVincenzo Frascino vdso_time_t vdso_time = 106693f5ca0SVincenzo Frascino (vdso_time_t)vdso_sym(version, name[2]); 107693f5ca0SVincenzo Frascino 108693f5ca0SVincenzo Frascino if (!vdso_time) { 10960e76e7aSMark Brown ksft_print_msg("Couldn't find %s\n", name[2]); 11060e76e7aSMark Brown ksft_test_result_skip("%s\n", name[2]); 111ec049891SVincenzo Frascino return; 112693f5ca0SVincenzo Frascino } 113693f5ca0SVincenzo Frascino 114693f5ca0SVincenzo Frascino long ret = vdso_time(NULL); 115693f5ca0SVincenzo Frascino 116693f5ca0SVincenzo Frascino if (ret > 0) { 117ec049891SVincenzo Frascino ksft_print_msg("The time in hours since January 1, 1970 is %lld\n", 118693f5ca0SVincenzo Frascino (long long)(ret / 3600)); 11960e76e7aSMark Brown ksft_test_result_pass("%s\n", name[2]); 120693f5ca0SVincenzo Frascino } else { 12160e76e7aSMark Brown ksft_test_result_fail("%s\n", name[2]); 122ec049891SVincenzo Frascino } 123693f5ca0SVincenzo Frascino } 124693f5ca0SVincenzo Frascino 125ec049891SVincenzo Frascino static void vdso_test_clock_getres(clockid_t clk_id) 126693f5ca0SVincenzo Frascino { 127ec049891SVincenzo Frascino int clock_getres_fail = 0; 128ec049891SVincenzo Frascino 129693f5ca0SVincenzo Frascino /* Find clock_getres. */ 130693f5ca0SVincenzo Frascino vdso_clock_getres_t vdso_clock_getres = 131693f5ca0SVincenzo Frascino (vdso_clock_getres_t)vdso_sym(version, name[3]); 132693f5ca0SVincenzo Frascino 133693f5ca0SVincenzo Frascino if (!vdso_clock_getres) { 13460e76e7aSMark Brown ksft_print_msg("Couldn't find %s\n", name[3]); 13560e76e7aSMark Brown ksft_test_result_skip("%s %s\n", name[3], 13660e76e7aSMark Brown vdso_clock_name[clk_id]); 137ec049891SVincenzo Frascino return; 138693f5ca0SVincenzo Frascino } 139693f5ca0SVincenzo Frascino 140693f5ca0SVincenzo Frascino struct timespec ts, sys_ts; 141693f5ca0SVincenzo Frascino long ret = vdso_clock_getres(clk_id, &ts); 142693f5ca0SVincenzo Frascino 143693f5ca0SVincenzo Frascino if (ret == 0) { 144ec049891SVincenzo Frascino ksft_print_msg("The vdso resolution is %lld %lld\n", 145693f5ca0SVincenzo Frascino (long long)ts.tv_sec, (long long)ts.tv_nsec); 146693f5ca0SVincenzo Frascino } else { 147ec049891SVincenzo Frascino clock_getres_fail++; 148693f5ca0SVincenzo Frascino } 149693f5ca0SVincenzo Frascino 150693f5ca0SVincenzo Frascino ret = syscall(SYS_clock_getres, clk_id, &sys_ts); 151693f5ca0SVincenzo Frascino 152ec049891SVincenzo Frascino ksft_print_msg("The syscall resolution is %lld %lld\n", 153ec049891SVincenzo Frascino (long long)sys_ts.tv_sec, (long long)sys_ts.tv_nsec); 154693f5ca0SVincenzo Frascino 155ec049891SVincenzo Frascino if ((sys_ts.tv_sec != ts.tv_sec) || (sys_ts.tv_nsec != ts.tv_nsec)) 156ec049891SVincenzo Frascino clock_getres_fail++; 157ec049891SVincenzo Frascino 158ec049891SVincenzo Frascino if (clock_getres_fail > 0) { 15960e76e7aSMark Brown ksft_test_result_fail("%s %s\n", name[3], 16060e76e7aSMark Brown vdso_clock_name[clk_id]); 161ec049891SVincenzo Frascino } else { 16260e76e7aSMark Brown ksft_test_result_pass("%s %s\n", name[3], 16360e76e7aSMark Brown vdso_clock_name[clk_id]); 164ec049891SVincenzo Frascino } 165693f5ca0SVincenzo Frascino } 166693f5ca0SVincenzo Frascino 167693f5ca0SVincenzo Frascino /* 168693f5ca0SVincenzo Frascino * This function calls vdso_test_clock_gettime and vdso_test_clock_getres 169693f5ca0SVincenzo Frascino * with different values for clock_id. 170693f5ca0SVincenzo Frascino */ 171ec049891SVincenzo Frascino static inline void vdso_test_clock(clockid_t clock_id) 172693f5ca0SVincenzo Frascino { 173*e63e1354SMark Brown ksft_print_msg("clock_id: %s\n", vdso_clock_name[clock_id]); 174693f5ca0SVincenzo Frascino 175ec049891SVincenzo Frascino vdso_test_clock_gettime(clock_id); 176693f5ca0SVincenzo Frascino 177ec049891SVincenzo Frascino vdso_test_clock_getres(clock_id); 178693f5ca0SVincenzo Frascino } 179693f5ca0SVincenzo Frascino 180ec049891SVincenzo Frascino #define VDSO_TEST_PLAN 16 181ec049891SVincenzo Frascino 182693f5ca0SVincenzo Frascino int main(int argc, char **argv) 183693f5ca0SVincenzo Frascino { 184693f5ca0SVincenzo Frascino unsigned long sysinfo_ehdr = getauxval(AT_SYSINFO_EHDR); 185ec049891SVincenzo Frascino 186ec049891SVincenzo Frascino ksft_print_header(); 187ec049891SVincenzo Frascino ksft_set_plan(VDSO_TEST_PLAN); 188693f5ca0SVincenzo Frascino 189693f5ca0SVincenzo Frascino if (!sysinfo_ehdr) { 190693f5ca0SVincenzo Frascino printf("AT_SYSINFO_EHDR is not present!\n"); 191693f5ca0SVincenzo Frascino return KSFT_SKIP; 192693f5ca0SVincenzo Frascino } 193693f5ca0SVincenzo Frascino 194693f5ca0SVincenzo Frascino version = versions[VDSO_VERSION]; 195693f5ca0SVincenzo Frascino name = (const char **)&names[VDSO_NAMES]; 196693f5ca0SVincenzo Frascino 197693f5ca0SVincenzo Frascino printf("[vDSO kselftest] VDSO_VERSION: %s\n", version); 198693f5ca0SVincenzo Frascino 199693f5ca0SVincenzo Frascino vdso_init_from_sysinfo_ehdr(getauxval(AT_SYSINFO_EHDR)); 200693f5ca0SVincenzo Frascino 201ec049891SVincenzo Frascino vdso_test_gettimeofday(); 202693f5ca0SVincenzo Frascino 203693f5ca0SVincenzo Frascino #if _POSIX_TIMERS > 0 204693f5ca0SVincenzo Frascino 205693f5ca0SVincenzo Frascino #ifdef CLOCK_REALTIME 206ec049891SVincenzo Frascino vdso_test_clock(CLOCK_REALTIME); 207693f5ca0SVincenzo Frascino #endif 208693f5ca0SVincenzo Frascino 209693f5ca0SVincenzo Frascino #ifdef CLOCK_BOOTTIME 210ec049891SVincenzo Frascino vdso_test_clock(CLOCK_BOOTTIME); 211693f5ca0SVincenzo Frascino #endif 212693f5ca0SVincenzo Frascino 213693f5ca0SVincenzo Frascino #ifdef CLOCK_TAI 214ec049891SVincenzo Frascino vdso_test_clock(CLOCK_TAI); 215693f5ca0SVincenzo Frascino #endif 216693f5ca0SVincenzo Frascino 217693f5ca0SVincenzo Frascino #ifdef CLOCK_REALTIME_COARSE 218ec049891SVincenzo Frascino vdso_test_clock(CLOCK_REALTIME_COARSE); 219693f5ca0SVincenzo Frascino #endif 220693f5ca0SVincenzo Frascino 221693f5ca0SVincenzo Frascino #ifdef CLOCK_MONOTONIC 222ec049891SVincenzo Frascino vdso_test_clock(CLOCK_MONOTONIC); 223693f5ca0SVincenzo Frascino #endif 224693f5ca0SVincenzo Frascino 225693f5ca0SVincenzo Frascino #ifdef CLOCK_MONOTONIC_RAW 226ec049891SVincenzo Frascino vdso_test_clock(CLOCK_MONOTONIC_RAW); 227693f5ca0SVincenzo Frascino #endif 228693f5ca0SVincenzo Frascino 229693f5ca0SVincenzo Frascino #ifdef CLOCK_MONOTONIC_COARSE 230ec049891SVincenzo Frascino vdso_test_clock(CLOCK_MONOTONIC_COARSE); 231693f5ca0SVincenzo Frascino #endif 232693f5ca0SVincenzo Frascino 233693f5ca0SVincenzo Frascino #endif 234693f5ca0SVincenzo Frascino 235ec049891SVincenzo Frascino vdso_test_time(); 236693f5ca0SVincenzo Frascino 237ec049891SVincenzo Frascino ksft_print_cnts(); 238ec049891SVincenzo Frascino return ksft_get_fail_cnt() == 0 ? KSFT_PASS : KSFT_FAIL; 239693f5ca0SVincenzo Frascino } 240