gettimeofday.S 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  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. seqcnt .req w7
  27. w_tmp .req w8
  28. x_tmp .req x8
  29. /*
  30. * Conventions for macro arguments:
  31. * - An argument is write-only if its name starts with "res".
  32. * - All other arguments are read-only, unless otherwise specified.
  33. */
  34. .macro seqcnt_acquire
  35. 9999: ldr seqcnt, [vdso_data, #VDSO_TB_SEQ_COUNT]
  36. tbnz seqcnt, #0, 9999b
  37. dmb ishld
  38. .endm
  39. .macro seqcnt_check fail
  40. dmb ishld
  41. ldr w_tmp, [vdso_data, #VDSO_TB_SEQ_COUNT]
  42. cmp w_tmp, seqcnt
  43. b.ne \fail
  44. .endm
  45. .macro syscall_check fail
  46. ldr w_tmp, [vdso_data, #VDSO_USE_SYSCALL]
  47. cbnz w_tmp, \fail
  48. .endm
  49. .macro get_nsec_per_sec res
  50. mov \res, #NSEC_PER_SEC_LO16
  51. movk \res, #NSEC_PER_SEC_HI16, lsl #16
  52. .endm
  53. /*
  54. * Returns the clock delta, in nanoseconds left-shifted by the clock
  55. * shift.
  56. */
  57. .macro get_clock_shifted_nsec res, cycle_last, mult
  58. /* Read the virtual counter. */
  59. isb
  60. mrs x_tmp, cntvct_el0
  61. /* Calculate cycle delta and convert to ns. */
  62. sub \res, x_tmp, \cycle_last
  63. /* We can only guarantee 56 bits of precision. */
  64. movn x_tmp, #0xff00, lsl #48
  65. and \res, x_tmp, \res
  66. mul \res, \res, \mult
  67. .endm
  68. /*
  69. * Returns in res_{sec,nsec} the REALTIME timespec, based on the
  70. * "wall time" (xtime) and the clock_mono delta.
  71. */
  72. .macro get_ts_realtime res_sec, res_nsec, \
  73. clock_nsec, xtime_sec, xtime_nsec, nsec_to_sec
  74. add \res_nsec, \clock_nsec, \xtime_nsec
  75. udiv x_tmp, \res_nsec, \nsec_to_sec
  76. add \res_sec, \xtime_sec, x_tmp
  77. msub \res_nsec, x_tmp, \nsec_to_sec, \res_nsec
  78. .endm
  79. /*
  80. * Returns in res_{sec,nsec} the timespec based on the clock_raw delta,
  81. * used for CLOCK_MONOTONIC_RAW.
  82. */
  83. .macro get_ts_clock_raw res_sec, res_nsec, clock_nsec, nsec_to_sec
  84. udiv \res_sec, \clock_nsec, \nsec_to_sec
  85. msub \res_nsec, \res_sec, \nsec_to_sec, \clock_nsec
  86. .endm
  87. /* sec and nsec are modified in place. */
  88. .macro add_ts sec, nsec, ts_sec, ts_nsec, nsec_to_sec
  89. /* Add timespec. */
  90. add \sec, \sec, \ts_sec
  91. add \nsec, \nsec, \ts_nsec
  92. /* Normalise the new timespec. */
  93. cmp \nsec, \nsec_to_sec
  94. b.lt 9999f
  95. sub \nsec, \nsec, \nsec_to_sec
  96. add \sec, \sec, #1
  97. 9999:
  98. cmp \nsec, #0
  99. b.ge 9998f
  100. add \nsec, \nsec, \nsec_to_sec
  101. sub \sec, \sec, #1
  102. 9998:
  103. .endm
  104. .macro clock_gettime_return, shift=0
  105. .if \shift == 1
  106. lsr x11, x11, x12
  107. .endif
  108. stp x10, x11, [x1, #TSPEC_TV_SEC]
  109. mov x0, xzr
  110. ret
  111. .endm
  112. .macro jump_slot jumptable, index, label
  113. .if (. - \jumptable) != 4 * (\index)
  114. .error "Jump slot index mismatch"
  115. .endif
  116. b \label
  117. .endm
  118. .text
  119. /* int __kernel_gettimeofday(struct timeval *tv, struct timezone *tz); */
  120. ENTRY(__kernel_gettimeofday)
  121. .cfi_startproc
  122. adr vdso_data, _vdso_data
  123. /* If tv is NULL, skip to the timezone code. */
  124. cbz x0, 2f
  125. /* Compute the time of day. */
  126. 1: seqcnt_acquire
  127. syscall_check fail=4f
  128. ldr x10, [vdso_data, #VDSO_CS_CYCLE_LAST]
  129. /* w11 = cs_mono_mult, w12 = cs_shift */
  130. ldp w11, w12, [vdso_data, #VDSO_CS_MONO_MULT]
  131. ldp x13, x14, [vdso_data, #VDSO_XTIME_CLK_SEC]
  132. seqcnt_check fail=1b
  133. get_nsec_per_sec res=x9
  134. lsl x9, x9, x12
  135. get_clock_shifted_nsec res=x15, cycle_last=x10, mult=x11
  136. get_ts_realtime res_sec=x10, res_nsec=x11, \
  137. clock_nsec=x15, xtime_sec=x13, xtime_nsec=x14, nsec_to_sec=x9
  138. /* Convert ns to us. */
  139. mov x13, #1000
  140. lsl x13, x13, x12
  141. udiv x11, x11, x13
  142. stp x10, x11, [x0, #TVAL_TV_SEC]
  143. 2:
  144. /* If tz is NULL, return 0. */
  145. cbz x1, 3f
  146. ldp w4, w5, [vdso_data, #VDSO_TZ_MINWEST]
  147. stp w4, w5, [x1, #TZ_MINWEST]
  148. 3:
  149. mov x0, xzr
  150. ret
  151. 4:
  152. /* Syscall fallback. */
  153. mov x8, #__NR_gettimeofday
  154. svc #0
  155. ret
  156. .cfi_endproc
  157. ENDPROC(__kernel_gettimeofday)
  158. #define JUMPSLOT_MAX CLOCK_MONOTONIC_COARSE
  159. /* int __kernel_clock_gettime(clockid_t clock_id, struct timespec *tp); */
  160. ENTRY(__kernel_clock_gettime)
  161. .cfi_startproc
  162. cmp w0, #JUMPSLOT_MAX
  163. b.hi syscall
  164. adr vdso_data, _vdso_data
  165. adr x_tmp, jumptable
  166. add x_tmp, x_tmp, w0, uxtw #2
  167. br x_tmp
  168. ALIGN
  169. jumptable:
  170. jump_slot jumptable, CLOCK_REALTIME, realtime
  171. jump_slot jumptable, CLOCK_MONOTONIC, monotonic
  172. b syscall
  173. b syscall
  174. jump_slot jumptable, CLOCK_MONOTONIC_RAW, monotonic_raw
  175. jump_slot jumptable, CLOCK_REALTIME_COARSE, realtime_coarse
  176. jump_slot jumptable, CLOCK_MONOTONIC_COARSE, monotonic_coarse
  177. .if (. - jumptable) != 4 * (JUMPSLOT_MAX + 1)
  178. .error "Wrong jumptable size"
  179. .endif
  180. ALIGN
  181. realtime:
  182. seqcnt_acquire
  183. syscall_check fail=syscall
  184. ldr x10, [vdso_data, #VDSO_CS_CYCLE_LAST]
  185. /* w11 = cs_mono_mult, w12 = cs_shift */
  186. ldp w11, w12, [vdso_data, #VDSO_CS_MONO_MULT]
  187. ldp x13, x14, [vdso_data, #VDSO_XTIME_CLK_SEC]
  188. seqcnt_check fail=realtime
  189. /* All computations are done with left-shifted nsecs. */
  190. get_nsec_per_sec res=x9
  191. lsl x9, x9, x12
  192. get_clock_shifted_nsec res=x15, cycle_last=x10, mult=x11
  193. get_ts_realtime res_sec=x10, res_nsec=x11, \
  194. clock_nsec=x15, xtime_sec=x13, xtime_nsec=x14, nsec_to_sec=x9
  195. clock_gettime_return, shift=1
  196. ALIGN
  197. monotonic:
  198. seqcnt_acquire
  199. syscall_check fail=syscall
  200. ldr x10, [vdso_data, #VDSO_CS_CYCLE_LAST]
  201. /* w11 = cs_mono_mult, w12 = cs_shift */
  202. ldp w11, w12, [vdso_data, #VDSO_CS_MONO_MULT]
  203. ldp x13, x14, [vdso_data, #VDSO_XTIME_CLK_SEC]
  204. ldp x3, x4, [vdso_data, #VDSO_WTM_CLK_SEC]
  205. seqcnt_check fail=monotonic
  206. /* All computations are done with left-shifted nsecs. */
  207. lsl x4, x4, x12
  208. get_nsec_per_sec res=x9
  209. lsl x9, x9, x12
  210. get_clock_shifted_nsec res=x15, cycle_last=x10, mult=x11
  211. get_ts_realtime res_sec=x10, res_nsec=x11, \
  212. clock_nsec=x15, xtime_sec=x13, xtime_nsec=x14, nsec_to_sec=x9
  213. add_ts sec=x10, nsec=x11, ts_sec=x3, ts_nsec=x4, nsec_to_sec=x9
  214. clock_gettime_return, shift=1
  215. ALIGN
  216. monotonic_raw:
  217. seqcnt_acquire
  218. syscall_check fail=syscall
  219. ldr x10, [vdso_data, #VDSO_CS_CYCLE_LAST]
  220. /* w11 = cs_raw_mult, w12 = cs_shift */
  221. ldp w12, w11, [vdso_data, #VDSO_CS_SHIFT]
  222. ldp x13, x14, [vdso_data, #VDSO_RAW_TIME_SEC]
  223. seqcnt_check fail=monotonic_raw
  224. /* All computations are done with left-shifted nsecs. */
  225. get_nsec_per_sec res=x9
  226. lsl x9, x9, x12
  227. get_clock_shifted_nsec res=x15, cycle_last=x10, mult=x11
  228. get_ts_clock_raw res_sec=x10, res_nsec=x11, \
  229. clock_nsec=x15, nsec_to_sec=x9
  230. add_ts sec=x10, nsec=x11, ts_sec=x13, ts_nsec=x14, nsec_to_sec=x9
  231. clock_gettime_return, shift=1
  232. ALIGN
  233. realtime_coarse:
  234. seqcnt_acquire
  235. ldp x10, x11, [vdso_data, #VDSO_XTIME_CRS_SEC]
  236. seqcnt_check fail=realtime_coarse
  237. clock_gettime_return
  238. ALIGN
  239. monotonic_coarse:
  240. seqcnt_acquire
  241. ldp x10, x11, [vdso_data, #VDSO_XTIME_CRS_SEC]
  242. ldp x13, x14, [vdso_data, #VDSO_WTM_CLK_SEC]
  243. seqcnt_check fail=monotonic_coarse
  244. /* Computations are done in (non-shifted) nsecs. */
  245. get_nsec_per_sec res=x9
  246. add_ts sec=x10, nsec=x11, ts_sec=x13, ts_nsec=x14, nsec_to_sec=x9
  247. clock_gettime_return
  248. ALIGN
  249. syscall: /* Syscall fallback. */
  250. mov x8, #__NR_clock_gettime
  251. svc #0
  252. ret
  253. .cfi_endproc
  254. ENDPROC(__kernel_clock_gettime)
  255. /* int __kernel_clock_getres(clockid_t clock_id, struct timespec *res); */
  256. ENTRY(__kernel_clock_getres)
  257. .cfi_startproc
  258. cmp w0, #CLOCK_REALTIME
  259. ccmp w0, #CLOCK_MONOTONIC, #0x4, ne
  260. ccmp w0, #CLOCK_MONOTONIC_RAW, #0x4, ne
  261. b.ne 1f
  262. ldr x2, 5f
  263. b 2f
  264. 1:
  265. cmp w0, #CLOCK_REALTIME_COARSE
  266. ccmp w0, #CLOCK_MONOTONIC_COARSE, #0x4, ne
  267. b.ne 4f
  268. ldr x2, 6f
  269. 2:
  270. cbz w1, 3f
  271. stp xzr, x2, [x1]
  272. 3: /* res == NULL. */
  273. mov w0, wzr
  274. ret
  275. 4: /* Syscall fallback. */
  276. mov x8, #__NR_clock_getres
  277. svc #0
  278. ret
  279. 5:
  280. .quad CLOCK_REALTIME_RES
  281. 6:
  282. .quad CLOCK_COARSE_RES
  283. .cfi_endproc
  284. ENDPROC(__kernel_clock_getres)