162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * vdso_full_test.c: Sample code to test all the timers. 462306a36Sopenharmony_ci * Copyright (c) 2019 Arm Ltd. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Compile with: 762306a36Sopenharmony_ci * gcc -std=gnu99 vdso_full_test.c parse_vdso.c 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <stdint.h> 1262306a36Sopenharmony_ci#include <elf.h> 1362306a36Sopenharmony_ci#include <stdio.h> 1462306a36Sopenharmony_ci#include <time.h> 1562306a36Sopenharmony_ci#include <sys/auxv.h> 1662306a36Sopenharmony_ci#include <sys/time.h> 1762306a36Sopenharmony_ci#define _GNU_SOURCE 1862306a36Sopenharmony_ci#include <unistd.h> 1962306a36Sopenharmony_ci#include <sys/syscall.h> 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#include "../kselftest.h" 2262306a36Sopenharmony_ci#include "vdso_config.h" 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ciextern void *vdso_sym(const char *version, const char *name); 2562306a36Sopenharmony_ciextern void vdso_init_from_sysinfo_ehdr(uintptr_t base); 2662306a36Sopenharmony_ciextern void vdso_init_from_auxv(void *auxv); 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_cistatic const char *version; 2962306a36Sopenharmony_cistatic const char **name; 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_citypedef long (*vdso_gettimeofday_t)(struct timeval *tv, struct timezone *tz); 3262306a36Sopenharmony_citypedef long (*vdso_clock_gettime_t)(clockid_t clk_id, struct timespec *ts); 3362306a36Sopenharmony_citypedef long (*vdso_clock_getres_t)(clockid_t clk_id, struct timespec *ts); 3462306a36Sopenharmony_citypedef time_t (*vdso_time_t)(time_t *t); 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci#define VDSO_TEST_PASS_MSG() "\n%s(): PASS\n", __func__ 3762306a36Sopenharmony_ci#define VDSO_TEST_FAIL_MSG(x) "\n%s(): %s FAIL\n", __func__, x 3862306a36Sopenharmony_ci#define VDSO_TEST_SKIP_MSG(x) "\n%s(): SKIP: Could not find %s\n", __func__, x 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_cistatic void vdso_test_gettimeofday(void) 4162306a36Sopenharmony_ci{ 4262306a36Sopenharmony_ci /* Find gettimeofday. */ 4362306a36Sopenharmony_ci vdso_gettimeofday_t vdso_gettimeofday = 4462306a36Sopenharmony_ci (vdso_gettimeofday_t)vdso_sym(version, name[0]); 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci if (!vdso_gettimeofday) { 4762306a36Sopenharmony_ci ksft_test_result_skip(VDSO_TEST_SKIP_MSG(name[0])); 4862306a36Sopenharmony_ci return; 4962306a36Sopenharmony_ci } 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci struct timeval tv; 5262306a36Sopenharmony_ci long ret = vdso_gettimeofday(&tv, 0); 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci if (ret == 0) { 5562306a36Sopenharmony_ci ksft_print_msg("The time is %lld.%06lld\n", 5662306a36Sopenharmony_ci (long long)tv.tv_sec, (long long)tv.tv_usec); 5762306a36Sopenharmony_ci ksft_test_result_pass(VDSO_TEST_PASS_MSG()); 5862306a36Sopenharmony_ci } else { 5962306a36Sopenharmony_ci ksft_test_result_fail(VDSO_TEST_FAIL_MSG(name[0])); 6062306a36Sopenharmony_ci } 6162306a36Sopenharmony_ci} 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_cistatic void vdso_test_clock_gettime(clockid_t clk_id) 6462306a36Sopenharmony_ci{ 6562306a36Sopenharmony_ci /* Find clock_gettime. */ 6662306a36Sopenharmony_ci vdso_clock_gettime_t vdso_clock_gettime = 6762306a36Sopenharmony_ci (vdso_clock_gettime_t)vdso_sym(version, name[1]); 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci if (!vdso_clock_gettime) { 7062306a36Sopenharmony_ci ksft_test_result_skip(VDSO_TEST_SKIP_MSG(name[1])); 7162306a36Sopenharmony_ci return; 7262306a36Sopenharmony_ci } 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci struct timespec ts; 7562306a36Sopenharmony_ci long ret = vdso_clock_gettime(clk_id, &ts); 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci if (ret == 0) { 7862306a36Sopenharmony_ci ksft_print_msg("The time is %lld.%06lld\n", 7962306a36Sopenharmony_ci (long long)ts.tv_sec, (long long)ts.tv_nsec); 8062306a36Sopenharmony_ci ksft_test_result_pass(VDSO_TEST_PASS_MSG()); 8162306a36Sopenharmony_ci } else { 8262306a36Sopenharmony_ci ksft_test_result_fail(VDSO_TEST_FAIL_MSG(name[1])); 8362306a36Sopenharmony_ci } 8462306a36Sopenharmony_ci} 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_cistatic void vdso_test_time(void) 8762306a36Sopenharmony_ci{ 8862306a36Sopenharmony_ci /* Find time. */ 8962306a36Sopenharmony_ci vdso_time_t vdso_time = 9062306a36Sopenharmony_ci (vdso_time_t)vdso_sym(version, name[2]); 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci if (!vdso_time) { 9362306a36Sopenharmony_ci ksft_test_result_skip(VDSO_TEST_SKIP_MSG(name[2])); 9462306a36Sopenharmony_ci return; 9562306a36Sopenharmony_ci } 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci long ret = vdso_time(NULL); 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci if (ret > 0) { 10062306a36Sopenharmony_ci ksft_print_msg("The time in hours since January 1, 1970 is %lld\n", 10162306a36Sopenharmony_ci (long long)(ret / 3600)); 10262306a36Sopenharmony_ci ksft_test_result_pass(VDSO_TEST_PASS_MSG()); 10362306a36Sopenharmony_ci } else { 10462306a36Sopenharmony_ci ksft_test_result_fail(VDSO_TEST_FAIL_MSG(name[2])); 10562306a36Sopenharmony_ci } 10662306a36Sopenharmony_ci} 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_cistatic void vdso_test_clock_getres(clockid_t clk_id) 10962306a36Sopenharmony_ci{ 11062306a36Sopenharmony_ci int clock_getres_fail = 0; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci /* Find clock_getres. */ 11362306a36Sopenharmony_ci vdso_clock_getres_t vdso_clock_getres = 11462306a36Sopenharmony_ci (vdso_clock_getres_t)vdso_sym(version, name[3]); 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci if (!vdso_clock_getres) { 11762306a36Sopenharmony_ci ksft_test_result_skip(VDSO_TEST_SKIP_MSG(name[3])); 11862306a36Sopenharmony_ci return; 11962306a36Sopenharmony_ci } 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci struct timespec ts, sys_ts; 12262306a36Sopenharmony_ci long ret = vdso_clock_getres(clk_id, &ts); 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci if (ret == 0) { 12562306a36Sopenharmony_ci ksft_print_msg("The vdso resolution is %lld %lld\n", 12662306a36Sopenharmony_ci (long long)ts.tv_sec, (long long)ts.tv_nsec); 12762306a36Sopenharmony_ci } else { 12862306a36Sopenharmony_ci clock_getres_fail++; 12962306a36Sopenharmony_ci } 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci ret = syscall(SYS_clock_getres, clk_id, &sys_ts); 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci ksft_print_msg("The syscall resolution is %lld %lld\n", 13462306a36Sopenharmony_ci (long long)sys_ts.tv_sec, (long long)sys_ts.tv_nsec); 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci if ((sys_ts.tv_sec != ts.tv_sec) || (sys_ts.tv_nsec != ts.tv_nsec)) 13762306a36Sopenharmony_ci clock_getres_fail++; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci if (clock_getres_fail > 0) { 14062306a36Sopenharmony_ci ksft_test_result_fail(VDSO_TEST_FAIL_MSG(name[3])); 14162306a36Sopenharmony_ci } else { 14262306a36Sopenharmony_ci ksft_test_result_pass(VDSO_TEST_PASS_MSG()); 14362306a36Sopenharmony_ci } 14462306a36Sopenharmony_ci} 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ciconst char *vdso_clock_name[12] = { 14762306a36Sopenharmony_ci "CLOCK_REALTIME", 14862306a36Sopenharmony_ci "CLOCK_MONOTONIC", 14962306a36Sopenharmony_ci "CLOCK_PROCESS_CPUTIME_ID", 15062306a36Sopenharmony_ci "CLOCK_THREAD_CPUTIME_ID", 15162306a36Sopenharmony_ci "CLOCK_MONOTONIC_RAW", 15262306a36Sopenharmony_ci "CLOCK_REALTIME_COARSE", 15362306a36Sopenharmony_ci "CLOCK_MONOTONIC_COARSE", 15462306a36Sopenharmony_ci "CLOCK_BOOTTIME", 15562306a36Sopenharmony_ci "CLOCK_REALTIME_ALARM", 15662306a36Sopenharmony_ci "CLOCK_BOOTTIME_ALARM", 15762306a36Sopenharmony_ci "CLOCK_SGI_CYCLE", 15862306a36Sopenharmony_ci "CLOCK_TAI", 15962306a36Sopenharmony_ci}; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci/* 16262306a36Sopenharmony_ci * This function calls vdso_test_clock_gettime and vdso_test_clock_getres 16362306a36Sopenharmony_ci * with different values for clock_id. 16462306a36Sopenharmony_ci */ 16562306a36Sopenharmony_cistatic inline void vdso_test_clock(clockid_t clock_id) 16662306a36Sopenharmony_ci{ 16762306a36Sopenharmony_ci ksft_print_msg("\nclock_id: %s\n", vdso_clock_name[clock_id]); 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci vdso_test_clock_gettime(clock_id); 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci vdso_test_clock_getres(clock_id); 17262306a36Sopenharmony_ci} 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci#define VDSO_TEST_PLAN 16 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ciint main(int argc, char **argv) 17762306a36Sopenharmony_ci{ 17862306a36Sopenharmony_ci unsigned long sysinfo_ehdr = getauxval(AT_SYSINFO_EHDR); 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci ksft_print_header(); 18162306a36Sopenharmony_ci ksft_set_plan(VDSO_TEST_PLAN); 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci if (!sysinfo_ehdr) { 18462306a36Sopenharmony_ci printf("AT_SYSINFO_EHDR is not present!\n"); 18562306a36Sopenharmony_ci return KSFT_SKIP; 18662306a36Sopenharmony_ci } 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci version = versions[VDSO_VERSION]; 18962306a36Sopenharmony_ci name = (const char **)&names[VDSO_NAMES]; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci printf("[vDSO kselftest] VDSO_VERSION: %s\n", version); 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci vdso_init_from_sysinfo_ehdr(getauxval(AT_SYSINFO_EHDR)); 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci vdso_test_gettimeofday(); 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci#if _POSIX_TIMERS > 0 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci#ifdef CLOCK_REALTIME 20062306a36Sopenharmony_ci vdso_test_clock(CLOCK_REALTIME); 20162306a36Sopenharmony_ci#endif 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci#ifdef CLOCK_BOOTTIME 20462306a36Sopenharmony_ci vdso_test_clock(CLOCK_BOOTTIME); 20562306a36Sopenharmony_ci#endif 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci#ifdef CLOCK_TAI 20862306a36Sopenharmony_ci vdso_test_clock(CLOCK_TAI); 20962306a36Sopenharmony_ci#endif 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci#ifdef CLOCK_REALTIME_COARSE 21262306a36Sopenharmony_ci vdso_test_clock(CLOCK_REALTIME_COARSE); 21362306a36Sopenharmony_ci#endif 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci#ifdef CLOCK_MONOTONIC 21662306a36Sopenharmony_ci vdso_test_clock(CLOCK_MONOTONIC); 21762306a36Sopenharmony_ci#endif 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci#ifdef CLOCK_MONOTONIC_RAW 22062306a36Sopenharmony_ci vdso_test_clock(CLOCK_MONOTONIC_RAW); 22162306a36Sopenharmony_ci#endif 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci#ifdef CLOCK_MONOTONIC_COARSE 22462306a36Sopenharmony_ci vdso_test_clock(CLOCK_MONOTONIC_COARSE); 22562306a36Sopenharmony_ci#endif 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci#endif 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci vdso_test_time(); 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci ksft_print_cnts(); 23262306a36Sopenharmony_ci return ksft_get_fail_cnt() == 0 ? KSFT_PASS : KSFT_FAIL; 23362306a36Sopenharmony_ci} 234