18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright 2006 Andi Kleen, SUSE Labs. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Fast user context implementation of clock_gettime, gettimeofday, and time. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * The code should have no internal unresolved relocations. 88c2ecf20Sopenharmony_ci * Check with readelf after changing. 98c2ecf20Sopenharmony_ci * Also alternative() doesn't work. 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci/* 128c2ecf20Sopenharmony_ci * Copyright (c) 2017 Oracle and/or its affiliates. All rights reserved. 138c2ecf20Sopenharmony_ci */ 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include <linux/kernel.h> 168c2ecf20Sopenharmony_ci#include <linux/time.h> 178c2ecf20Sopenharmony_ci#include <linux/string.h> 188c2ecf20Sopenharmony_ci#include <asm/io.h> 198c2ecf20Sopenharmony_ci#include <asm/unistd.h> 208c2ecf20Sopenharmony_ci#include <asm/timex.h> 218c2ecf20Sopenharmony_ci#include <asm/clocksource.h> 228c2ecf20Sopenharmony_ci#include <asm/vvar.h> 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#ifdef CONFIG_SPARC64 258c2ecf20Sopenharmony_ci#define SYSCALL_STRING \ 268c2ecf20Sopenharmony_ci "ta 0x6d;" \ 278c2ecf20Sopenharmony_ci "bcs,a 1f;" \ 288c2ecf20Sopenharmony_ci " sub %%g0, %%o0, %%o0;" \ 298c2ecf20Sopenharmony_ci "1:" 308c2ecf20Sopenharmony_ci#else 318c2ecf20Sopenharmony_ci#define SYSCALL_STRING \ 328c2ecf20Sopenharmony_ci "ta 0x10;" \ 338c2ecf20Sopenharmony_ci "bcs,a 1f;" \ 348c2ecf20Sopenharmony_ci " sub %%g0, %%o0, %%o0;" \ 358c2ecf20Sopenharmony_ci "1:" 368c2ecf20Sopenharmony_ci#endif 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci#define SYSCALL_CLOBBERS \ 398c2ecf20Sopenharmony_ci "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", \ 408c2ecf20Sopenharmony_ci "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", \ 418c2ecf20Sopenharmony_ci "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", \ 428c2ecf20Sopenharmony_ci "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", \ 438c2ecf20Sopenharmony_ci "f32", "f34", "f36", "f38", "f40", "f42", "f44", "f46", \ 448c2ecf20Sopenharmony_ci "f48", "f50", "f52", "f54", "f56", "f58", "f60", "f62", \ 458c2ecf20Sopenharmony_ci "cc", "memory" 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci/* 488c2ecf20Sopenharmony_ci * Compute the vvar page's address in the process address space, and return it 498c2ecf20Sopenharmony_ci * as a pointer to the vvar_data. 508c2ecf20Sopenharmony_ci */ 518c2ecf20Sopenharmony_cinotrace static __always_inline struct vvar_data *get_vvar_data(void) 528c2ecf20Sopenharmony_ci{ 538c2ecf20Sopenharmony_ci unsigned long ret; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci /* 568c2ecf20Sopenharmony_ci * vdso data page is the first vDSO page so grab the PC 578c2ecf20Sopenharmony_ci * and move up a page to get to the data page. 588c2ecf20Sopenharmony_ci */ 598c2ecf20Sopenharmony_ci __asm__("rd %%pc, %0" : "=r" (ret)); 608c2ecf20Sopenharmony_ci ret &= ~(8192 - 1); 618c2ecf20Sopenharmony_ci ret -= 8192; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci return (struct vvar_data *) ret; 648c2ecf20Sopenharmony_ci} 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_cinotrace static long vdso_fallback_gettime(long clock, struct __kernel_old_timespec *ts) 678c2ecf20Sopenharmony_ci{ 688c2ecf20Sopenharmony_ci register long num __asm__("g1") = __NR_clock_gettime; 698c2ecf20Sopenharmony_ci register long o0 __asm__("o0") = clock; 708c2ecf20Sopenharmony_ci register long o1 __asm__("o1") = (long) ts; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci __asm__ __volatile__(SYSCALL_STRING : "=r" (o0) : "r" (num), 738c2ecf20Sopenharmony_ci "0" (o0), "r" (o1) : SYSCALL_CLOBBERS); 748c2ecf20Sopenharmony_ci return o0; 758c2ecf20Sopenharmony_ci} 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_cinotrace static long vdso_fallback_gettimeofday(struct __kernel_old_timeval *tv, struct timezone *tz) 788c2ecf20Sopenharmony_ci{ 798c2ecf20Sopenharmony_ci register long num __asm__("g1") = __NR_gettimeofday; 808c2ecf20Sopenharmony_ci register long o0 __asm__("o0") = (long) tv; 818c2ecf20Sopenharmony_ci register long o1 __asm__("o1") = (long) tz; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci __asm__ __volatile__(SYSCALL_STRING : "=r" (o0) : "r" (num), 848c2ecf20Sopenharmony_ci "0" (o0), "r" (o1) : SYSCALL_CLOBBERS); 858c2ecf20Sopenharmony_ci return o0; 868c2ecf20Sopenharmony_ci} 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci#ifdef CONFIG_SPARC64 898c2ecf20Sopenharmony_cinotrace static __always_inline u64 vread_tick(void) 908c2ecf20Sopenharmony_ci{ 918c2ecf20Sopenharmony_ci u64 ret; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci __asm__ __volatile__("rd %%tick, %0" : "=r" (ret)); 948c2ecf20Sopenharmony_ci return ret; 958c2ecf20Sopenharmony_ci} 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_cinotrace static __always_inline u64 vread_tick_stick(void) 988c2ecf20Sopenharmony_ci{ 998c2ecf20Sopenharmony_ci u64 ret; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci __asm__ __volatile__("rd %%asr24, %0" : "=r" (ret)); 1028c2ecf20Sopenharmony_ci return ret; 1038c2ecf20Sopenharmony_ci} 1048c2ecf20Sopenharmony_ci#else 1058c2ecf20Sopenharmony_cinotrace static __always_inline u64 vread_tick(void) 1068c2ecf20Sopenharmony_ci{ 1078c2ecf20Sopenharmony_ci register unsigned long long ret asm("o4"); 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci __asm__ __volatile__("rd %%tick, %L0\n\t" 1108c2ecf20Sopenharmony_ci "srlx %L0, 32, %H0" 1118c2ecf20Sopenharmony_ci : "=r" (ret)); 1128c2ecf20Sopenharmony_ci return ret; 1138c2ecf20Sopenharmony_ci} 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_cinotrace static __always_inline u64 vread_tick_stick(void) 1168c2ecf20Sopenharmony_ci{ 1178c2ecf20Sopenharmony_ci register unsigned long long ret asm("o4"); 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci __asm__ __volatile__("rd %%asr24, %L0\n\t" 1208c2ecf20Sopenharmony_ci "srlx %L0, 32, %H0" 1218c2ecf20Sopenharmony_ci : "=r" (ret)); 1228c2ecf20Sopenharmony_ci return ret; 1238c2ecf20Sopenharmony_ci} 1248c2ecf20Sopenharmony_ci#endif 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_cinotrace static __always_inline u64 vgetsns(struct vvar_data *vvar) 1278c2ecf20Sopenharmony_ci{ 1288c2ecf20Sopenharmony_ci u64 v; 1298c2ecf20Sopenharmony_ci u64 cycles; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci cycles = vread_tick(); 1328c2ecf20Sopenharmony_ci v = (cycles - vvar->clock.cycle_last) & vvar->clock.mask; 1338c2ecf20Sopenharmony_ci return v * vvar->clock.mult; 1348c2ecf20Sopenharmony_ci} 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_cinotrace static __always_inline u64 vgetsns_stick(struct vvar_data *vvar) 1378c2ecf20Sopenharmony_ci{ 1388c2ecf20Sopenharmony_ci u64 v; 1398c2ecf20Sopenharmony_ci u64 cycles; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci cycles = vread_tick_stick(); 1428c2ecf20Sopenharmony_ci v = (cycles - vvar->clock.cycle_last) & vvar->clock.mask; 1438c2ecf20Sopenharmony_ci return v * vvar->clock.mult; 1448c2ecf20Sopenharmony_ci} 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_cinotrace static __always_inline int do_realtime(struct vvar_data *vvar, 1478c2ecf20Sopenharmony_ci struct __kernel_old_timespec *ts) 1488c2ecf20Sopenharmony_ci{ 1498c2ecf20Sopenharmony_ci unsigned long seq; 1508c2ecf20Sopenharmony_ci u64 ns; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci do { 1538c2ecf20Sopenharmony_ci seq = vvar_read_begin(vvar); 1548c2ecf20Sopenharmony_ci ts->tv_sec = vvar->wall_time_sec; 1558c2ecf20Sopenharmony_ci ns = vvar->wall_time_snsec; 1568c2ecf20Sopenharmony_ci ns += vgetsns(vvar); 1578c2ecf20Sopenharmony_ci ns >>= vvar->clock.shift; 1588c2ecf20Sopenharmony_ci } while (unlikely(vvar_read_retry(vvar, seq))); 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci ts->tv_sec += __iter_div_u64_rem(ns, NSEC_PER_SEC, &ns); 1618c2ecf20Sopenharmony_ci ts->tv_nsec = ns; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci return 0; 1648c2ecf20Sopenharmony_ci} 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_cinotrace static __always_inline int do_realtime_stick(struct vvar_data *vvar, 1678c2ecf20Sopenharmony_ci struct __kernel_old_timespec *ts) 1688c2ecf20Sopenharmony_ci{ 1698c2ecf20Sopenharmony_ci unsigned long seq; 1708c2ecf20Sopenharmony_ci u64 ns; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci do { 1738c2ecf20Sopenharmony_ci seq = vvar_read_begin(vvar); 1748c2ecf20Sopenharmony_ci ts->tv_sec = vvar->wall_time_sec; 1758c2ecf20Sopenharmony_ci ns = vvar->wall_time_snsec; 1768c2ecf20Sopenharmony_ci ns += vgetsns_stick(vvar); 1778c2ecf20Sopenharmony_ci ns >>= vvar->clock.shift; 1788c2ecf20Sopenharmony_ci } while (unlikely(vvar_read_retry(vvar, seq))); 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci ts->tv_sec += __iter_div_u64_rem(ns, NSEC_PER_SEC, &ns); 1818c2ecf20Sopenharmony_ci ts->tv_nsec = ns; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci return 0; 1848c2ecf20Sopenharmony_ci} 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_cinotrace static __always_inline int do_monotonic(struct vvar_data *vvar, 1878c2ecf20Sopenharmony_ci struct __kernel_old_timespec *ts) 1888c2ecf20Sopenharmony_ci{ 1898c2ecf20Sopenharmony_ci unsigned long seq; 1908c2ecf20Sopenharmony_ci u64 ns; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci do { 1938c2ecf20Sopenharmony_ci seq = vvar_read_begin(vvar); 1948c2ecf20Sopenharmony_ci ts->tv_sec = vvar->monotonic_time_sec; 1958c2ecf20Sopenharmony_ci ns = vvar->monotonic_time_snsec; 1968c2ecf20Sopenharmony_ci ns += vgetsns(vvar); 1978c2ecf20Sopenharmony_ci ns >>= vvar->clock.shift; 1988c2ecf20Sopenharmony_ci } while (unlikely(vvar_read_retry(vvar, seq))); 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci ts->tv_sec += __iter_div_u64_rem(ns, NSEC_PER_SEC, &ns); 2018c2ecf20Sopenharmony_ci ts->tv_nsec = ns; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci return 0; 2048c2ecf20Sopenharmony_ci} 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_cinotrace static __always_inline int do_monotonic_stick(struct vvar_data *vvar, 2078c2ecf20Sopenharmony_ci struct __kernel_old_timespec *ts) 2088c2ecf20Sopenharmony_ci{ 2098c2ecf20Sopenharmony_ci unsigned long seq; 2108c2ecf20Sopenharmony_ci u64 ns; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci do { 2138c2ecf20Sopenharmony_ci seq = vvar_read_begin(vvar); 2148c2ecf20Sopenharmony_ci ts->tv_sec = vvar->monotonic_time_sec; 2158c2ecf20Sopenharmony_ci ns = vvar->monotonic_time_snsec; 2168c2ecf20Sopenharmony_ci ns += vgetsns_stick(vvar); 2178c2ecf20Sopenharmony_ci ns >>= vvar->clock.shift; 2188c2ecf20Sopenharmony_ci } while (unlikely(vvar_read_retry(vvar, seq))); 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci ts->tv_sec += __iter_div_u64_rem(ns, NSEC_PER_SEC, &ns); 2218c2ecf20Sopenharmony_ci ts->tv_nsec = ns; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci return 0; 2248c2ecf20Sopenharmony_ci} 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_cinotrace static int do_realtime_coarse(struct vvar_data *vvar, 2278c2ecf20Sopenharmony_ci struct __kernel_old_timespec *ts) 2288c2ecf20Sopenharmony_ci{ 2298c2ecf20Sopenharmony_ci unsigned long seq; 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci do { 2328c2ecf20Sopenharmony_ci seq = vvar_read_begin(vvar); 2338c2ecf20Sopenharmony_ci ts->tv_sec = vvar->wall_time_coarse_sec; 2348c2ecf20Sopenharmony_ci ts->tv_nsec = vvar->wall_time_coarse_nsec; 2358c2ecf20Sopenharmony_ci } while (unlikely(vvar_read_retry(vvar, seq))); 2368c2ecf20Sopenharmony_ci return 0; 2378c2ecf20Sopenharmony_ci} 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_cinotrace static int do_monotonic_coarse(struct vvar_data *vvar, 2408c2ecf20Sopenharmony_ci struct __kernel_old_timespec *ts) 2418c2ecf20Sopenharmony_ci{ 2428c2ecf20Sopenharmony_ci unsigned long seq; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci do { 2458c2ecf20Sopenharmony_ci seq = vvar_read_begin(vvar); 2468c2ecf20Sopenharmony_ci ts->tv_sec = vvar->monotonic_time_coarse_sec; 2478c2ecf20Sopenharmony_ci ts->tv_nsec = vvar->monotonic_time_coarse_nsec; 2488c2ecf20Sopenharmony_ci } while (unlikely(vvar_read_retry(vvar, seq))); 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci return 0; 2518c2ecf20Sopenharmony_ci} 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_cinotrace int 2548c2ecf20Sopenharmony_ci__vdso_clock_gettime(clockid_t clock, struct __kernel_old_timespec *ts) 2558c2ecf20Sopenharmony_ci{ 2568c2ecf20Sopenharmony_ci struct vvar_data *vvd = get_vvar_data(); 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci switch (clock) { 2598c2ecf20Sopenharmony_ci case CLOCK_REALTIME: 2608c2ecf20Sopenharmony_ci if (unlikely(vvd->vclock_mode == VCLOCK_NONE)) 2618c2ecf20Sopenharmony_ci break; 2628c2ecf20Sopenharmony_ci return do_realtime(vvd, ts); 2638c2ecf20Sopenharmony_ci case CLOCK_MONOTONIC: 2648c2ecf20Sopenharmony_ci if (unlikely(vvd->vclock_mode == VCLOCK_NONE)) 2658c2ecf20Sopenharmony_ci break; 2668c2ecf20Sopenharmony_ci return do_monotonic(vvd, ts); 2678c2ecf20Sopenharmony_ci case CLOCK_REALTIME_COARSE: 2688c2ecf20Sopenharmony_ci return do_realtime_coarse(vvd, ts); 2698c2ecf20Sopenharmony_ci case CLOCK_MONOTONIC_COARSE: 2708c2ecf20Sopenharmony_ci return do_monotonic_coarse(vvd, ts); 2718c2ecf20Sopenharmony_ci } 2728c2ecf20Sopenharmony_ci /* 2738c2ecf20Sopenharmony_ci * Unknown clock ID ? Fall back to the syscall. 2748c2ecf20Sopenharmony_ci */ 2758c2ecf20Sopenharmony_ci return vdso_fallback_gettime(clock, ts); 2768c2ecf20Sopenharmony_ci} 2778c2ecf20Sopenharmony_ciint 2788c2ecf20Sopenharmony_ciclock_gettime(clockid_t, struct __kernel_old_timespec *) 2798c2ecf20Sopenharmony_ci __attribute__((weak, alias("__vdso_clock_gettime"))); 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_cinotrace int 2828c2ecf20Sopenharmony_ci__vdso_clock_gettime_stick(clockid_t clock, struct __kernel_old_timespec *ts) 2838c2ecf20Sopenharmony_ci{ 2848c2ecf20Sopenharmony_ci struct vvar_data *vvd = get_vvar_data(); 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci switch (clock) { 2878c2ecf20Sopenharmony_ci case CLOCK_REALTIME: 2888c2ecf20Sopenharmony_ci if (unlikely(vvd->vclock_mode == VCLOCK_NONE)) 2898c2ecf20Sopenharmony_ci break; 2908c2ecf20Sopenharmony_ci return do_realtime_stick(vvd, ts); 2918c2ecf20Sopenharmony_ci case CLOCK_MONOTONIC: 2928c2ecf20Sopenharmony_ci if (unlikely(vvd->vclock_mode == VCLOCK_NONE)) 2938c2ecf20Sopenharmony_ci break; 2948c2ecf20Sopenharmony_ci return do_monotonic_stick(vvd, ts); 2958c2ecf20Sopenharmony_ci case CLOCK_REALTIME_COARSE: 2968c2ecf20Sopenharmony_ci return do_realtime_coarse(vvd, ts); 2978c2ecf20Sopenharmony_ci case CLOCK_MONOTONIC_COARSE: 2988c2ecf20Sopenharmony_ci return do_monotonic_coarse(vvd, ts); 2998c2ecf20Sopenharmony_ci } 3008c2ecf20Sopenharmony_ci /* 3018c2ecf20Sopenharmony_ci * Unknown clock ID ? Fall back to the syscall. 3028c2ecf20Sopenharmony_ci */ 3038c2ecf20Sopenharmony_ci return vdso_fallback_gettime(clock, ts); 3048c2ecf20Sopenharmony_ci} 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_cinotrace int 3078c2ecf20Sopenharmony_ci__vdso_gettimeofday(struct __kernel_old_timeval *tv, struct timezone *tz) 3088c2ecf20Sopenharmony_ci{ 3098c2ecf20Sopenharmony_ci struct vvar_data *vvd = get_vvar_data(); 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci if (likely(vvd->vclock_mode != VCLOCK_NONE)) { 3128c2ecf20Sopenharmony_ci if (likely(tv != NULL)) { 3138c2ecf20Sopenharmony_ci union tstv_t { 3148c2ecf20Sopenharmony_ci struct __kernel_old_timespec ts; 3158c2ecf20Sopenharmony_ci struct __kernel_old_timeval tv; 3168c2ecf20Sopenharmony_ci } *tstv = (union tstv_t *) tv; 3178c2ecf20Sopenharmony_ci do_realtime(vvd, &tstv->ts); 3188c2ecf20Sopenharmony_ci /* 3198c2ecf20Sopenharmony_ci * Assign before dividing to ensure that the division is 3208c2ecf20Sopenharmony_ci * done in the type of tv_usec, not tv_nsec. 3218c2ecf20Sopenharmony_ci * 3228c2ecf20Sopenharmony_ci * There cannot be > 1 billion usec in a second: 3238c2ecf20Sopenharmony_ci * do_realtime() has already distributed such overflow 3248c2ecf20Sopenharmony_ci * into tv_sec. So we can assign it to an int safely. 3258c2ecf20Sopenharmony_ci */ 3268c2ecf20Sopenharmony_ci tstv->tv.tv_usec = tstv->ts.tv_nsec; 3278c2ecf20Sopenharmony_ci tstv->tv.tv_usec /= 1000; 3288c2ecf20Sopenharmony_ci } 3298c2ecf20Sopenharmony_ci if (unlikely(tz != NULL)) { 3308c2ecf20Sopenharmony_ci /* Avoid memcpy. Some old compilers fail to inline it */ 3318c2ecf20Sopenharmony_ci tz->tz_minuteswest = vvd->tz_minuteswest; 3328c2ecf20Sopenharmony_ci tz->tz_dsttime = vvd->tz_dsttime; 3338c2ecf20Sopenharmony_ci } 3348c2ecf20Sopenharmony_ci return 0; 3358c2ecf20Sopenharmony_ci } 3368c2ecf20Sopenharmony_ci return vdso_fallback_gettimeofday(tv, tz); 3378c2ecf20Sopenharmony_ci} 3388c2ecf20Sopenharmony_ciint 3398c2ecf20Sopenharmony_cigettimeofday(struct __kernel_old_timeval *, struct timezone *) 3408c2ecf20Sopenharmony_ci __attribute__((weak, alias("__vdso_gettimeofday"))); 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_cinotrace int 3438c2ecf20Sopenharmony_ci__vdso_gettimeofday_stick(struct __kernel_old_timeval *tv, struct timezone *tz) 3448c2ecf20Sopenharmony_ci{ 3458c2ecf20Sopenharmony_ci struct vvar_data *vvd = get_vvar_data(); 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci if (likely(vvd->vclock_mode != VCLOCK_NONE)) { 3488c2ecf20Sopenharmony_ci if (likely(tv != NULL)) { 3498c2ecf20Sopenharmony_ci union tstv_t { 3508c2ecf20Sopenharmony_ci struct __kernel_old_timespec ts; 3518c2ecf20Sopenharmony_ci struct __kernel_old_timeval tv; 3528c2ecf20Sopenharmony_ci } *tstv = (union tstv_t *) tv; 3538c2ecf20Sopenharmony_ci do_realtime_stick(vvd, &tstv->ts); 3548c2ecf20Sopenharmony_ci /* 3558c2ecf20Sopenharmony_ci * Assign before dividing to ensure that the division is 3568c2ecf20Sopenharmony_ci * done in the type of tv_usec, not tv_nsec. 3578c2ecf20Sopenharmony_ci * 3588c2ecf20Sopenharmony_ci * There cannot be > 1 billion usec in a second: 3598c2ecf20Sopenharmony_ci * do_realtime() has already distributed such overflow 3608c2ecf20Sopenharmony_ci * into tv_sec. So we can assign it to an int safely. 3618c2ecf20Sopenharmony_ci */ 3628c2ecf20Sopenharmony_ci tstv->tv.tv_usec = tstv->ts.tv_nsec; 3638c2ecf20Sopenharmony_ci tstv->tv.tv_usec /= 1000; 3648c2ecf20Sopenharmony_ci } 3658c2ecf20Sopenharmony_ci if (unlikely(tz != NULL)) { 3668c2ecf20Sopenharmony_ci /* Avoid memcpy. Some old compilers fail to inline it */ 3678c2ecf20Sopenharmony_ci tz->tz_minuteswest = vvd->tz_minuteswest; 3688c2ecf20Sopenharmony_ci tz->tz_dsttime = vvd->tz_dsttime; 3698c2ecf20Sopenharmony_ci } 3708c2ecf20Sopenharmony_ci return 0; 3718c2ecf20Sopenharmony_ci } 3728c2ecf20Sopenharmony_ci return vdso_fallback_gettimeofday(tv, tz); 3738c2ecf20Sopenharmony_ci} 374