compat_gettimeofday.h 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. /* SPDX-License-Identifier: GPL-2.0 */
  2. /*
  3. * Copyright (C) 2018 ARM Limited
  4. */
  5. #ifndef __ASM_VDSO_COMPAT_GETTIMEOFDAY_H
  6. #define __ASM_VDSO_COMPAT_GETTIMEOFDAY_H
  7. #ifndef __ASSEMBLER__
  8. #include <asm/barrier.h>
  9. #include <asm/unistd_compat_32.h>
  10. #include <asm/errno.h>
  11. #include <asm/vdso/compat_barrier.h>
  12. #define VDSO_HAS_CLOCK_GETRES 1
  13. #define BUILD_VDSO32 1
  14. static __always_inline
  15. int gettimeofday_fallback(struct __kernel_old_timeval *_tv,
  16. struct timezone *_tz)
  17. {
  18. register struct timezone *tz asm("r1") = _tz;
  19. register struct __kernel_old_timeval *tv asm("r0") = _tv;
  20. register long ret asm ("r0");
  21. register long nr asm("r7") = __NR_compat32_gettimeofday;
  22. asm volatile(
  23. " swi #0\n"
  24. : "=r" (ret)
  25. : "r" (tv), "r" (tz), "r" (nr)
  26. : "memory");
  27. return ret;
  28. }
  29. static __always_inline
  30. long clock_gettime_fallback(clockid_t _clkid, struct __kernel_timespec *_ts)
  31. {
  32. register struct __kernel_timespec *ts asm("r1") = _ts;
  33. register clockid_t clkid asm("r0") = _clkid;
  34. register long ret asm ("r0");
  35. register long nr asm("r7") = __NR_compat32_clock_gettime64;
  36. asm volatile(
  37. " swi #0\n"
  38. : "=r" (ret)
  39. : "r" (clkid), "r" (ts), "r" (nr)
  40. : "memory");
  41. return ret;
  42. }
  43. static __always_inline
  44. long clock_gettime32_fallback(clockid_t _clkid, struct old_timespec32 *_ts)
  45. {
  46. register struct old_timespec32 *ts asm("r1") = _ts;
  47. register clockid_t clkid asm("r0") = _clkid;
  48. register long ret asm ("r0");
  49. register long nr asm("r7") = __NR_compat32_clock_gettime;
  50. asm volatile(
  51. " swi #0\n"
  52. : "=r" (ret)
  53. : "r" (clkid), "r" (ts), "r" (nr)
  54. : "memory");
  55. return ret;
  56. }
  57. static __always_inline
  58. int clock_getres_fallback(clockid_t _clkid, struct __kernel_timespec *_ts)
  59. {
  60. register struct __kernel_timespec *ts asm("r1") = _ts;
  61. register clockid_t clkid asm("r0") = _clkid;
  62. register long ret asm ("r0");
  63. register long nr asm("r7") = __NR_compat32_clock_getres_time64;
  64. asm volatile(
  65. " swi #0\n"
  66. : "=r" (ret)
  67. : "r" (clkid), "r" (ts), "r" (nr)
  68. : "memory");
  69. return ret;
  70. }
  71. static __always_inline
  72. int clock_getres32_fallback(clockid_t _clkid, struct old_timespec32 *_ts)
  73. {
  74. register struct old_timespec32 *ts asm("r1") = _ts;
  75. register clockid_t clkid asm("r0") = _clkid;
  76. register long ret asm ("r0");
  77. register long nr asm("r7") = __NR_compat32_clock_getres;
  78. asm volatile(
  79. " swi #0\n"
  80. : "=r" (ret)
  81. : "r" (clkid), "r" (ts), "r" (nr)
  82. : "memory");
  83. return ret;
  84. }
  85. static __always_inline u64 __arch_get_hw_counter(s32 clock_mode,
  86. const struct vdso_time_data *vd)
  87. {
  88. u64 res;
  89. /*
  90. * Core checks for mode already, so this raced against a concurrent
  91. * update. Return something. Core will do another round and then
  92. * see the mode change and fallback to the syscall.
  93. */
  94. if (clock_mode != VDSO_CLOCKMODE_ARCHTIMER)
  95. return 0;
  96. /*
  97. * This isb() is required to prevent that the counter value
  98. * is speculated.
  99. */
  100. isb();
  101. asm volatile("mrrc p15, 1, %Q0, %R0, c14" : "=r" (res));
  102. /*
  103. * This isb() is required to prevent that the seq lock is
  104. * speculated.
  105. */
  106. isb();
  107. return res;
  108. }
  109. static __always_inline const struct vdso_time_data *__arch_get_vdso_u_time_data(void)
  110. {
  111. const struct vdso_time_data *ret;
  112. /*
  113. * This simply puts &_vdso_time_data into ret. The reason why we don't use
  114. * `ret = _vdso_time_data` is that the compiler tends to optimise this in a
  115. * very suboptimal way: instead of keeping &_vdso_time_data in a register,
  116. * it goes through a relocation almost every time _vdso_time_data must be
  117. * accessed (even in subfunctions). This is both time and space
  118. * consuming: each relocation uses a word in the code section, and it
  119. * has to be loaded at runtime.
  120. *
  121. * This trick hides the assignment from the compiler. Since it cannot
  122. * track where the pointer comes from, it will only use one relocation
  123. * where __aarch64_get_vdso_u_time_data() is called, and then keep the
  124. * result in a register.
  125. */
  126. asm volatile("mov %0, %1" : "=r"(ret) : "r"(&vdso_u_time_data));
  127. return ret;
  128. }
  129. #define __arch_get_vdso_u_time_data __arch_get_vdso_u_time_data
  130. static inline bool vdso_clocksource_ok(const struct vdso_clock *vc)
  131. {
  132. return vc->clock_mode == VDSO_CLOCKMODE_ARCHTIMER;
  133. }
  134. #define vdso_clocksource_ok vdso_clocksource_ok
  135. #endif /* !__ASSEMBLER__ */
  136. #endif /* __ASM_VDSO_COMPAT_GETTIMEOFDAY_H */