2020-10-26 14:49:42 +03:00
// SPDX-License-Identifier: GPL-2.0
/*
* vdso_full_test . c : Sample code to test all the timers .
* Copyright ( c ) 2019 Arm Ltd .
*
* Compile with :
* gcc - std = gnu99 vdso_full_test . c parse_vdso . c
*
*/
# include <stdint.h>
# include <elf.h>
# include <stdio.h>
# include <time.h>
# include <sys/auxv.h>
# include <sys/time.h>
# define _GNU_SOURCE
# include <unistd.h>
# include <sys/syscall.h>
# include "../kselftest.h"
# include "vdso_config.h"
extern void * vdso_sym ( const char * version , const char * name ) ;
extern void vdso_init_from_sysinfo_ehdr ( uintptr_t base ) ;
extern void vdso_init_from_auxv ( void * auxv ) ;
static const char * version ;
static const char * * name ;
typedef long ( * vdso_gettimeofday_t ) ( struct timeval * tv , struct timezone * tz ) ;
typedef long ( * vdso_clock_gettime_t ) ( clockid_t clk_id , struct timespec * ts ) ;
typedef long ( * vdso_clock_getres_t ) ( clockid_t clk_id , struct timespec * ts ) ;
typedef time_t ( * vdso_time_t ) ( time_t * t ) ;
2022-01-31 14:34:05 +03:00
# define VDSO_TEST_PASS_MSG() "\n%s(): PASS\n", __func__
# define VDSO_TEST_FAIL_MSG(x) "\n%s(): %s FAIL\n", __func__, x
# define VDSO_TEST_SKIP_MSG(x) "\n%s(): SKIP: Could not find %s\n", __func__, x
static void vdso_test_gettimeofday ( void )
2020-10-26 14:49:42 +03:00
{
/* Find gettimeofday. */
vdso_gettimeofday_t vdso_gettimeofday =
( vdso_gettimeofday_t ) vdso_sym ( version , name [ 0 ] ) ;
if ( ! vdso_gettimeofday ) {
2022-01-31 14:34:05 +03:00
ksft_test_result_skip ( VDSO_TEST_SKIP_MSG ( name [ 0 ] ) ) ;
return ;
2020-10-26 14:49:42 +03:00
}
struct timeval tv ;
long ret = vdso_gettimeofday ( & tv , 0 ) ;
if ( ret = = 0 ) {
2022-01-31 14:34:05 +03:00
ksft_print_msg ( " The time is %lld.%06lld \n " ,
( long long ) tv . tv_sec , ( long long ) tv . tv_usec ) ;
ksft_test_result_pass ( VDSO_TEST_PASS_MSG ( ) ) ;
2020-10-26 14:49:42 +03:00
} else {
2022-01-31 14:34:05 +03:00
ksft_test_result_fail ( VDSO_TEST_FAIL_MSG ( name [ 0 ] ) ) ;
2020-10-26 14:49:42 +03:00
}
}
2022-01-31 14:34:05 +03:00
static void vdso_test_clock_gettime ( clockid_t clk_id )
2020-10-26 14:49:42 +03:00
{
/* Find clock_gettime. */
vdso_clock_gettime_t vdso_clock_gettime =
( vdso_clock_gettime_t ) vdso_sym ( version , name [ 1 ] ) ;
if ( ! vdso_clock_gettime ) {
2022-01-31 14:34:05 +03:00
ksft_test_result_skip ( VDSO_TEST_SKIP_MSG ( name [ 1 ] ) ) ;
return ;
2020-10-26 14:49:42 +03:00
}
struct timespec ts ;
long ret = vdso_clock_gettime ( clk_id , & ts ) ;
if ( ret = = 0 ) {
2022-01-31 14:34:05 +03:00
ksft_print_msg ( " The time is %lld.%06lld \n " ,
( long long ) ts . tv_sec , ( long long ) ts . tv_nsec ) ;
ksft_test_result_pass ( VDSO_TEST_PASS_MSG ( ) ) ;
2020-10-26 14:49:42 +03:00
} else {
2022-01-31 14:34:05 +03:00
ksft_test_result_fail ( VDSO_TEST_FAIL_MSG ( name [ 1 ] ) ) ;
2020-10-26 14:49:42 +03:00
}
}
2022-01-31 14:34:05 +03:00
static void vdso_test_time ( void )
2020-10-26 14:49:42 +03:00
{
/* Find time. */
vdso_time_t vdso_time =
( vdso_time_t ) vdso_sym ( version , name [ 2 ] ) ;
if ( ! vdso_time ) {
2022-01-31 14:34:05 +03:00
ksft_test_result_skip ( VDSO_TEST_SKIP_MSG ( name [ 2 ] ) ) ;
return ;
2020-10-26 14:49:42 +03:00
}
long ret = vdso_time ( NULL ) ;
if ( ret > 0 ) {
2022-01-31 14:34:05 +03:00
ksft_print_msg ( " The time in hours since January 1, 1970 is %lld \n " ,
2020-10-26 14:49:42 +03:00
( long long ) ( ret / 3600 ) ) ;
2022-01-31 14:34:05 +03:00
ksft_test_result_pass ( VDSO_TEST_PASS_MSG ( ) ) ;
2020-10-26 14:49:42 +03:00
} else {
2022-01-31 14:34:05 +03:00
ksft_test_result_fail ( VDSO_TEST_FAIL_MSG ( name [ 2 ] ) ) ;
2020-10-26 14:49:42 +03:00
}
}
2022-01-31 14:34:05 +03:00
static void vdso_test_clock_getres ( clockid_t clk_id )
2020-10-26 14:49:42 +03:00
{
2022-01-31 14:34:05 +03:00
int clock_getres_fail = 0 ;
2020-10-26 14:49:42 +03:00
/* Find clock_getres. */
vdso_clock_getres_t vdso_clock_getres =
( vdso_clock_getres_t ) vdso_sym ( version , name [ 3 ] ) ;
if ( ! vdso_clock_getres ) {
2022-01-31 14:34:05 +03:00
ksft_test_result_skip ( VDSO_TEST_SKIP_MSG ( name [ 3 ] ) ) ;
return ;
2020-10-26 14:49:42 +03:00
}
struct timespec ts , sys_ts ;
long ret = vdso_clock_getres ( clk_id , & ts ) ;
if ( ret = = 0 ) {
2022-01-31 14:34:05 +03:00
ksft_print_msg ( " The vdso resolution is %lld %lld \n " ,
( long long ) ts . tv_sec , ( long long ) ts . tv_nsec ) ;
2020-10-26 14:49:42 +03:00
} else {
2022-01-31 14:34:05 +03:00
clock_getres_fail + + ;
2020-10-26 14:49:42 +03:00
}
ret = syscall ( SYS_clock_getres , clk_id , & sys_ts ) ;
2022-01-31 14:34:05 +03:00
ksft_print_msg ( " The syscall resolution is %lld %lld \n " ,
( long long ) sys_ts . tv_sec , ( long long ) sys_ts . tv_nsec ) ;
2020-10-26 14:49:42 +03:00
2022-01-31 14:34:05 +03:00
if ( ( sys_ts . tv_sec ! = ts . tv_sec ) | | ( sys_ts . tv_nsec ! = ts . tv_nsec ) )
clock_getres_fail + + ;
if ( clock_getres_fail > 0 ) {
ksft_test_result_fail ( VDSO_TEST_FAIL_MSG ( name [ 3 ] ) ) ;
} else {
ksft_test_result_pass ( VDSO_TEST_PASS_MSG ( ) ) ;
}
2020-10-26 14:49:42 +03:00
}
const char * vdso_clock_name [ 12 ] = {
" CLOCK_REALTIME " ,
" CLOCK_MONOTONIC " ,
" CLOCK_PROCESS_CPUTIME_ID " ,
" CLOCK_THREAD_CPUTIME_ID " ,
" CLOCK_MONOTONIC_RAW " ,
" CLOCK_REALTIME_COARSE " ,
" CLOCK_MONOTONIC_COARSE " ,
" CLOCK_BOOTTIME " ,
" CLOCK_REALTIME_ALARM " ,
" CLOCK_BOOTTIME_ALARM " ,
" CLOCK_SGI_CYCLE " ,
" CLOCK_TAI " ,
} ;
/*
* This function calls vdso_test_clock_gettime and vdso_test_clock_getres
* with different values for clock_id .
*/
2022-01-31 14:34:05 +03:00
static inline void vdso_test_clock ( clockid_t clock_id )
2020-10-26 14:49:42 +03:00
{
2022-01-31 14:34:05 +03:00
ksft_print_msg ( " \n clock_id: %s \n " , vdso_clock_name [ clock_id ] ) ;
2020-10-26 14:49:42 +03:00
2022-01-31 14:34:05 +03:00
vdso_test_clock_gettime ( clock_id ) ;
2020-10-26 14:49:42 +03:00
2022-01-31 14:34:05 +03:00
vdso_test_clock_getres ( clock_id ) ;
2020-10-26 14:49:42 +03:00
}
2022-01-31 14:34:05 +03:00
# define VDSO_TEST_PLAN 16
2020-10-26 14:49:42 +03:00
int main ( int argc , char * * argv )
{
unsigned long sysinfo_ehdr = getauxval ( AT_SYSINFO_EHDR ) ;
2022-01-31 14:34:05 +03:00
ksft_print_header ( ) ;
ksft_set_plan ( VDSO_TEST_PLAN ) ;
2020-10-26 14:49:42 +03:00
if ( ! sysinfo_ehdr ) {
printf ( " AT_SYSINFO_EHDR is not present! \n " ) ;
return KSFT_SKIP ;
}
version = versions [ VDSO_VERSION ] ;
name = ( const char * * ) & names [ VDSO_NAMES ] ;
printf ( " [vDSO kselftest] VDSO_VERSION: %s \n " , version ) ;
vdso_init_from_sysinfo_ehdr ( getauxval ( AT_SYSINFO_EHDR ) ) ;
2022-01-31 14:34:05 +03:00
vdso_test_gettimeofday ( ) ;
2020-10-26 14:49:42 +03:00
# if _POSIX_TIMERS > 0
# ifdef CLOCK_REALTIME
2022-01-31 14:34:05 +03:00
vdso_test_clock ( CLOCK_REALTIME ) ;
2020-10-26 14:49:42 +03:00
# endif
# ifdef CLOCK_BOOTTIME
2022-01-31 14:34:05 +03:00
vdso_test_clock ( CLOCK_BOOTTIME ) ;
2020-10-26 14:49:42 +03:00
# endif
# ifdef CLOCK_TAI
2022-01-31 14:34:05 +03:00
vdso_test_clock ( CLOCK_TAI ) ;
2020-10-26 14:49:42 +03:00
# endif
# ifdef CLOCK_REALTIME_COARSE
2022-01-31 14:34:05 +03:00
vdso_test_clock ( CLOCK_REALTIME_COARSE ) ;
2020-10-26 14:49:42 +03:00
# endif
# ifdef CLOCK_MONOTONIC
2022-01-31 14:34:05 +03:00
vdso_test_clock ( CLOCK_MONOTONIC ) ;
2020-10-26 14:49:42 +03:00
# endif
# ifdef CLOCK_MONOTONIC_RAW
2022-01-31 14:34:05 +03:00
vdso_test_clock ( CLOCK_MONOTONIC_RAW ) ;
2020-10-26 14:49:42 +03:00
# endif
# ifdef CLOCK_MONOTONIC_COARSE
2022-01-31 14:34:05 +03:00
vdso_test_clock ( CLOCK_MONOTONIC_COARSE ) ;
2020-10-26 14:49:42 +03:00
# endif
# endif
2022-01-31 14:34:05 +03:00
vdso_test_time ( ) ;
2020-10-26 14:49:42 +03:00
2022-01-31 14:34:05 +03:00
ksft_print_cnts ( ) ;
return ksft_get_fail_cnt ( ) = = 0 ? KSFT_PASS : KSFT_FAIL ;
2020-10-26 14:49:42 +03:00
}