gettimeofday.S 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. /*
  2. * Userspace implementations of gettimeofday() and friends.
  3. *
  4. * Copyright (C) 2012 ARM Limited
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License version 2 as
  8. * published by the Free Software Foundation.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. *
  18. * Author: Will Deacon <will.deacon@arm.com>
  19. */
  20. #include <linux/linkage.h>
  21. #include <asm/asm-offsets.h>
  22. #include <asm/unistd.h>
  23. #define NSEC_PER_SEC_LO16 0xca00
  24. #define NSEC_PER_SEC_HI16 0x3b9a
  25. vdso_data .req x6
  26. use_syscall .req w7
  27. seqcnt .req w8
  28. .macro seqcnt_acquire
  29. 9999: ldr seqcnt, [vdso_data, #VDSO_TB_SEQ_COUNT]
  30. tbnz seqcnt, #0, 9999b
  31. dmb ishld
  32. ldr use_syscall, [vdso_data, #VDSO_USE_SYSCALL]
  33. .endm
  34. .macro seqcnt_read, cnt
  35. dmb ishld
  36. ldr \cnt, [vdso_data, #VDSO_TB_SEQ_COUNT]
  37. .endm
  38. .macro seqcnt_check, cnt, fail
  39. cmp \cnt, seqcnt
  40. b.ne \fail
  41. .endm
  42. .text
  43. /* int __kernel_gettimeofday(struct timeval *tv, struct timezone *tz); */
  44. ENTRY(__kernel_gettimeofday)
  45. .cfi_startproc
  46. mov x2, x30
  47. .cfi_register x30, x2
  48. /* Acquire the sequence counter and get the timespec. */
  49. adr vdso_data, _vdso_data
  50. 1: seqcnt_acquire
  51. cbnz use_syscall, 4f
  52. /* If tv is NULL, skip to the timezone code. */
  53. cbz x0, 2f
  54. bl __do_get_tspec
  55. seqcnt_check w9, 1b
  56. /* Convert ns to us. */
  57. mov x13, #1000
  58. lsl x13, x13, x12
  59. udiv x11, x11, x13
  60. stp x10, x11, [x0, #TVAL_TV_SEC]
  61. 2:
  62. /* If tz is NULL, return 0. */
  63. cbz x1, 3f
  64. ldp w4, w5, [vdso_data, #VDSO_TZ_MINWEST]
  65. seqcnt_read w9
  66. seqcnt_check w9, 1b
  67. stp w4, w5, [x1, #TZ_MINWEST]
  68. 3:
  69. mov x0, xzr
  70. ret x2
  71. 4:
  72. /* Syscall fallback. */
  73. mov x8, #__NR_gettimeofday
  74. svc #0
  75. ret x2
  76. .cfi_endproc
  77. ENDPROC(__kernel_gettimeofday)
  78. /* int __kernel_clock_gettime(clockid_t clock_id, struct timespec *tp); */
  79. ENTRY(__kernel_clock_gettime)
  80. .cfi_startproc
  81. cmp w0, #CLOCK_REALTIME
  82. ccmp w0, #CLOCK_MONOTONIC, #0x4, ne
  83. b.ne 2f
  84. mov x2, x30
  85. .cfi_register x30, x2
  86. /* Get kernel timespec. */
  87. adr vdso_data, _vdso_data
  88. 1: seqcnt_acquire
  89. cbnz use_syscall, 7f
  90. bl __do_get_tspec
  91. seqcnt_check w9, 1b
  92. cmp w0, #CLOCK_MONOTONIC
  93. b.ne 6f
  94. /* Get wtm timespec. */
  95. ldp x13, x14, [vdso_data, #VDSO_WTM_CLK_SEC]
  96. /* Check the sequence counter. */
  97. seqcnt_read w9
  98. seqcnt_check w9, 1b
  99. b 4f
  100. 2:
  101. cmp w0, #CLOCK_REALTIME_COARSE
  102. ccmp w0, #CLOCK_MONOTONIC_COARSE, #0x4, ne
  103. b.ne 8f
  104. /* Get coarse timespec. */
  105. adr vdso_data, _vdso_data
  106. 3: seqcnt_acquire
  107. ldp x10, x11, [vdso_data, #VDSO_XTIME_CRS_SEC]
  108. /* Get wtm timespec. */
  109. ldp x13, x14, [vdso_data, #VDSO_WTM_CLK_SEC]
  110. /* Check the sequence counter. */
  111. seqcnt_read w9
  112. seqcnt_check w9, 3b
  113. cmp w0, #CLOCK_MONOTONIC_COARSE
  114. b.ne 6f
  115. 4:
  116. /* Add on wtm timespec. */
  117. add x10, x10, x13
  118. lsl x14, x14, x12
  119. add x11, x11, x14
  120. /* Normalise the new timespec. */
  121. mov x15, #NSEC_PER_SEC_LO16
  122. movk x15, #NSEC_PER_SEC_HI16, lsl #16
  123. lsl x15, x15, x12
  124. cmp x11, x15
  125. b.lt 5f
  126. sub x11, x11, x15
  127. add x10, x10, #1
  128. 5:
  129. cmp x11, #0
  130. b.ge 6f
  131. add x11, x11, x15
  132. sub x10, x10, #1
  133. 6: /* Store to the user timespec. */
  134. lsr x11, x11, x12
  135. stp x10, x11, [x1, #TSPEC_TV_SEC]
  136. mov x0, xzr
  137. ret x2
  138. 7:
  139. mov x30, x2
  140. 8: /* Syscall fallback. */
  141. mov x8, #__NR_clock_gettime
  142. svc #0
  143. ret
  144. .cfi_endproc
  145. ENDPROC(__kernel_clock_gettime)
  146. /* int __kernel_clock_getres(clockid_t clock_id, struct timespec *res); */
  147. ENTRY(__kernel_clock_getres)
  148. .cfi_startproc
  149. cbz w1, 3f
  150. cmp w0, #CLOCK_REALTIME
  151. ccmp w0, #CLOCK_MONOTONIC, #0x4, ne
  152. b.ne 1f
  153. ldr x2, 5f
  154. b 2f
  155. 1:
  156. cmp w0, #CLOCK_REALTIME_COARSE
  157. ccmp w0, #CLOCK_MONOTONIC_COARSE, #0x4, ne
  158. b.ne 4f
  159. ldr x2, 6f
  160. 2:
  161. stp xzr, x2, [x1]
  162. 3: /* res == NULL. */
  163. mov w0, wzr
  164. ret
  165. 4: /* Syscall fallback. */
  166. mov x8, #__NR_clock_getres
  167. svc #0
  168. ret
  169. 5:
  170. .quad CLOCK_REALTIME_RES
  171. 6:
  172. .quad CLOCK_COARSE_RES
  173. .cfi_endproc
  174. ENDPROC(__kernel_clock_getres)
  175. /*
  176. * Read the current time from the architected counter.
  177. * Expects vdso_data to be initialised.
  178. * Clobbers the temporary registers (x9 - x15).
  179. * Returns:
  180. * - w9 = vDSO sequence counter
  181. * - (x10, x11) = (ts->tv_sec, shifted ts->tv_nsec)
  182. * - w12 = cs_shift
  183. */
  184. ENTRY(__do_get_tspec)
  185. .cfi_startproc
  186. /* Read from the vDSO data page. */
  187. ldr x10, [vdso_data, #VDSO_CS_CYCLE_LAST]
  188. ldp x13, x14, [vdso_data, #VDSO_XTIME_CLK_SEC]
  189. ldp w11, w12, [vdso_data, #VDSO_CS_MULT]
  190. seqcnt_read w9
  191. /* Read the virtual counter. */
  192. isb
  193. mrs x15, cntvct_el0
  194. /* Calculate cycle delta and convert to ns. */
  195. sub x10, x15, x10
  196. /* We can only guarantee 56 bits of precision. */
  197. movn x15, #0xff00, lsl #48
  198. and x10, x15, x10
  199. mul x10, x10, x11
  200. /* Use the kernel time to calculate the new timespec. */
  201. mov x11, #NSEC_PER_SEC_LO16
  202. movk x11, #NSEC_PER_SEC_HI16, lsl #16
  203. lsl x11, x11, x12
  204. add x15, x10, x14
  205. udiv x14, x15, x11
  206. add x10, x13, x14
  207. mul x13, x14, x11
  208. sub x11, x15, x13
  209. ret
  210. .cfi_endproc
  211. ENDPROC(__do_get_tspec)