clock_gettime.S 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. /*
  2. * Userland implementation of clock_gettime() for 64 bits processes in a
  3. * s390 kernel for use in the vDSO
  4. *
  5. * Copyright IBM Corp. 2008
  6. * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
  7. *
  8. * This program is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License (version 2 only)
  10. * as published by the Free Software Foundation.
  11. */
  12. #include <asm/vdso.h>
  13. #include <asm/asm-offsets.h>
  14. #include <asm/unistd.h>
  15. .text
  16. .align 4
  17. .globl __kernel_clock_gettime
  18. .type __kernel_clock_gettime,@function
  19. __kernel_clock_gettime:
  20. .cfi_startproc
  21. larl %r5,_vdso_data
  22. cghi %r2,__CLOCK_REALTIME
  23. je 4f
  24. cghi %r2,-2 /* CLOCK_THREAD_CPUTIME_ID for this thread */
  25. je 9f
  26. cghi %r2,__CLOCK_MONOTONIC
  27. jne 12f
  28. /* CLOCK_MONOTONIC */
  29. ltgr %r3,%r3
  30. jz 3f /* tp == NULL */
  31. 0: lg %r4,__VDSO_UPD_COUNT(%r5) /* load update counter */
  32. tmll %r4,0x0001 /* pending update ? loop */
  33. jnz 0b
  34. stck 48(%r15) /* Store TOD clock */
  35. lg %r1,48(%r15)
  36. sg %r1,__VDSO_XTIME_STAMP(%r5) /* TOD - cycle_last */
  37. msgf %r1,__VDSO_NTP_MULT(%r5) /* * NTP adjustment */
  38. srlg %r1,%r1,12 /* cyc2ns(clock,cycle_delta) */
  39. alg %r1,__VDSO_XTIME_NSEC(%r5) /* + xtime */
  40. lg %r0,__VDSO_XTIME_SEC(%r5)
  41. alg %r1,__VDSO_WTOM_NSEC(%r5) /* + wall_to_monotonic */
  42. alg %r0,__VDSO_WTOM_SEC(%r5)
  43. clg %r4,__VDSO_UPD_COUNT(%r5) /* check update counter */
  44. jne 0b
  45. larl %r5,13f
  46. 1: clg %r1,0(%r5)
  47. jl 2f
  48. slg %r1,0(%r5)
  49. aghi %r0,1
  50. j 1b
  51. 2: stg %r0,0(%r3) /* store tp->tv_sec */
  52. stg %r1,8(%r3) /* store tp->tv_nsec */
  53. 3: lghi %r2,0
  54. br %r14
  55. /* CLOCK_REALTIME */
  56. 4: ltr %r3,%r3 /* tp == NULL */
  57. jz 8f
  58. 5: lg %r4,__VDSO_UPD_COUNT(%r5) /* load update counter */
  59. tmll %r4,0x0001 /* pending update ? loop */
  60. jnz 5b
  61. stck 48(%r15) /* Store TOD clock */
  62. lg %r1,48(%r15)
  63. sg %r1,__VDSO_XTIME_STAMP(%r5) /* TOD - cycle_last */
  64. msgf %r1,__VDSO_NTP_MULT(%r5) /* * NTP adjustment */
  65. srlg %r1,%r1,12 /* cyc2ns(clock,cycle_delta) */
  66. alg %r1,__VDSO_XTIME_NSEC(%r5) /* + xtime */
  67. lg %r0,__VDSO_XTIME_SEC(%r5)
  68. clg %r4,__VDSO_UPD_COUNT(%r5) /* check update counter */
  69. jne 5b
  70. larl %r5,13f
  71. 6: clg %r1,0(%r5)
  72. jl 7f
  73. slg %r1,0(%r5)
  74. aghi %r0,1
  75. j 6b
  76. 7: stg %r0,0(%r3) /* store tp->tv_sec */
  77. stg %r1,8(%r3) /* store tp->tv_nsec */
  78. 8: lghi %r2,0
  79. br %r14
  80. /* CLOCK_THREAD_CPUTIME_ID for this thread */
  81. 9: icm %r0,15,__VDSO_ECTG_OK(%r5)
  82. jz 12f
  83. ear %r2,%a4
  84. llilh %r4,0x0100
  85. sar %a4,%r4
  86. lghi %r4,0
  87. epsw %r5,0
  88. sacf 512 /* Magic ectg instruction */
  89. .insn ssf,0xc80100000000,__VDSO_ECTG_BASE(4),__VDSO_ECTG_USER(4),4
  90. tml %r5,0x4000
  91. jo 11f
  92. tml %r5,0x8000
  93. jno 10f
  94. sacf 256
  95. j 11f
  96. 10: sacf 0
  97. 11: sar %a4,%r2
  98. algr %r1,%r0 /* r1 = cputime as TOD value */
  99. mghi %r1,1000 /* convert to nanoseconds */
  100. srlg %r1,%r1,12 /* r1 = cputime in nanosec */
  101. lgr %r4,%r1
  102. larl %r5,13f
  103. srlg %r1,%r1,9 /* divide by 1000000000 */
  104. mlg %r0,8(%r5)
  105. srlg %r0,%r0,11 /* r0 = tv_sec */
  106. stg %r0,0(%r3)
  107. msg %r0,0(%r5) /* calculate tv_nsec */
  108. slgr %r4,%r0 /* r4 = tv_nsec */
  109. stg %r4,8(%r3)
  110. lghi %r2,0
  111. br %r14
  112. /* Fallback to system call */
  113. 12: lghi %r1,__NR_clock_gettime
  114. svc 0
  115. br %r14
  116. 13: .quad 1000000000
  117. 14: .quad 19342813113834067
  118. .cfi_endproc
  119. .size __kernel_clock_gettime,.-__kernel_clock_gettime