1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 2f08c3bdfSopenharmony_ci/* 3f08c3bdfSopenharmony_ci * Copyright (c) 2020 Linaro Limited. All rights reserved. 4f08c3bdfSopenharmony_ci * Author: Viresh Kumar<viresh.kumar@linaro.org> 5f08c3bdfSopenharmony_ci */ 6f08c3bdfSopenharmony_ci 7f08c3bdfSopenharmony_ci/*\ 8f08c3bdfSopenharmony_ci * [Description] 9f08c3bdfSopenharmony_ci * 10f08c3bdfSopenharmony_ci * Check time difference between successive readings and report a bug if 11f08c3bdfSopenharmony_ci * difference found to be over 5 ms. 12f08c3bdfSopenharmony_ci * 13f08c3bdfSopenharmony_ci * This test reports a s390x BUG which has been fixed in: 14f08c3bdfSopenharmony_ci * 15f08c3bdfSopenharmony_ci * commit 5b43bd184530af6b868d8273b0a743a138d37ee8 16f08c3bdfSopenharmony_ci * Author: Heiko Carstens <hca@linux.ibm.com> 17f08c3bdfSopenharmony_ci * Date: Wed Mar 24 20:23:55 2021 +0100 18f08c3bdfSopenharmony_ci * 19f08c3bdfSopenharmony_ci * s390/vdso: fix initializing and updating of vdso_data 20f08c3bdfSopenharmony_ci */ 21f08c3bdfSopenharmony_ci 22f08c3bdfSopenharmony_ci#include "config.h" 23f08c3bdfSopenharmony_ci#include "parse_vdso.h" 24f08c3bdfSopenharmony_ci#include "time64_variants.h" 25f08c3bdfSopenharmony_ci#include "tst_timer.h" 26f08c3bdfSopenharmony_ci#include "tst_safe_clocks.h" 27f08c3bdfSopenharmony_ci 28f08c3bdfSopenharmony_ciclockid_t clks[] = { 29f08c3bdfSopenharmony_ci CLOCK_REALTIME, 30f08c3bdfSopenharmony_ci CLOCK_REALTIME_COARSE, 31f08c3bdfSopenharmony_ci CLOCK_MONOTONIC, 32f08c3bdfSopenharmony_ci CLOCK_MONOTONIC_COARSE, 33f08c3bdfSopenharmony_ci CLOCK_MONOTONIC_RAW, 34f08c3bdfSopenharmony_ci CLOCK_BOOTTIME, 35f08c3bdfSopenharmony_ci}; 36f08c3bdfSopenharmony_ci 37f08c3bdfSopenharmony_cistatic gettime_t ptr_vdso_gettime, ptr_vdso_gettime64; 38f08c3bdfSopenharmony_cistatic long long delta, precise_delta, coarse_delta; 39f08c3bdfSopenharmony_ci 40f08c3bdfSopenharmony_cistatic inline int do_vdso_gettime(gettime_t vdso, clockid_t clk_id, void *ts) 41f08c3bdfSopenharmony_ci{ 42f08c3bdfSopenharmony_ci if (!vdso) { 43f08c3bdfSopenharmony_ci errno = ENOSYS; 44f08c3bdfSopenharmony_ci return -1; 45f08c3bdfSopenharmony_ci } 46f08c3bdfSopenharmony_ci 47f08c3bdfSopenharmony_ci return vdso(clk_id, ts); 48f08c3bdfSopenharmony_ci} 49f08c3bdfSopenharmony_ci 50f08c3bdfSopenharmony_cistatic inline int vdso_gettime(clockid_t clk_id, void *ts) 51f08c3bdfSopenharmony_ci{ 52f08c3bdfSopenharmony_ci return do_vdso_gettime(ptr_vdso_gettime, clk_id, ts); 53f08c3bdfSopenharmony_ci} 54f08c3bdfSopenharmony_ci 55f08c3bdfSopenharmony_cistatic inline int vdso_gettime64(clockid_t clk_id, void *ts) 56f08c3bdfSopenharmony_ci{ 57f08c3bdfSopenharmony_ci return do_vdso_gettime(ptr_vdso_gettime64, clk_id, ts); 58f08c3bdfSopenharmony_ci} 59f08c3bdfSopenharmony_ci 60f08c3bdfSopenharmony_cistatic inline int my_gettimeofday(clockid_t clk_id, void *ts) 61f08c3bdfSopenharmony_ci{ 62f08c3bdfSopenharmony_ci struct timeval tval; 63f08c3bdfSopenharmony_ci 64f08c3bdfSopenharmony_ci if (clk_id != CLOCK_REALTIME) 65f08c3bdfSopenharmony_ci tst_brk(TBROK, "%s: Invalid clk_id, exiting", tst_clock_name(clk_id)); 66f08c3bdfSopenharmony_ci 67f08c3bdfSopenharmony_ci if (gettimeofday(&tval, NULL) < 0) 68f08c3bdfSopenharmony_ci tst_brk(TBROK | TERRNO, "gettimeofday() failed"); 69f08c3bdfSopenharmony_ci 70f08c3bdfSopenharmony_ci /* 71f08c3bdfSopenharmony_ci * The array defines the type to TST_LIBC_TIMESPEC and so we can cast 72f08c3bdfSopenharmony_ci * this into struct timespec. 73f08c3bdfSopenharmony_ci */ 74f08c3bdfSopenharmony_ci *((struct timespec *)ts) = tst_timespec_from_us(tst_timeval_to_us(tval)); 75f08c3bdfSopenharmony_ci return 0; 76f08c3bdfSopenharmony_ci} 77f08c3bdfSopenharmony_ci 78f08c3bdfSopenharmony_cistatic struct time64_variants variants[] = { 79f08c3bdfSopenharmony_ci { .clock_gettime = libc_clock_gettime, .ts_type = TST_LIBC_TIMESPEC, .desc = "vDSO or syscall with libc spec"}, 80f08c3bdfSopenharmony_ci 81f08c3bdfSopenharmony_ci#if (__NR_clock_gettime != __LTP__NR_INVALID_SYSCALL) 82f08c3bdfSopenharmony_ci { .clock_gettime = sys_clock_gettime, .ts_type = TST_KERN_OLD_TIMESPEC, .desc = "syscall with old kernel spec"}, 83f08c3bdfSopenharmony_ci { .clock_gettime = vdso_gettime, .ts_type = TST_KERN_OLD_TIMESPEC, .desc = "vDSO with old kernel spec"}, 84f08c3bdfSopenharmony_ci#endif 85f08c3bdfSopenharmony_ci 86f08c3bdfSopenharmony_ci#if (__NR_clock_gettime64 != __LTP__NR_INVALID_SYSCALL) 87f08c3bdfSopenharmony_ci { .clock_gettime = sys_clock_gettime64, .ts_type = TST_KERN_TIMESPEC, .desc = "syscall time64 with kernel spec"}, 88f08c3bdfSopenharmony_ci { .clock_gettime = vdso_gettime64, .ts_type = TST_KERN_TIMESPEC, .desc = "vDSO time64 with kernel spec"}, 89f08c3bdfSopenharmony_ci#endif 90f08c3bdfSopenharmony_ci { .clock_gettime = my_gettimeofday, .ts_type = TST_LIBC_TIMESPEC, .desc = "gettimeofday"}, 91f08c3bdfSopenharmony_ci}; 92f08c3bdfSopenharmony_ci 93f08c3bdfSopenharmony_cistatic void setup(void) 94f08c3bdfSopenharmony_ci{ 95f08c3bdfSopenharmony_ci struct timespec res; 96f08c3bdfSopenharmony_ci 97f08c3bdfSopenharmony_ci clock_getres(CLOCK_REALTIME, &res); 98f08c3bdfSopenharmony_ci precise_delta = 5 + res.tv_nsec / 1000000; 99f08c3bdfSopenharmony_ci 100f08c3bdfSopenharmony_ci clock_getres(CLOCK_REALTIME_COARSE, &res); 101f08c3bdfSopenharmony_ci coarse_delta = 5 + res.tv_nsec / 1000000; 102f08c3bdfSopenharmony_ci 103f08c3bdfSopenharmony_ci if (tst_is_virt(VIRT_ANY)) { 104f08c3bdfSopenharmony_ci tst_res(TINFO, "Running in a virtual machine, multiply the delta by 10."); 105f08c3bdfSopenharmony_ci precise_delta *= 10; 106f08c3bdfSopenharmony_ci coarse_delta *= 10; 107f08c3bdfSopenharmony_ci } 108f08c3bdfSopenharmony_ci 109f08c3bdfSopenharmony_ci find_clock_gettime_vdso(&ptr_vdso_gettime, &ptr_vdso_gettime64); 110f08c3bdfSopenharmony_ci} 111f08c3bdfSopenharmony_ci 112f08c3bdfSopenharmony_cistatic void run(unsigned int i) 113f08c3bdfSopenharmony_ci{ 114f08c3bdfSopenharmony_ci struct tst_ts ts; 115f08c3bdfSopenharmony_ci long long start, end = 0, diff, slack; 116f08c3bdfSopenharmony_ci struct time64_variants *tv; 117f08c3bdfSopenharmony_ci int count = 10000, ret; 118f08c3bdfSopenharmony_ci unsigned int j; 119f08c3bdfSopenharmony_ci 120f08c3bdfSopenharmony_ci if (clks[i] == CLOCK_REALTIME_COARSE || clks[i] == CLOCK_MONOTONIC_COARSE) 121f08c3bdfSopenharmony_ci delta = coarse_delta; 122f08c3bdfSopenharmony_ci else 123f08c3bdfSopenharmony_ci delta = precise_delta; 124f08c3bdfSopenharmony_ci 125f08c3bdfSopenharmony_ci do { 126f08c3bdfSopenharmony_ci for (j = 0; j < ARRAY_SIZE(variants); j++) { 127f08c3bdfSopenharmony_ci /* Refresh time in start */ 128f08c3bdfSopenharmony_ci start = end; 129f08c3bdfSopenharmony_ci 130f08c3bdfSopenharmony_ci tv = &variants[j]; 131f08c3bdfSopenharmony_ci ts.type = tv->ts_type; 132f08c3bdfSopenharmony_ci 133f08c3bdfSopenharmony_ci /* Do gettimeofday() test only for CLOCK_REALTIME */ 134f08c3bdfSopenharmony_ci if (tv->clock_gettime == my_gettimeofday && clks[i] != CLOCK_REALTIME) 135f08c3bdfSopenharmony_ci continue; 136f08c3bdfSopenharmony_ci 137f08c3bdfSopenharmony_ci ret = tv->clock_gettime(clks[i], tst_ts_get(&ts)); 138f08c3bdfSopenharmony_ci if (ret) { 139f08c3bdfSopenharmony_ci /* 140f08c3bdfSopenharmony_ci * _vdso_gettime() sets error to ENOSYS if vdso 141f08c3bdfSopenharmony_ci * isn't available. 142f08c3bdfSopenharmony_ci */ 143f08c3bdfSopenharmony_ci if (errno == ENOSYS) 144f08c3bdfSopenharmony_ci continue; 145f08c3bdfSopenharmony_ci 146f08c3bdfSopenharmony_ci tst_res(TFAIL | TERRNO, "%s: clock_gettime() failed (%d)", 147f08c3bdfSopenharmony_ci tst_clock_name(clks[i]), j); 148f08c3bdfSopenharmony_ci return; 149f08c3bdfSopenharmony_ci } 150f08c3bdfSopenharmony_ci 151f08c3bdfSopenharmony_ci end = tst_ts_to_ns(ts); 152f08c3bdfSopenharmony_ci 153f08c3bdfSopenharmony_ci /* Skip comparison on first traversal */ 154f08c3bdfSopenharmony_ci if (count == 10000 && !j) 155f08c3bdfSopenharmony_ci continue; 156f08c3bdfSopenharmony_ci 157f08c3bdfSopenharmony_ci /* 158f08c3bdfSopenharmony_ci * gettimeofday() doesn't capture time less than 1 us, 159f08c3bdfSopenharmony_ci * add 999 to it. 160f08c3bdfSopenharmony_ci */ 161f08c3bdfSopenharmony_ci if (tv->clock_gettime == my_gettimeofday) 162f08c3bdfSopenharmony_ci slack = 999; 163f08c3bdfSopenharmony_ci else 164f08c3bdfSopenharmony_ci slack = 0; 165f08c3bdfSopenharmony_ci 166f08c3bdfSopenharmony_ci diff = end + slack - start; 167f08c3bdfSopenharmony_ci if (diff < 0) { 168f08c3bdfSopenharmony_ci tst_res(TFAIL, "%s: Time travelled backwards (%d): %lld ns", 169f08c3bdfSopenharmony_ci tst_clock_name(clks[i]), j, diff); 170f08c3bdfSopenharmony_ci return; 171f08c3bdfSopenharmony_ci } 172f08c3bdfSopenharmony_ci 173f08c3bdfSopenharmony_ci diff /= 1000000; 174f08c3bdfSopenharmony_ci 175f08c3bdfSopenharmony_ci if (diff >= delta) { 176f08c3bdfSopenharmony_ci tst_res(TFAIL, "%s(%s): Difference between successive readings greater than %lld ms (%d): %lld", 177f08c3bdfSopenharmony_ci tst_clock_name(clks[i]), tv->desc, delta, j, diff); 178f08c3bdfSopenharmony_ci return; 179f08c3bdfSopenharmony_ci } 180f08c3bdfSopenharmony_ci } 181f08c3bdfSopenharmony_ci } while (--count); 182f08c3bdfSopenharmony_ci 183f08c3bdfSopenharmony_ci tst_res(TPASS, "%s: Difference between successive readings is reasonable for following variants:", 184f08c3bdfSopenharmony_ci tst_clock_name(clks[i])); 185f08c3bdfSopenharmony_ci for (j = 0; j < ARRAY_SIZE(variants); j++) { 186f08c3bdfSopenharmony_ci if (variants[j].clock_gettime == my_gettimeofday && clks[i] != CLOCK_REALTIME) 187f08c3bdfSopenharmony_ci continue; 188f08c3bdfSopenharmony_ci tst_res(TINFO, "\t- %s", variants[j].desc); 189f08c3bdfSopenharmony_ci } 190f08c3bdfSopenharmony_ci} 191f08c3bdfSopenharmony_ci 192f08c3bdfSopenharmony_cistatic struct tst_test test = { 193f08c3bdfSopenharmony_ci .test = run, 194f08c3bdfSopenharmony_ci .setup = setup, 195f08c3bdfSopenharmony_ci .tcnt = ARRAY_SIZE(clks), 196f08c3bdfSopenharmony_ci .tags = (const struct tst_tag[]) { 197f08c3bdfSopenharmony_ci {"linux-git", "5b43bd184530"}, 198f08c3bdfSopenharmony_ci {} 199f08c3bdfSopenharmony_ci } 200f08c3bdfSopenharmony_ci}; 201