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
  36static int vdso_test_gettimeofday(void)
  37{
  38        /* Find gettimeofday. */
  39        vdso_gettimeofday_t vdso_gettimeofday =
  40                (vdso_gettimeofday_t)vdso_sym(version, name[0]);
  41
  42        if (!vdso_gettimeofday) {
  43                printf("Could not find %s\n", name[0]);
  44                return KSFT_SKIP;
  45        }
  46
  47        struct timeval tv;
  48        long ret = vdso_gettimeofday(&tv, 0);
  49
  50        if (ret == 0) {
  51                printf("The time is %lld.%06lld\n",
  52                       (long long)tv.tv_sec, (long long)tv.tv_usec);
  53        } else {
  54                printf("%s failed\n", name[0]);
  55                return KSFT_FAIL;
  56        }
  57
  58        return KSFT_PASS;
  59}
  60
  61static int vdso_test_clock_gettime(clockid_t clk_id)
  62{
  63        /* Find clock_gettime. */
  64        vdso_clock_gettime_t vdso_clock_gettime =
  65                (vdso_clock_gettime_t)vdso_sym(version, name[1]);
  66
  67        if (!vdso_clock_gettime) {
  68                printf("Could not find %s\n", name[1]);
  69                return KSFT_SKIP;
  70        }
  71
  72        struct timespec ts;
  73        long ret = vdso_clock_gettime(clk_id, &ts);
  74
  75        if (ret == 0) {
  76                printf("The time is %lld.%06lld\n",
  77                       (long long)ts.tv_sec, (long long)ts.tv_nsec);
  78        } else {
  79                printf("%s failed\n", name[1]);
  80                return KSFT_FAIL;
  81        }
  82
  83        return KSFT_PASS;
  84}
  85
  86static int 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                printf("Could not find %s\n", name[2]);
  94                return KSFT_SKIP;
  95        }
  96
  97        long ret = vdso_time(NULL);
  98
  99        if (ret > 0) {
 100                printf("The time in hours since January 1, 1970 is %lld\n",
 101                                (long long)(ret / 3600));
 102        } else {
 103                printf("%s failed\n", name[2]);
 104                return KSFT_FAIL;
 105        }
 106
 107        return KSFT_PASS;
 108}
 109
 110static int vdso_test_clock_getres(clockid_t clk_id)
 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                printf("Could not find %s\n", name[3]);
 118                return KSFT_SKIP;
 119        }
 120
 121        struct timespec ts, sys_ts;
 122        long ret = vdso_clock_getres(clk_id, &ts);
 123
 124        if (ret == 0) {
 125                printf("The resolution is %lld %lld\n",
 126                       (long long)ts.tv_sec, (long long)ts.tv_nsec);
 127        } else {
 128                printf("%s failed\n", name[3]);
 129                return KSFT_FAIL;
 130        }
 131
 132        ret = syscall(SYS_clock_getres, clk_id, &sys_ts);
 133
 134        if ((sys_ts.tv_sec != ts.tv_sec) || (sys_ts.tv_nsec != ts.tv_nsec)) {
 135                printf("%s failed\n", name[3]);
 136                return KSFT_FAIL;
 137        }
 138
 139        return KSFT_PASS;
 140}
 141
 142const char *vdso_clock_name[12] = {
 143        "CLOCK_REALTIME",
 144        "CLOCK_MONOTONIC",
 145        "CLOCK_PROCESS_CPUTIME_ID",
 146        "CLOCK_THREAD_CPUTIME_ID",
 147        "CLOCK_MONOTONIC_RAW",
 148        "CLOCK_REALTIME_COARSE",
 149        "CLOCK_MONOTONIC_COARSE",
 150        "CLOCK_BOOTTIME",
 151        "CLOCK_REALTIME_ALARM",
 152        "CLOCK_BOOTTIME_ALARM",
 153        "CLOCK_SGI_CYCLE",
 154        "CLOCK_TAI",
 155};
 156
 157/*
 158 * This function calls vdso_test_clock_gettime and vdso_test_clock_getres
 159 * with different values for clock_id.
 160 */
 161static inline int vdso_test_clock(clockid_t clock_id)
 162{
 163        int ret0, ret1;
 164
 165        ret0 = vdso_test_clock_gettime(clock_id);
 166        /* A skipped test is considered passed */
 167        if (ret0 == KSFT_SKIP)
 168                ret0 = KSFT_PASS;
 169
 170        ret1 = vdso_test_clock_getres(clock_id);
 171        /* A skipped test is considered passed */
 172        if (ret1 == KSFT_SKIP)
 173                ret1 = KSFT_PASS;
 174
 175        ret0 += ret1;
 176
 177        printf("clock_id: %s", vdso_clock_name[clock_id]);
 178
 179        if (ret0 > 0)
 180                printf(" [FAIL]\n");
 181        else
 182                printf(" [PASS]\n");
 183
 184        return ret0;
 185}
 186
 187int main(int argc, char **argv)
 188{
 189        unsigned long sysinfo_ehdr = getauxval(AT_SYSINFO_EHDR);
 190        int ret;
 191
 192        if (!sysinfo_ehdr) {
 193                printf("AT_SYSINFO_EHDR is not present!\n");
 194                return KSFT_SKIP;
 195        }
 196
 197        version = versions[VDSO_VERSION];
 198        name = (const char **)&names[VDSO_NAMES];
 199
 200        printf("[vDSO kselftest] VDSO_VERSION: %s\n", version);
 201
 202        vdso_init_from_sysinfo_ehdr(getauxval(AT_SYSINFO_EHDR));
 203
 204        ret = vdso_test_gettimeofday();
 205
 206#if _POSIX_TIMERS > 0
 207
 208#ifdef CLOCK_REALTIME
 209        ret += vdso_test_clock(CLOCK_REALTIME);
 210#endif
 211
 212#ifdef CLOCK_BOOTTIME
 213        ret += vdso_test_clock(CLOCK_BOOTTIME);
 214#endif
 215
 216#ifdef CLOCK_TAI
 217        ret += vdso_test_clock(CLOCK_TAI);
 218#endif
 219
 220#ifdef CLOCK_REALTIME_COARSE
 221        ret += vdso_test_clock(CLOCK_REALTIME_COARSE);
 222#endif
 223
 224#ifdef CLOCK_MONOTONIC
 225        ret += vdso_test_clock(CLOCK_MONOTONIC);
 226#endif
 227
 228#ifdef CLOCK_MONOTONIC_RAW
 229        ret += vdso_test_clock(CLOCK_MONOTONIC_RAW);
 230#endif
 231
 232#ifdef CLOCK_MONOTONIC_COARSE
 233        ret += vdso_test_clock(CLOCK_MONOTONIC_COARSE);
 234#endif
 235
 236#endif
 237
 238        ret += vdso_test_time();
 239
 240        if (ret > 0)
 241                return KSFT_FAIL;
 242
 243        return KSFT_PASS;
 244}
 245