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