gettimeofday.S 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  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. /*
  68. * Fake address dependency from the value computed from the counter
  69. * register to subsequent data page accesses so that the sequence
  70. * locking also orders the read of the counter.
  71. */
  72. and x_tmp, \res, xzr
  73. add vdso_data, vdso_data, x_tmp
  74. .endm
  75. /*
  76. * Returns in res_{sec,nsec} the REALTIME timespec, based on the
  77. * "wall time" (xtime) and the clock_mono delta.
  78. */
  79. .macro get_ts_realtime res_sec, res_nsec, \
  80. clock_nsec, xtime_sec, xtime_nsec, nsec_to_sec
  81. add \res_nsec, \clock_nsec, \xtime_nsec
  82. udiv x_tmp, \res_nsec, \nsec_to_sec
  83. add \res_sec, \xtime_sec, x_tmp
  84. msub \res_nsec, x_tmp, \nsec_to_sec, \res_nsec
  85. .endm
  86. /*
  87. * Returns in res_{sec,nsec} the timespec based on the clock_raw delta,
  88. * used for CLOCK_MONOTONIC_RAW.
  89. */
  90. .macro get_ts_clock_raw res_sec, res_nsec, clock_nsec, nsec_to_sec
  91. udiv \res_sec, \clock_nsec, \nsec_to_sec
  92. msub \res_nsec, \res_sec, \nsec_to_sec, \clock_nsec
  93. .endm
  94. /* sec and nsec are modified in place. */
  95. .macro add_ts sec, nsec, ts_sec, ts_nsec, nsec_to_sec
  96. /* Add timespec. */
  97. add \sec, \sec, \ts_sec
  98. add \nsec, \nsec, \ts_nsec
  99. /* Normalise the new timespec. */
  100. cmp \nsec, \nsec_to_sec
  101. b.lt 9999f
  102. sub \nsec, \nsec, \nsec_to_sec
  103. add \sec, \sec, #1
  104. 9999:
  105. cmp \nsec, #0
  106. b.ge 9998f
  107. add \nsec, \nsec, \nsec_to_sec
  108. sub \sec, \sec, #1
  109. 9998:
  110. .endm
  111. .macro clock_gettime_return, shift=0
  112. .if \shift == 1
  113. lsr x11, x11, x12
  114. .endif
  115. stp x10, x11, [x1, #TSPEC_TV_SEC]
  116. mov x0, xzr
  117. ret
  118. .endm
  119. .macro jump_slot jumptable, index, label
  120. .if (. - \jumptable) != 4 * (\index)
  121. .error "Jump slot index mismatch"
  122. .endif
  123. b \label
  124. .endm
  125. .text
  126. /* int __kernel_gettimeofday(struct timeval *tv, struct timezone *tz); */
  127. ENTRY(__kernel_gettimeofday)
  128. .cfi_startproc
  129. adr vdso_data, _vdso_data
  130. /* If tv is NULL, skip to the timezone code. */
  131. cbz x0, 2f
  132. /* Compute the time of day. */
  133. 1: seqcnt_acquire
  134. syscall_check fail=4f
  135. ldr x10, [vdso_data, #VDSO_CS_CYCLE_LAST]
  136. /* w11 = cs_mono_mult, w12 = cs_shift */
  137. ldp w11, w12, [vdso_data, #VDSO_CS_MONO_MULT]
  138. ldp x13, x14, [vdso_data, #VDSO_XTIME_CLK_SEC]
  139. get_nsec_per_sec res=x9
  140. lsl x9, x9, x12
  141. get_clock_shifted_nsec res=x15, cycle_last=x10, mult=x11
  142. seqcnt_check fail=1b
  143. get_ts_realtime res_sec=x10, res_nsec=x11, \
  144. clock_nsec=x15, xtime_sec=x13, xtime_nsec=x14, nsec_to_sec=x9
  145. /* Convert ns to us. */
  146. mov x13, #1000
  147. lsl x13, x13, x12
  148. udiv x11, x11, x13
  149. stp x10, x11, [x0, #TVAL_TV_SEC]
  150. 2:
  151. /* If tz is NULL, return 0. */
  152. cbz x1, 3f
  153. ldp w4, w5, [vdso_data, #VDSO_TZ_MINWEST]
  154. stp w4, w5, [x1, #TZ_MINWEST]
  155. 3:
  156. mov x0, xzr
  157. ret
  158. 4:
  159. /* Syscall fallback. */
  160. mov x8, #__NR_gettimeofday
  161. svc #0
  162. ret
  163. .cfi_endproc
  164. ENDPROC(__kernel_gettimeofday)
  165. #define JUMPSLOT_MAX CLOCK_MONOTONIC_COARSE
  166. /* int __kernel_clock_gettime(clockid_t clock_id, struct timespec *tp); */
  167. ENTRY(__kernel_clock_gettime)
  168. .cfi_startproc
  169. cmp w0, #JUMPSLOT_MAX
  170. b.hi syscall
  171. adr vdso_data, _vdso_data
  172. adr x_tmp, jumptable
  173. add x_tmp, x_tmp, w0, uxtw #2
  174. br x_tmp
  175. ALIGN
  176. jumptable:
  177. jump_slot jumptable, CLOCK_REALTIME, realtime
  178. jump_slot jumptable, CLOCK_MONOTONIC, monotonic
  179. b syscall
  180. b syscall
  181. jump_slot jumptable, CLOCK_MONOTONIC_RAW, monotonic_raw
  182. jump_slot jumptable, CLOCK_REALTIME_COARSE, realtime_coarse
  183. jump_slot jumptable, CLOCK_MONOTONIC_COARSE, monotonic_coarse
  184. .if (. - jumptable) != 4 * (JUMPSLOT_MAX + 1)
  185. .error "Wrong jumptable size"
  186. .endif
  187. ALIGN
  188. realtime:
  189. seqcnt_acquire
  190. syscall_check fail=syscall
  191. ldr x10, [vdso_data, #VDSO_CS_CYCLE_LAST]
  192. /* w11 = cs_mono_mult, w12 = cs_shift */
  193. ldp w11, w12, [vdso_data, #VDSO_CS_MONO_MULT]
  194. ldp x13, x14, [vdso_data, #VDSO_XTIME_CLK_SEC]
  195. /* All computations are done with left-shifted nsecs. */
  196. get_nsec_per_sec res=x9
  197. lsl x9, x9, x12
  198. get_clock_shifted_nsec res=x15, cycle_last=x10, mult=x11
  199. seqcnt_check fail=realtime
  200. get_ts_realtime res_sec=x10, res_nsec=x11, \
  201. clock_nsec=x15, xtime_sec=x13, xtime_nsec=x14, nsec_to_sec=x9
  202. clock_gettime_return shift=1
  203. ALIGN
  204. monotonic:
  205. seqcnt_acquire
  206. syscall_check fail=syscall
  207. ldr x10, [vdso_data, #VDSO_CS_CYCLE_LAST]
  208. /* w11 = cs_mono_mult, w12 = cs_shift */
  209. ldp w11, w12, [vdso_data, #VDSO_CS_MONO_MULT]
  210. ldp x13, x14, [vdso_data, #VDSO_XTIME_CLK_SEC]
  211. ldp x3, x4, [vdso_data, #VDSO_WTM_CLK_SEC]
  212. /* All computations are done with left-shifted nsecs. */
  213. lsl x4, x4, x12
  214. get_nsec_per_sec res=x9
  215. lsl x9, x9, x12
  216. get_clock_shifted_nsec res=x15, cycle_last=x10, mult=x11
  217. seqcnt_check fail=monotonic
  218. get_ts_realtime res_sec=x10, res_nsec=x11, \
  219. clock_nsec=x15, xtime_sec=x13, xtime_nsec=x14, nsec_to_sec=x9
  220. add_ts sec=x10, nsec=x11, ts_sec=x3, ts_nsec=x4, nsec_to_sec=x9
  221. clock_gettime_return shift=1
  222. ALIGN
  223. monotonic_raw:
  224. seqcnt_acquire
  225. syscall_check fail=syscall
  226. ldr x10, [vdso_data, #VDSO_CS_CYCLE_LAST]
  227. /* w11 = cs_raw_mult, w12 = cs_shift */
  228. ldp w12, w11, [vdso_data, #VDSO_CS_SHIFT]
  229. ldp x13, x14, [vdso_data, #VDSO_RAW_TIME_SEC]
  230. /* All computations are done with left-shifted nsecs. */
  231. get_nsec_per_sec res=x9
  232. lsl x9, x9, x12
  233. get_clock_shifted_nsec res=x15, cycle_last=x10, mult=x11
  234. seqcnt_check fail=monotonic_raw
  235. get_ts_clock_raw res_sec=x10, res_nsec=x11, \
  236. clock_nsec=x15, nsec_to_sec=x9
  237. add_ts sec=x10, nsec=x11, ts_sec=x13, ts_nsec=x14, nsec_to_sec=x9
  238. clock_gettime_return shift=1
  239. ALIGN
  240. realtime_coarse:
  241. seqcnt_acquire
  242. ldp x10, x11, [vdso_data, #VDSO_XTIME_CRS_SEC]
  243. seqcnt_check fail=realtime_coarse
  244. clock_gettime_return
  245. ALIGN
  246. monotonic_coarse:
  247. seqcnt_acquire
  248. ldp x10, x11, [vdso_data, #VDSO_XTIME_CRS_SEC]
  249. ldp x13, x14, [vdso_data, #VDSO_WTM_CLK_SEC]
  250. seqcnt_check fail=monotonic_coarse
  251. /* Computations are done in (non-shifted) nsecs. */
  252. get_nsec_per_sec res=x9
  253. add_ts sec=x10, nsec=x11, ts_sec=x13, ts_nsec=x14, nsec_to_sec=x9
  254. clock_gettime_return
  255. ALIGN
  256. syscall: /* Syscall fallback. */
  257. mov x8, #__NR_clock_gettime
  258. svc #0
  259. ret
  260. .cfi_endproc
  261. ENDPROC(__kernel_clock_gettime)
  262. /* int __kernel_clock_getres(clockid_t clock_id, struct timespec *res); */
  263. ENTRY(__kernel_clock_getres)
  264. .cfi_startproc
  265. cmp w0, #CLOCK_REALTIME
  266. ccmp w0, #CLOCK_MONOTONIC, #0x4, ne
  267. ccmp w0, #CLOCK_MONOTONIC_RAW, #0x4, ne
  268. b.ne 1f
  269. adr vdso_data, _vdso_data
  270. ldr w2, [vdso_data, #CLOCK_REALTIME_RES]
  271. b 2f
  272. 1:
  273. cmp w0, #CLOCK_REALTIME_COARSE
  274. ccmp w0, #CLOCK_MONOTONIC_COARSE, #0x4, ne
  275. b.ne 4f
  276. ldr x2, 5f
  277. 2:
  278. cbz x1, 3f
  279. stp xzr, x2, [x1]
  280. 3: /* res == NULL. */
  281. mov w0, wzr
  282. ret
  283. 4: /* Syscall fallback. */
  284. mov x8, #__NR_clock_getres
  285. svc #0
  286. ret
  287. 5:
  288. .quad CLOCK_COARSE_RES
  289. .cfi_endproc
  290. ENDPROC(__kernel_clock_getres)