gettimeofday.S 5.1 KB

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