gettimeofday.S 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  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 w13, 1b
  56. /* Convert ns to us. */
  57. mov x11, #1000
  58. udiv x10, x10, x11
  59. stp x9, x10, [x0, #TVAL_TV_SEC]
  60. 2:
  61. /* If tz is NULL, return 0. */
  62. cbz x1, 3f
  63. ldp w4, w5, [vdso_data, #VDSO_TZ_MINWEST]
  64. seqcnt_read w13
  65. seqcnt_check w13, 1b
  66. stp w4, w5, [x1, #TZ_MINWEST]
  67. 3:
  68. mov x0, xzr
  69. ret x2
  70. 4:
  71. /* Syscall fallback. */
  72. mov x8, #__NR_gettimeofday
  73. svc #0
  74. ret x2
  75. .cfi_endproc
  76. ENDPROC(__kernel_gettimeofday)
  77. /* int __kernel_clock_gettime(clockid_t clock_id, struct timespec *tp); */
  78. ENTRY(__kernel_clock_gettime)
  79. .cfi_startproc
  80. cmp w0, #CLOCK_REALTIME
  81. ccmp w0, #CLOCK_MONOTONIC, #0x4, ne
  82. b.ne 2f
  83. mov x2, x30
  84. .cfi_register x30, x2
  85. /* Get kernel timespec. */
  86. adr vdso_data, _vdso_data
  87. 1: seqcnt_acquire
  88. cbnz use_syscall, 7f
  89. bl __do_get_tspec
  90. seqcnt_check w13, 1b
  91. cmp w0, #CLOCK_MONOTONIC
  92. b.ne 6f
  93. /* Get wtm timespec. */
  94. ldp x14, x15, [vdso_data, #VDSO_WTM_CLK_SEC]
  95. /* Check the sequence counter. */
  96. seqcnt_read w13
  97. seqcnt_check w13, 1b
  98. b 4f
  99. 2:
  100. cmp w0, #CLOCK_REALTIME_COARSE
  101. ccmp w0, #CLOCK_MONOTONIC_COARSE, #0x4, ne
  102. b.ne 8f
  103. /* Get coarse timespec. */
  104. adr vdso_data, _vdso_data
  105. 3: seqcnt_acquire
  106. ldp x9, x10, [vdso_data, #VDSO_XTIME_CRS_SEC]
  107. cmp w0, #CLOCK_MONOTONIC_COARSE
  108. b.ne 6f
  109. /* Get wtm timespec. */
  110. ldp x14, x15, [vdso_data, #VDSO_WTM_CLK_SEC]
  111. /* Check the sequence counter. */
  112. seqcnt_read w13
  113. seqcnt_check w13, 3b
  114. 4:
  115. /* Add on wtm timespec. */
  116. add x9, x9, x14
  117. add x10, x10, x15
  118. /* Normalise the new timespec. */
  119. mov x14, #NSEC_PER_SEC_LO16
  120. movk x14, #NSEC_PER_SEC_HI16, lsl #16
  121. cmp x10, x14
  122. b.lt 5f
  123. sub x10, x10, x14
  124. add x9, x9, #1
  125. 5:
  126. cmp x10, #0
  127. b.ge 6f
  128. add x10, x10, x14
  129. sub x9, x9, #1
  130. 6: /* Store to the user timespec. */
  131. stp x9, x10, [x1, #TSPEC_TV_SEC]
  132. mov x0, xzr
  133. ret x2
  134. 7:
  135. mov x30, x2
  136. 8: /* Syscall fallback. */
  137. mov x8, #__NR_clock_gettime
  138. svc #0
  139. ret
  140. .cfi_endproc
  141. ENDPROC(__kernel_clock_gettime)
  142. /* int __kernel_clock_getres(clockid_t clock_id, struct timespec *res); */
  143. ENTRY(__kernel_clock_getres)
  144. .cfi_startproc
  145. cbz w1, 3f
  146. cmp w0, #CLOCK_REALTIME
  147. ccmp w0, #CLOCK_MONOTONIC, #0x4, ne
  148. b.ne 1f
  149. ldr x2, 5f
  150. b 2f
  151. 1:
  152. cmp w0, #CLOCK_REALTIME_COARSE
  153. ccmp w0, #CLOCK_MONOTONIC_COARSE, #0x4, ne
  154. b.ne 4f
  155. ldr x2, 6f
  156. 2:
  157. stp xzr, x2, [x1]
  158. 3: /* res == NULL. */
  159. mov w0, wzr
  160. ret
  161. 4: /* Syscall fallback. */
  162. mov x8, #__NR_clock_getres
  163. svc #0
  164. ret
  165. 5:
  166. .quad CLOCK_REALTIME_RES
  167. 6:
  168. .quad CLOCK_COARSE_RES
  169. .cfi_endproc
  170. ENDPROC(__kernel_clock_getres)
  171. /*
  172. * Read the current time from the architected counter.
  173. * Expects vdso_data to be initialised.
  174. * Clobbers the temporary registers (x9 - x15).
  175. * Returns:
  176. * - (x9, x10) = (ts->tv_sec, ts->tv_nsec)
  177. * - (x11, x12) = (xtime->tv_sec, xtime->tv_nsec)
  178. * - w13 = vDSO sequence counter
  179. */
  180. ENTRY(__do_get_tspec)
  181. .cfi_startproc
  182. /* Read from the vDSO data page. */
  183. ldr x10, [vdso_data, #VDSO_CS_CYCLE_LAST]
  184. ldp x11, x12, [vdso_data, #VDSO_XTIME_CLK_SEC]
  185. ldp w14, w15, [vdso_data, #VDSO_CS_MULT]
  186. seqcnt_read w13
  187. /* Read the physical counter. */
  188. isb
  189. mrs x9, cntpct_el0
  190. /* Calculate cycle delta and convert to ns. */
  191. sub x10, x9, x10
  192. /* We can only guarantee 56 bits of precision. */
  193. movn x9, #0xff0, lsl #48
  194. and x10, x9, x10
  195. mul x10, x10, x14
  196. lsr x10, x10, x15
  197. /* Use the kernel time to calculate the new timespec. */
  198. add x10, x12, x10
  199. mov x14, #NSEC_PER_SEC_LO16
  200. movk x14, #NSEC_PER_SEC_HI16, lsl #16
  201. udiv x15, x10, x14
  202. add x9, x15, x11
  203. mul x14, x14, x15
  204. sub x10, x10, x14
  205. ret
  206. .cfi_endproc
  207. ENDPROC(__do_get_tspec)