18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2018 ARM Limited 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci#ifndef __ASM_VDSO_GETTIMEOFDAY_H 68c2ecf20Sopenharmony_ci#define __ASM_VDSO_GETTIMEOFDAY_H 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#ifndef __ASSEMBLY__ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <asm/barrier.h> 118c2ecf20Sopenharmony_ci#include <asm/unistd.h> 128c2ecf20Sopenharmony_ci#include <asm/errno.h> 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include <asm/vdso/compat_barrier.h> 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#define VDSO_HAS_CLOCK_GETRES 1 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#define BUILD_VDSO32 1 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_cistatic __always_inline 218c2ecf20Sopenharmony_ciint gettimeofday_fallback(struct __kernel_old_timeval *_tv, 228c2ecf20Sopenharmony_ci struct timezone *_tz) 238c2ecf20Sopenharmony_ci{ 248c2ecf20Sopenharmony_ci register struct timezone *tz asm("r1") = _tz; 258c2ecf20Sopenharmony_ci register struct __kernel_old_timeval *tv asm("r0") = _tv; 268c2ecf20Sopenharmony_ci register long ret asm ("r0"); 278c2ecf20Sopenharmony_ci register long nr asm("r7") = __NR_compat_gettimeofday; 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci asm volatile( 308c2ecf20Sopenharmony_ci " swi #0\n" 318c2ecf20Sopenharmony_ci : "=r" (ret) 328c2ecf20Sopenharmony_ci : "r" (tv), "r" (tz), "r" (nr) 338c2ecf20Sopenharmony_ci : "memory"); 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci return ret; 368c2ecf20Sopenharmony_ci} 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_cistatic __always_inline 398c2ecf20Sopenharmony_cilong clock_gettime_fallback(clockid_t _clkid, struct __kernel_timespec *_ts) 408c2ecf20Sopenharmony_ci{ 418c2ecf20Sopenharmony_ci register struct __kernel_timespec *ts asm("r1") = _ts; 428c2ecf20Sopenharmony_ci register clockid_t clkid asm("r0") = _clkid; 438c2ecf20Sopenharmony_ci register long ret asm ("r0"); 448c2ecf20Sopenharmony_ci register long nr asm("r7") = __NR_compat_clock_gettime64; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci asm volatile( 478c2ecf20Sopenharmony_ci " swi #0\n" 488c2ecf20Sopenharmony_ci : "=r" (ret) 498c2ecf20Sopenharmony_ci : "r" (clkid), "r" (ts), "r" (nr) 508c2ecf20Sopenharmony_ci : "memory"); 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci return ret; 538c2ecf20Sopenharmony_ci} 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_cistatic __always_inline 568c2ecf20Sopenharmony_cilong clock_gettime32_fallback(clockid_t _clkid, struct old_timespec32 *_ts) 578c2ecf20Sopenharmony_ci{ 588c2ecf20Sopenharmony_ci register struct old_timespec32 *ts asm("r1") = _ts; 598c2ecf20Sopenharmony_ci register clockid_t clkid asm("r0") = _clkid; 608c2ecf20Sopenharmony_ci register long ret asm ("r0"); 618c2ecf20Sopenharmony_ci register long nr asm("r7") = __NR_compat_clock_gettime; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci asm volatile( 648c2ecf20Sopenharmony_ci " swi #0\n" 658c2ecf20Sopenharmony_ci : "=r" (ret) 668c2ecf20Sopenharmony_ci : "r" (clkid), "r" (ts), "r" (nr) 678c2ecf20Sopenharmony_ci : "memory"); 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci return ret; 708c2ecf20Sopenharmony_ci} 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_cistatic __always_inline 738c2ecf20Sopenharmony_ciint clock_getres_fallback(clockid_t _clkid, struct __kernel_timespec *_ts) 748c2ecf20Sopenharmony_ci{ 758c2ecf20Sopenharmony_ci register struct __kernel_timespec *ts asm("r1") = _ts; 768c2ecf20Sopenharmony_ci register clockid_t clkid asm("r0") = _clkid; 778c2ecf20Sopenharmony_ci register long ret asm ("r0"); 788c2ecf20Sopenharmony_ci register long nr asm("r7") = __NR_compat_clock_getres_time64; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci asm volatile( 818c2ecf20Sopenharmony_ci " swi #0\n" 828c2ecf20Sopenharmony_ci : "=r" (ret) 838c2ecf20Sopenharmony_ci : "r" (clkid), "r" (ts), "r" (nr) 848c2ecf20Sopenharmony_ci : "memory"); 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci return ret; 878c2ecf20Sopenharmony_ci} 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_cistatic __always_inline 908c2ecf20Sopenharmony_ciint clock_getres32_fallback(clockid_t _clkid, struct old_timespec32 *_ts) 918c2ecf20Sopenharmony_ci{ 928c2ecf20Sopenharmony_ci register struct old_timespec32 *ts asm("r1") = _ts; 938c2ecf20Sopenharmony_ci register clockid_t clkid asm("r0") = _clkid; 948c2ecf20Sopenharmony_ci register long ret asm ("r0"); 958c2ecf20Sopenharmony_ci register long nr asm("r7") = __NR_compat_clock_getres; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci asm volatile( 988c2ecf20Sopenharmony_ci " swi #0\n" 998c2ecf20Sopenharmony_ci : "=r" (ret) 1008c2ecf20Sopenharmony_ci : "r" (clkid), "r" (ts), "r" (nr) 1018c2ecf20Sopenharmony_ci : "memory"); 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci return ret; 1048c2ecf20Sopenharmony_ci} 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_cistatic __always_inline u64 __arch_get_hw_counter(s32 clock_mode, 1078c2ecf20Sopenharmony_ci const struct vdso_data *vd) 1088c2ecf20Sopenharmony_ci{ 1098c2ecf20Sopenharmony_ci u64 res; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci /* 1128c2ecf20Sopenharmony_ci * Core checks for mode already, so this raced against a concurrent 1138c2ecf20Sopenharmony_ci * update. Return something. Core will do another round and then 1148c2ecf20Sopenharmony_ci * see the mode change and fallback to the syscall. 1158c2ecf20Sopenharmony_ci */ 1168c2ecf20Sopenharmony_ci if (clock_mode != VDSO_CLOCKMODE_ARCHTIMER) 1178c2ecf20Sopenharmony_ci return 0; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci /* 1208c2ecf20Sopenharmony_ci * This isb() is required to prevent that the counter value 1218c2ecf20Sopenharmony_ci * is speculated. 1228c2ecf20Sopenharmony_ci */ 1238c2ecf20Sopenharmony_ci isb(); 1248c2ecf20Sopenharmony_ci asm volatile("mrrc p15, 1, %Q0, %R0, c14" : "=r" (res)); 1258c2ecf20Sopenharmony_ci /* 1268c2ecf20Sopenharmony_ci * This isb() is required to prevent that the seq lock is 1278c2ecf20Sopenharmony_ci * speculated. 1288c2ecf20Sopenharmony_ci */ 1298c2ecf20Sopenharmony_ci isb(); 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci return res; 1328c2ecf20Sopenharmony_ci} 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_cistatic __always_inline const struct vdso_data *__arch_get_vdso_data(void) 1358c2ecf20Sopenharmony_ci{ 1368c2ecf20Sopenharmony_ci const struct vdso_data *ret; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci /* 1398c2ecf20Sopenharmony_ci * This simply puts &_vdso_data into ret. The reason why we don't use 1408c2ecf20Sopenharmony_ci * `ret = _vdso_data` is that the compiler tends to optimise this in a 1418c2ecf20Sopenharmony_ci * very suboptimal way: instead of keeping &_vdso_data in a register, 1428c2ecf20Sopenharmony_ci * it goes through a relocation almost every time _vdso_data must be 1438c2ecf20Sopenharmony_ci * accessed (even in subfunctions). This is both time and space 1448c2ecf20Sopenharmony_ci * consuming: each relocation uses a word in the code section, and it 1458c2ecf20Sopenharmony_ci * has to be loaded at runtime. 1468c2ecf20Sopenharmony_ci * 1478c2ecf20Sopenharmony_ci * This trick hides the assignment from the compiler. Since it cannot 1488c2ecf20Sopenharmony_ci * track where the pointer comes from, it will only use one relocation 1498c2ecf20Sopenharmony_ci * where __arch_get_vdso_data() is called, and then keep the result in 1508c2ecf20Sopenharmony_ci * a register. 1518c2ecf20Sopenharmony_ci */ 1528c2ecf20Sopenharmony_ci asm volatile("mov %0, %1" : "=r"(ret) : "r"(_vdso_data)); 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci return ret; 1558c2ecf20Sopenharmony_ci} 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci#ifdef CONFIG_TIME_NS 1588c2ecf20Sopenharmony_cistatic __always_inline const struct vdso_data *__arch_get_timens_vdso_data(void) 1598c2ecf20Sopenharmony_ci{ 1608c2ecf20Sopenharmony_ci const struct vdso_data *ret; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci /* See __arch_get_vdso_data(). */ 1638c2ecf20Sopenharmony_ci asm volatile("mov %0, %1" : "=r"(ret) : "r"(_timens_data)); 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci return ret; 1668c2ecf20Sopenharmony_ci} 1678c2ecf20Sopenharmony_ci#endif 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_cistatic inline bool vdso_clocksource_ok(const struct vdso_data *vd) 1708c2ecf20Sopenharmony_ci{ 1718c2ecf20Sopenharmony_ci return vd->clock_mode == VDSO_CLOCKMODE_ARCHTIMER; 1728c2ecf20Sopenharmony_ci} 1738c2ecf20Sopenharmony_ci#define vdso_clocksource_ok vdso_clocksource_ok 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci#endif /* !__ASSEMBLY__ */ 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci#endif /* __ASM_VDSO_GETTIMEOFDAY_H */ 178