18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Fast user context implementation of clock_gettime, gettimeofday, and time.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2019 ARM Limited.
68c2ecf20Sopenharmony_ci * Copyright 2006 Andi Kleen, SUSE Labs.
78c2ecf20Sopenharmony_ci * 32 Bit compat layer by Stefani Seibold <stefani@seibold.net>
88c2ecf20Sopenharmony_ci *  sponsored by Rohde & Schwarz GmbH & Co. KG Munich/Germany
98c2ecf20Sopenharmony_ci */
108c2ecf20Sopenharmony_ci#ifndef __ASM_VDSO_GETTIMEOFDAY_H
118c2ecf20Sopenharmony_ci#define __ASM_VDSO_GETTIMEOFDAY_H
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#ifndef __ASSEMBLY__
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#include <uapi/linux/time.h>
168c2ecf20Sopenharmony_ci#include <asm/vgtod.h>
178c2ecf20Sopenharmony_ci#include <asm/vvar.h>
188c2ecf20Sopenharmony_ci#include <asm/unistd.h>
198c2ecf20Sopenharmony_ci#include <asm/msr.h>
208c2ecf20Sopenharmony_ci#include <asm/pvclock.h>
218c2ecf20Sopenharmony_ci#include <clocksource/hyperv_timer.h>
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci#define __vdso_data (VVAR(_vdso_data))
248c2ecf20Sopenharmony_ci#define __timens_vdso_data (TIMENS(_vdso_data))
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci#define VDSO_HAS_TIME 1
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci#define VDSO_HAS_CLOCK_GETRES 1
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci/*
318c2ecf20Sopenharmony_ci * Declare the memory-mapped vclock data pages.  These come from hypervisors.
328c2ecf20Sopenharmony_ci * If we ever reintroduce something like direct access to an MMIO clock like
338c2ecf20Sopenharmony_ci * the HPET again, it will go here as well.
348c2ecf20Sopenharmony_ci *
358c2ecf20Sopenharmony_ci * A load from any of these pages will segfault if the clock in question is
368c2ecf20Sopenharmony_ci * disabled, so appropriate compiler barriers and checks need to be used
378c2ecf20Sopenharmony_ci * to prevent stray loads.
388c2ecf20Sopenharmony_ci *
398c2ecf20Sopenharmony_ci * These declarations MUST NOT be const.  The compiler will assume that
408c2ecf20Sopenharmony_ci * an extern const variable has genuinely constant contents, and the
418c2ecf20Sopenharmony_ci * resulting code won't work, since the whole point is that these pages
428c2ecf20Sopenharmony_ci * change over time, possibly while we're accessing them.
438c2ecf20Sopenharmony_ci */
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci#ifdef CONFIG_PARAVIRT_CLOCK
468c2ecf20Sopenharmony_ci/*
478c2ecf20Sopenharmony_ci * This is the vCPU 0 pvclock page.  We only use pvclock from the vDSO
488c2ecf20Sopenharmony_ci * if the hypervisor tells us that all vCPUs can get valid data from the
498c2ecf20Sopenharmony_ci * vCPU 0 page.
508c2ecf20Sopenharmony_ci */
518c2ecf20Sopenharmony_ciextern struct pvclock_vsyscall_time_info pvclock_page
528c2ecf20Sopenharmony_ci	__attribute__((visibility("hidden")));
538c2ecf20Sopenharmony_ci#endif
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci#ifdef CONFIG_HYPERV_TIMER
568c2ecf20Sopenharmony_ciextern struct ms_hyperv_tsc_page hvclock_page
578c2ecf20Sopenharmony_ci	__attribute__((visibility("hidden")));
588c2ecf20Sopenharmony_ci#endif
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci#ifdef CONFIG_TIME_NS
618c2ecf20Sopenharmony_cistatic __always_inline const struct vdso_data *__arch_get_timens_vdso_data(void)
628c2ecf20Sopenharmony_ci{
638c2ecf20Sopenharmony_ci	return __timens_vdso_data;
648c2ecf20Sopenharmony_ci}
658c2ecf20Sopenharmony_ci#endif
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci#ifndef BUILD_VDSO32
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_cistatic __always_inline
708c2ecf20Sopenharmony_cilong clock_gettime_fallback(clockid_t _clkid, struct __kernel_timespec *_ts)
718c2ecf20Sopenharmony_ci{
728c2ecf20Sopenharmony_ci	long ret;
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci	asm ("syscall" : "=a" (ret), "=m" (*_ts) :
758c2ecf20Sopenharmony_ci	     "0" (__NR_clock_gettime), "D" (_clkid), "S" (_ts) :
768c2ecf20Sopenharmony_ci	     "rcx", "r11");
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci	return ret;
798c2ecf20Sopenharmony_ci}
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_cistatic __always_inline
828c2ecf20Sopenharmony_cilong gettimeofday_fallback(struct __kernel_old_timeval *_tv,
838c2ecf20Sopenharmony_ci			   struct timezone *_tz)
848c2ecf20Sopenharmony_ci{
858c2ecf20Sopenharmony_ci	long ret;
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci	asm("syscall" : "=a" (ret) :
888c2ecf20Sopenharmony_ci	    "0" (__NR_gettimeofday), "D" (_tv), "S" (_tz) : "memory");
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci	return ret;
918c2ecf20Sopenharmony_ci}
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_cistatic __always_inline
948c2ecf20Sopenharmony_cilong clock_getres_fallback(clockid_t _clkid, struct __kernel_timespec *_ts)
958c2ecf20Sopenharmony_ci{
968c2ecf20Sopenharmony_ci	long ret;
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	asm ("syscall" : "=a" (ret), "=m" (*_ts) :
998c2ecf20Sopenharmony_ci	     "0" (__NR_clock_getres), "D" (_clkid), "S" (_ts) :
1008c2ecf20Sopenharmony_ci	     "rcx", "r11");
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci	return ret;
1038c2ecf20Sopenharmony_ci}
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci#else
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_cistatic __always_inline
1088c2ecf20Sopenharmony_cilong clock_gettime_fallback(clockid_t _clkid, struct __kernel_timespec *_ts)
1098c2ecf20Sopenharmony_ci{
1108c2ecf20Sopenharmony_ci	long ret;
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci	asm (
1138c2ecf20Sopenharmony_ci		"mov %%ebx, %%edx \n"
1148c2ecf20Sopenharmony_ci		"mov %[clock], %%ebx \n"
1158c2ecf20Sopenharmony_ci		"call __kernel_vsyscall \n"
1168c2ecf20Sopenharmony_ci		"mov %%edx, %%ebx \n"
1178c2ecf20Sopenharmony_ci		: "=a" (ret), "=m" (*_ts)
1188c2ecf20Sopenharmony_ci		: "0" (__NR_clock_gettime64), [clock] "g" (_clkid), "c" (_ts)
1198c2ecf20Sopenharmony_ci		: "edx");
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	return ret;
1228c2ecf20Sopenharmony_ci}
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_cistatic __always_inline
1258c2ecf20Sopenharmony_cilong clock_gettime32_fallback(clockid_t _clkid, struct old_timespec32 *_ts)
1268c2ecf20Sopenharmony_ci{
1278c2ecf20Sopenharmony_ci	long ret;
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci	asm (
1308c2ecf20Sopenharmony_ci		"mov %%ebx, %%edx \n"
1318c2ecf20Sopenharmony_ci		"mov %[clock], %%ebx \n"
1328c2ecf20Sopenharmony_ci		"call __kernel_vsyscall \n"
1338c2ecf20Sopenharmony_ci		"mov %%edx, %%ebx \n"
1348c2ecf20Sopenharmony_ci		: "=a" (ret), "=m" (*_ts)
1358c2ecf20Sopenharmony_ci		: "0" (__NR_clock_gettime), [clock] "g" (_clkid), "c" (_ts)
1368c2ecf20Sopenharmony_ci		: "edx");
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	return ret;
1398c2ecf20Sopenharmony_ci}
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_cistatic __always_inline
1428c2ecf20Sopenharmony_cilong gettimeofday_fallback(struct __kernel_old_timeval *_tv,
1438c2ecf20Sopenharmony_ci			   struct timezone *_tz)
1448c2ecf20Sopenharmony_ci{
1458c2ecf20Sopenharmony_ci	long ret;
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	asm(
1488c2ecf20Sopenharmony_ci		"mov %%ebx, %%edx \n"
1498c2ecf20Sopenharmony_ci		"mov %2, %%ebx \n"
1508c2ecf20Sopenharmony_ci		"call __kernel_vsyscall \n"
1518c2ecf20Sopenharmony_ci		"mov %%edx, %%ebx \n"
1528c2ecf20Sopenharmony_ci		: "=a" (ret)
1538c2ecf20Sopenharmony_ci		: "0" (__NR_gettimeofday), "g" (_tv), "c" (_tz)
1548c2ecf20Sopenharmony_ci		: "memory", "edx");
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci	return ret;
1578c2ecf20Sopenharmony_ci}
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_cistatic __always_inline long
1608c2ecf20Sopenharmony_ciclock_getres_fallback(clockid_t _clkid, struct __kernel_timespec *_ts)
1618c2ecf20Sopenharmony_ci{
1628c2ecf20Sopenharmony_ci	long ret;
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci	asm (
1658c2ecf20Sopenharmony_ci		"mov %%ebx, %%edx \n"
1668c2ecf20Sopenharmony_ci		"mov %[clock], %%ebx \n"
1678c2ecf20Sopenharmony_ci		"call __kernel_vsyscall \n"
1688c2ecf20Sopenharmony_ci		"mov %%edx, %%ebx \n"
1698c2ecf20Sopenharmony_ci		: "=a" (ret), "=m" (*_ts)
1708c2ecf20Sopenharmony_ci		: "0" (__NR_clock_getres_time64), [clock] "g" (_clkid), "c" (_ts)
1718c2ecf20Sopenharmony_ci		: "edx");
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci	return ret;
1748c2ecf20Sopenharmony_ci}
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_cistatic __always_inline
1778c2ecf20Sopenharmony_cilong clock_getres32_fallback(clockid_t _clkid, struct old_timespec32 *_ts)
1788c2ecf20Sopenharmony_ci{
1798c2ecf20Sopenharmony_ci	long ret;
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci	asm (
1828c2ecf20Sopenharmony_ci		"mov %%ebx, %%edx \n"
1838c2ecf20Sopenharmony_ci		"mov %[clock], %%ebx \n"
1848c2ecf20Sopenharmony_ci		"call __kernel_vsyscall \n"
1858c2ecf20Sopenharmony_ci		"mov %%edx, %%ebx \n"
1868c2ecf20Sopenharmony_ci		: "=a" (ret), "=m" (*_ts)
1878c2ecf20Sopenharmony_ci		: "0" (__NR_clock_getres), [clock] "g" (_clkid), "c" (_ts)
1888c2ecf20Sopenharmony_ci		: "edx");
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci	return ret;
1918c2ecf20Sopenharmony_ci}
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci#endif
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci#ifdef CONFIG_PARAVIRT_CLOCK
1968c2ecf20Sopenharmony_cistatic u64 vread_pvclock(void)
1978c2ecf20Sopenharmony_ci{
1988c2ecf20Sopenharmony_ci	const struct pvclock_vcpu_time_info *pvti = &pvclock_page.pvti;
1998c2ecf20Sopenharmony_ci	u32 version;
2008c2ecf20Sopenharmony_ci	u64 ret;
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci	/*
2038c2ecf20Sopenharmony_ci	 * Note: The kernel and hypervisor must guarantee that cpu ID
2048c2ecf20Sopenharmony_ci	 * number maps 1:1 to per-CPU pvclock time info.
2058c2ecf20Sopenharmony_ci	 *
2068c2ecf20Sopenharmony_ci	 * Because the hypervisor is entirely unaware of guest userspace
2078c2ecf20Sopenharmony_ci	 * preemption, it cannot guarantee that per-CPU pvclock time
2088c2ecf20Sopenharmony_ci	 * info is updated if the underlying CPU changes or that that
2098c2ecf20Sopenharmony_ci	 * version is increased whenever underlying CPU changes.
2108c2ecf20Sopenharmony_ci	 *
2118c2ecf20Sopenharmony_ci	 * On KVM, we are guaranteed that pvti updates for any vCPU are
2128c2ecf20Sopenharmony_ci	 * atomic as seen by *all* vCPUs.  This is an even stronger
2138c2ecf20Sopenharmony_ci	 * guarantee than we get with a normal seqlock.
2148c2ecf20Sopenharmony_ci	 *
2158c2ecf20Sopenharmony_ci	 * On Xen, we don't appear to have that guarantee, but Xen still
2168c2ecf20Sopenharmony_ci	 * supplies a valid seqlock using the version field.
2178c2ecf20Sopenharmony_ci	 *
2188c2ecf20Sopenharmony_ci	 * We only do pvclock vdso timing at all if
2198c2ecf20Sopenharmony_ci	 * PVCLOCK_TSC_STABLE_BIT is set, and we interpret that bit to
2208c2ecf20Sopenharmony_ci	 * mean that all vCPUs have matching pvti and that the TSC is
2218c2ecf20Sopenharmony_ci	 * synced, so we can just look at vCPU 0's pvti.
2228c2ecf20Sopenharmony_ci	 */
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci	do {
2258c2ecf20Sopenharmony_ci		version = pvclock_read_begin(pvti);
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci		if (unlikely(!(pvti->flags & PVCLOCK_TSC_STABLE_BIT)))
2288c2ecf20Sopenharmony_ci			return U64_MAX;
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci		ret = __pvclock_read_cycles(pvti, rdtsc_ordered());
2318c2ecf20Sopenharmony_ci	} while (pvclock_read_retry(pvti, version));
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci	return ret;
2348c2ecf20Sopenharmony_ci}
2358c2ecf20Sopenharmony_ci#endif
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci#ifdef CONFIG_HYPERV_TIMER
2388c2ecf20Sopenharmony_cistatic u64 vread_hvclock(void)
2398c2ecf20Sopenharmony_ci{
2408c2ecf20Sopenharmony_ci	return hv_read_tsc_page(&hvclock_page);
2418c2ecf20Sopenharmony_ci}
2428c2ecf20Sopenharmony_ci#endif
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_cistatic inline u64 __arch_get_hw_counter(s32 clock_mode,
2458c2ecf20Sopenharmony_ci					const struct vdso_data *vd)
2468c2ecf20Sopenharmony_ci{
2478c2ecf20Sopenharmony_ci	if (likely(clock_mode == VDSO_CLOCKMODE_TSC))
2488c2ecf20Sopenharmony_ci		return (u64)rdtsc_ordered();
2498c2ecf20Sopenharmony_ci	/*
2508c2ecf20Sopenharmony_ci	 * For any memory-mapped vclock type, we need to make sure that gcc
2518c2ecf20Sopenharmony_ci	 * doesn't cleverly hoist a load before the mode check.  Otherwise we
2528c2ecf20Sopenharmony_ci	 * might end up touching the memory-mapped page even if the vclock in
2538c2ecf20Sopenharmony_ci	 * question isn't enabled, which will segfault.  Hence the barriers.
2548c2ecf20Sopenharmony_ci	 */
2558c2ecf20Sopenharmony_ci#ifdef CONFIG_PARAVIRT_CLOCK
2568c2ecf20Sopenharmony_ci	if (clock_mode == VDSO_CLOCKMODE_PVCLOCK) {
2578c2ecf20Sopenharmony_ci		barrier();
2588c2ecf20Sopenharmony_ci		return vread_pvclock();
2598c2ecf20Sopenharmony_ci	}
2608c2ecf20Sopenharmony_ci#endif
2618c2ecf20Sopenharmony_ci#ifdef CONFIG_HYPERV_TIMER
2628c2ecf20Sopenharmony_ci	if (clock_mode == VDSO_CLOCKMODE_HVCLOCK) {
2638c2ecf20Sopenharmony_ci		barrier();
2648c2ecf20Sopenharmony_ci		return vread_hvclock();
2658c2ecf20Sopenharmony_ci	}
2668c2ecf20Sopenharmony_ci#endif
2678c2ecf20Sopenharmony_ci	return U64_MAX;
2688c2ecf20Sopenharmony_ci}
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_cistatic __always_inline const struct vdso_data *__arch_get_vdso_data(void)
2718c2ecf20Sopenharmony_ci{
2728c2ecf20Sopenharmony_ci	return __vdso_data;
2738c2ecf20Sopenharmony_ci}
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_cistatic inline bool arch_vdso_clocksource_ok(const struct vdso_data *vd)
2768c2ecf20Sopenharmony_ci{
2778c2ecf20Sopenharmony_ci	return true;
2788c2ecf20Sopenharmony_ci}
2798c2ecf20Sopenharmony_ci#define vdso_clocksource_ok arch_vdso_clocksource_ok
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci/*
2828c2ecf20Sopenharmony_ci * Clocksource read value validation to handle PV and HyperV clocksources
2838c2ecf20Sopenharmony_ci * which can be invalidated asynchronously and indicate invalidation by
2848c2ecf20Sopenharmony_ci * returning U64_MAX, which can be effectively tested by checking for a
2858c2ecf20Sopenharmony_ci * negative value after casting it to s64.
2868c2ecf20Sopenharmony_ci */
2878c2ecf20Sopenharmony_cistatic inline bool arch_vdso_cycles_ok(u64 cycles)
2888c2ecf20Sopenharmony_ci{
2898c2ecf20Sopenharmony_ci	return (s64)cycles >= 0;
2908c2ecf20Sopenharmony_ci}
2918c2ecf20Sopenharmony_ci#define vdso_cycles_ok arch_vdso_cycles_ok
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci/*
2948c2ecf20Sopenharmony_ci * x86 specific delta calculation.
2958c2ecf20Sopenharmony_ci *
2968c2ecf20Sopenharmony_ci * The regular implementation assumes that clocksource reads are globally
2978c2ecf20Sopenharmony_ci * monotonic. The TSC can be slightly off across sockets which can cause
2988c2ecf20Sopenharmony_ci * the regular delta calculation (@cycles - @last) to return a huge time
2998c2ecf20Sopenharmony_ci * jump.
3008c2ecf20Sopenharmony_ci *
3018c2ecf20Sopenharmony_ci * Therefore it needs to be verified that @cycles are greater than
3028c2ecf20Sopenharmony_ci * @last. If not then use @last, which is the base time of the current
3038c2ecf20Sopenharmony_ci * conversion period.
3048c2ecf20Sopenharmony_ci *
3058c2ecf20Sopenharmony_ci * This variant also removes the masking of the subtraction because the
3068c2ecf20Sopenharmony_ci * clocksource mask of all VDSO capable clocksources on x86 is U64_MAX
3078c2ecf20Sopenharmony_ci * which would result in a pointless operation. The compiler cannot
3088c2ecf20Sopenharmony_ci * optimize it away as the mask comes from the vdso data and is not compile
3098c2ecf20Sopenharmony_ci * time constant.
3108c2ecf20Sopenharmony_ci */
3118c2ecf20Sopenharmony_cistatic __always_inline
3128c2ecf20Sopenharmony_ciu64 vdso_calc_delta(u64 cycles, u64 last, u64 mask, u32 mult)
3138c2ecf20Sopenharmony_ci{
3148c2ecf20Sopenharmony_ci	if (cycles > last)
3158c2ecf20Sopenharmony_ci		return (cycles - last) * mult;
3168c2ecf20Sopenharmony_ci	return 0;
3178c2ecf20Sopenharmony_ci}
3188c2ecf20Sopenharmony_ci#define vdso_calc_delta vdso_calc_delta
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci#endif /* !__ASSEMBLY__ */
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci#endif /* __ASM_VDSO_GETTIMEOFDAY_H */
323