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