| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166 |
- /* SPDX-License-Identifier: GPL-2.0 */
- /*
- * Copyright (C) 2018 ARM Limited
- */
- #ifndef __ASM_VDSO_COMPAT_GETTIMEOFDAY_H
- #define __ASM_VDSO_COMPAT_GETTIMEOFDAY_H
- #ifndef __ASSEMBLER__
- #include <asm/barrier.h>
- #include <asm/unistd_compat_32.h>
- #include <asm/errno.h>
- #include <asm/vdso/compat_barrier.h>
- #define VDSO_HAS_CLOCK_GETRES 1
- #define BUILD_VDSO32 1
- static __always_inline
- int gettimeofday_fallback(struct __kernel_old_timeval *_tv,
- struct timezone *_tz)
- {
- register struct timezone *tz asm("r1") = _tz;
- register struct __kernel_old_timeval *tv asm("r0") = _tv;
- register long ret asm ("r0");
- register long nr asm("r7") = __NR_compat32_gettimeofday;
- asm volatile(
- " swi #0\n"
- : "=r" (ret)
- : "r" (tv), "r" (tz), "r" (nr)
- : "memory");
- return ret;
- }
- static __always_inline
- long clock_gettime_fallback(clockid_t _clkid, struct __kernel_timespec *_ts)
- {
- register struct __kernel_timespec *ts asm("r1") = _ts;
- register clockid_t clkid asm("r0") = _clkid;
- register long ret asm ("r0");
- register long nr asm("r7") = __NR_compat32_clock_gettime64;
- asm volatile(
- " swi #0\n"
- : "=r" (ret)
- : "r" (clkid), "r" (ts), "r" (nr)
- : "memory");
- return ret;
- }
- static __always_inline
- long clock_gettime32_fallback(clockid_t _clkid, struct old_timespec32 *_ts)
- {
- register struct old_timespec32 *ts asm("r1") = _ts;
- register clockid_t clkid asm("r0") = _clkid;
- register long ret asm ("r0");
- register long nr asm("r7") = __NR_compat32_clock_gettime;
- asm volatile(
- " swi #0\n"
- : "=r" (ret)
- : "r" (clkid), "r" (ts), "r" (nr)
- : "memory");
- return ret;
- }
- static __always_inline
- int clock_getres_fallback(clockid_t _clkid, struct __kernel_timespec *_ts)
- {
- register struct __kernel_timespec *ts asm("r1") = _ts;
- register clockid_t clkid asm("r0") = _clkid;
- register long ret asm ("r0");
- register long nr asm("r7") = __NR_compat32_clock_getres_time64;
- asm volatile(
- " swi #0\n"
- : "=r" (ret)
- : "r" (clkid), "r" (ts), "r" (nr)
- : "memory");
- return ret;
- }
- static __always_inline
- int clock_getres32_fallback(clockid_t _clkid, struct old_timespec32 *_ts)
- {
- register struct old_timespec32 *ts asm("r1") = _ts;
- register clockid_t clkid asm("r0") = _clkid;
- register long ret asm ("r0");
- register long nr asm("r7") = __NR_compat32_clock_getres;
- asm volatile(
- " swi #0\n"
- : "=r" (ret)
- : "r" (clkid), "r" (ts), "r" (nr)
- : "memory");
- return ret;
- }
- static __always_inline u64 __arch_get_hw_counter(s32 clock_mode,
- const struct vdso_time_data *vd)
- {
- u64 res;
- /*
- * Core checks for mode already, so this raced against a concurrent
- * update. Return something. Core will do another round and then
- * see the mode change and fallback to the syscall.
- */
- if (clock_mode != VDSO_CLOCKMODE_ARCHTIMER)
- return 0;
- /*
- * This isb() is required to prevent that the counter value
- * is speculated.
- */
- isb();
- asm volatile("mrrc p15, 1, %Q0, %R0, c14" : "=r" (res));
- /*
- * This isb() is required to prevent that the seq lock is
- * speculated.
- */
- isb();
- return res;
- }
- static __always_inline const struct vdso_time_data *__arch_get_vdso_u_time_data(void)
- {
- const struct vdso_time_data *ret;
- /*
- * This simply puts &_vdso_time_data into ret. The reason why we don't use
- * `ret = _vdso_time_data` is that the compiler tends to optimise this in a
- * very suboptimal way: instead of keeping &_vdso_time_data in a register,
- * it goes through a relocation almost every time _vdso_time_data must be
- * accessed (even in subfunctions). This is both time and space
- * consuming: each relocation uses a word in the code section, and it
- * has to be loaded at runtime.
- *
- * This trick hides the assignment from the compiler. Since it cannot
- * track where the pointer comes from, it will only use one relocation
- * where __aarch64_get_vdso_u_time_data() is called, and then keep the
- * result in a register.
- */
- asm volatile("mov %0, %1" : "=r"(ret) : "r"(&vdso_u_time_data));
- return ret;
- }
- #define __arch_get_vdso_u_time_data __arch_get_vdso_u_time_data
- static inline bool vdso_clocksource_ok(const struct vdso_clock *vc)
- {
- return vc->clock_mode == VDSO_CLOCKMODE_ARCHTIMER;
- }
- #define vdso_clocksource_ok vdso_clocksource_ok
- #endif /* !__ASSEMBLER__ */
- #endif /* __ASM_VDSO_COMPAT_GETTIMEOFDAY_H */
|