kernel_user_helpers.txt 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. Kernel-provided User Helpers
  2. ============================
  3. These are segment of kernel provided user code reachable from user space
  4. at a fixed address in kernel memory. This is used to provide user space
  5. with some operations which require kernel help because of unimplemented
  6. native feature and/or instructions in many ARM CPUs. The idea is for this
  7. code to be executed directly in user mode for best efficiency but which is
  8. too intimate with the kernel counter part to be left to user libraries.
  9. In fact this code might even differ from one CPU to another depending on
  10. the available instruction set, or whether it is a SMP systems. In other
  11. words, the kernel reserves the right to change this code as needed without
  12. warning. Only the entry points and their results as documented here are
  13. guaranteed to be stable.
  14. This is different from (but doesn't preclude) a full blown VDSO
  15. implementation, however a VDSO would prevent some assembly tricks with
  16. constants that allows for efficient branching to those code segments. And
  17. since those code segments only use a few cycles before returning to user
  18. code, the overhead of a VDSO indirect far call would add a measurable
  19. overhead to such minimalistic operations.
  20. User space is expected to bypass those helpers and implement those things
  21. inline (either in the code emitted directly by the compiler, or part of
  22. the implementation of a library call) when optimizing for a recent enough
  23. processor that has the necessary native support, but only if resulting
  24. binaries are already to be incompatible with earlier ARM processors due to
  25. usage of similar native instructions for other things. In other words
  26. don't make binaries unable to run on earlier processors just for the sake
  27. of not using these kernel helpers if your compiled code is not going to
  28. use new instructions for other purpose.
  29. New helpers may be added over time, so an older kernel may be missing some
  30. helpers present in a newer kernel. For this reason, programs must check
  31. the value of __kuser_helper_version (see below) before assuming that it is
  32. safe to call any particular helper. This check should ideally be
  33. performed only once at process startup time, and execution aborted early
  34. if the required helpers are not provided by the kernel version that
  35. process is running on.
  36. kuser_helper_version
  37. --------------------
  38. Location: 0xffff0ffc
  39. Reference declaration:
  40. extern int32_t __kuser_helper_version;
  41. Definition:
  42. This field contains the number of helpers being implemented by the
  43. running kernel. User space may read this to determine the availability
  44. of a particular helper.
  45. Usage example:
  46. #define __kuser_helper_version (*(int32_t *)0xffff0ffc)
  47. void check_kuser_version(void)
  48. {
  49. if (__kuser_helper_version < 2) {
  50. fprintf(stderr, "can't do atomic operations, kernel too old\n");
  51. abort();
  52. }
  53. }
  54. Notes:
  55. User space may assume that the value of this field never changes
  56. during the lifetime of any single process. This means that this
  57. field can be read once during the initialisation of a library or
  58. startup phase of a program.
  59. kuser_get_tls
  60. -------------
  61. Location: 0xffff0fe0
  62. Reference prototype:
  63. void * __kuser_get_tls(void);
  64. Input:
  65. lr = return address
  66. Output:
  67. r0 = TLS value
  68. Clobbered registers:
  69. none
  70. Definition:
  71. Get the TLS value as previously set via the __ARM_NR_set_tls syscall.
  72. Usage example:
  73. typedef void * (__kuser_get_tls_t)(void);
  74. #define __kuser_get_tls (*(__kuser_get_tls_t *)0xffff0fe0)
  75. void foo()
  76. {
  77. void *tls = __kuser_get_tls();
  78. printf("TLS = %p\n", tls);
  79. }
  80. Notes:
  81. - Valid only if __kuser_helper_version >= 1 (from kernel version 2.6.12).
  82. kuser_cmpxchg
  83. -------------
  84. Location: 0xffff0fc0
  85. Reference prototype:
  86. int __kuser_cmpxchg(int32_t oldval, int32_t newval, volatile int32_t *ptr);
  87. Input:
  88. r0 = oldval
  89. r1 = newval
  90. r2 = ptr
  91. lr = return address
  92. Output:
  93. r0 = success code (zero or non-zero)
  94. C flag = set if r0 == 0, clear if r0 != 0
  95. Clobbered registers:
  96. r3, ip, flags
  97. Definition:
  98. Atomically store newval in *ptr only if *ptr is equal to oldval.
  99. Return zero if *ptr was changed or non-zero if no exchange happened.
  100. The C flag is also set if *ptr was changed to allow for assembly
  101. optimization in the calling code.
  102. Usage example:
  103. typedef int (__kuser_cmpxchg_t)(int oldval, int newval, volatile int *ptr);
  104. #define __kuser_cmpxchg (*(__kuser_cmpxchg_t *)0xffff0fc0)
  105. int atomic_add(volatile int *ptr, int val)
  106. {
  107. int old, new;
  108. do {
  109. old = *ptr;
  110. new = old + val;
  111. } while(__kuser_cmpxchg(old, new, ptr));
  112. return new;
  113. }
  114. Notes:
  115. - This routine already includes memory barriers as needed.
  116. - Valid only if __kuser_helper_version >= 2 (from kernel version 2.6.12).
  117. kuser_memory_barrier
  118. --------------------
  119. Location: 0xffff0fa0
  120. Reference prototype:
  121. void __kuser_memory_barrier(void);
  122. Input:
  123. lr = return address
  124. Output:
  125. none
  126. Clobbered registers:
  127. none
  128. Definition:
  129. Apply any needed memory barrier to preserve consistency with data modified
  130. manually and __kuser_cmpxchg usage.
  131. Usage example:
  132. typedef void (__kuser_dmb_t)(void);
  133. #define __kuser_dmb (*(__kuser_dmb_t *)0xffff0fa0)
  134. Notes:
  135. - Valid only if __kuser_helper_version >= 3 (from kernel version 2.6.15).
  136. kuser_cmpxchg64
  137. ---------------
  138. Location: 0xffff0f60
  139. Reference prototype:
  140. int __kuser_cmpxchg64(const int64_t *oldval,
  141. const int64_t *newval,
  142. volatile int64_t *ptr);
  143. Input:
  144. r0 = pointer to oldval
  145. r1 = pointer to newval
  146. r2 = pointer to target value
  147. lr = return address
  148. Output:
  149. r0 = success code (zero or non-zero)
  150. C flag = set if r0 == 0, clear if r0 != 0
  151. Clobbered registers:
  152. r3, lr, flags
  153. Definition:
  154. Atomically store the 64-bit value pointed by *newval in *ptr only if *ptr
  155. is equal to the 64-bit value pointed by *oldval. Return zero if *ptr was
  156. changed or non-zero if no exchange happened.
  157. The C flag is also set if *ptr was changed to allow for assembly
  158. optimization in the calling code.
  159. Usage example:
  160. typedef int (__kuser_cmpxchg64_t)(const int64_t *oldval,
  161. const int64_t *newval,
  162. volatile int64_t *ptr);
  163. #define __kuser_cmpxchg64 (*(__kuser_cmpxchg64_t *)0xffff0f60)
  164. int64_t atomic_add64(volatile int64_t *ptr, int64_t val)
  165. {
  166. int64_t old, new;
  167. do {
  168. old = *ptr;
  169. new = old + val;
  170. } while(__kuser_cmpxchg64(&old, &new, ptr));
  171. return new;
  172. }
  173. Notes:
  174. - This routine already includes memory barriers as needed.
  175. - Due to the length of this sequence, this spans 2 conventional kuser
  176. "slots", therefore 0xffff0f80 is not used as a valid entry point.
  177. - Valid only if __kuser_helper_version >= 5 (from kernel version 3.1).