| Kernel-provided User Helpers | 
 | ============================ | 
 |  | 
 | These are segment of kernel provided user code reachable from user space | 
 | at a fixed address in kernel memory.  This is used to provide user space | 
 | with some operations which require kernel help because of unimplemented | 
 | native feature and/or instructions in many ARM CPUs. The idea is for this | 
 | code to be executed directly in user mode for best efficiency but which is | 
 | too intimate with the kernel counter part to be left to user libraries. | 
 | In fact this code might even differ from one CPU to another depending on | 
 | the available instruction set, or whether it is a SMP systems. In other | 
 | words, the kernel reserves the right to change this code as needed without | 
 | warning. Only the entry points and their results as documented here are | 
 | guaranteed to be stable. | 
 |  | 
 | This is different from (but doesn't preclude) a full blown VDSO | 
 | implementation, however a VDSO would prevent some assembly tricks with | 
 | constants that allows for efficient branching to those code segments. And | 
 | since those code segments only use a few cycles before returning to user | 
 | code, the overhead of a VDSO indirect far call would add a measurable | 
 | overhead to such minimalistic operations. | 
 |  | 
 | User space is expected to bypass those helpers and implement those things | 
 | inline (either in the code emitted directly by the compiler, or part of | 
 | the implementation of a library call) when optimizing for a recent enough | 
 | processor that has the necessary native support, but only if resulting | 
 | binaries are already to be incompatible with earlier ARM processors due to | 
 | usage of similar native instructions for other things.  In other words | 
 | don't make binaries unable to run on earlier processors just for the sake | 
 | of not using these kernel helpers if your compiled code is not going to | 
 | use new instructions for other purpose. | 
 |  | 
 | New helpers may be added over time, so an older kernel may be missing some | 
 | helpers present in a newer kernel.  For this reason, programs must check | 
 | the value of __kuser_helper_version (see below) before assuming that it is | 
 | safe to call any particular helper.  This check should ideally be | 
 | performed only once at process startup time, and execution aborted early | 
 | if the required helpers are not provided by the kernel version that | 
 | process is running on. | 
 |  | 
 | kuser_helper_version | 
 | -------------------- | 
 |  | 
 | Location:	0xffff0ffc | 
 |  | 
 | Reference declaration: | 
 |  | 
 |   extern int32_t __kuser_helper_version; | 
 |  | 
 | Definition: | 
 |  | 
 |   This field contains the number of helpers being implemented by the | 
 |   running kernel.  User space may read this to determine the availability | 
 |   of a particular helper. | 
 |  | 
 | Usage example: | 
 |  | 
 | #define __kuser_helper_version (*(int32_t *)0xffff0ffc) | 
 |  | 
 | void check_kuser_version(void) | 
 | { | 
 | 	if (__kuser_helper_version < 2) { | 
 | 		fprintf(stderr, "can't do atomic operations, kernel too old\n"); | 
 | 		abort(); | 
 | 	} | 
 | } | 
 |  | 
 | Notes: | 
 |  | 
 |   User space may assume that the value of this field never changes | 
 |   during the lifetime of any single process.  This means that this | 
 |   field can be read once during the initialisation of a library or | 
 |   startup phase of a program. | 
 |  | 
 | kuser_get_tls | 
 | ------------- | 
 |  | 
 | Location:	0xffff0fe0 | 
 |  | 
 | Reference prototype: | 
 |  | 
 |   void * __kuser_get_tls(void); | 
 |  | 
 | Input: | 
 |  | 
 |   lr = return address | 
 |  | 
 | Output: | 
 |  | 
 |   r0 = TLS value | 
 |  | 
 | Clobbered registers: | 
 |  | 
 |   none | 
 |  | 
 | Definition: | 
 |  | 
 |   Get the TLS value as previously set via the __ARM_NR_set_tls syscall. | 
 |  | 
 | Usage example: | 
 |  | 
 | typedef void * (__kuser_get_tls_t)(void); | 
 | #define __kuser_get_tls (*(__kuser_get_tls_t *)0xffff0fe0) | 
 |  | 
 | void foo() | 
 | { | 
 | 	void *tls = __kuser_get_tls(); | 
 | 	printf("TLS = %p\n", tls); | 
 | } | 
 |  | 
 | Notes: | 
 |  | 
 |   - Valid only if __kuser_helper_version >= 1 (from kernel version 2.6.12). | 
 |  | 
 | kuser_cmpxchg | 
 | ------------- | 
 |  | 
 | Location:	0xffff0fc0 | 
 |  | 
 | Reference prototype: | 
 |  | 
 |   int __kuser_cmpxchg(int32_t oldval, int32_t newval, volatile int32_t *ptr); | 
 |  | 
 | Input: | 
 |  | 
 |   r0 = oldval | 
 |   r1 = newval | 
 |   r2 = ptr | 
 |   lr = return address | 
 |  | 
 | Output: | 
 |  | 
 |   r0 = success code (zero or non-zero) | 
 |   C flag = set if r0 == 0, clear if r0 != 0 | 
 |  | 
 | Clobbered registers: | 
 |  | 
 |   r3, ip, flags | 
 |  | 
 | Definition: | 
 |  | 
 |   Atomically store newval in *ptr only if *ptr is equal to oldval. | 
 |   Return zero if *ptr was changed or non-zero if no exchange happened. | 
 |   The C flag is also set if *ptr was changed to allow for assembly | 
 |   optimization in the calling code. | 
 |  | 
 | Usage example: | 
 |  | 
 | typedef int (__kuser_cmpxchg_t)(int oldval, int newval, volatile int *ptr); | 
 | #define __kuser_cmpxchg (*(__kuser_cmpxchg_t *)0xffff0fc0) | 
 |  | 
 | int atomic_add(volatile int *ptr, int val) | 
 | { | 
 | 	int old, new; | 
 |  | 
 | 	do { | 
 | 		old = *ptr; | 
 | 		new = old + val; | 
 | 	} while(__kuser_cmpxchg(old, new, ptr)); | 
 |  | 
 | 	return new; | 
 | } | 
 |  | 
 | Notes: | 
 |  | 
 |   - This routine already includes memory barriers as needed. | 
 |  | 
 |   - Valid only if __kuser_helper_version >= 2 (from kernel version 2.6.12). | 
 |  | 
 | kuser_memory_barrier | 
 | -------------------- | 
 |  | 
 | Location:	0xffff0fa0 | 
 |  | 
 | Reference prototype: | 
 |  | 
 |   void __kuser_memory_barrier(void); | 
 |  | 
 | Input: | 
 |  | 
 |   lr = return address | 
 |  | 
 | Output: | 
 |  | 
 |   none | 
 |  | 
 | Clobbered registers: | 
 |  | 
 |   none | 
 |  | 
 | Definition: | 
 |  | 
 |   Apply any needed memory barrier to preserve consistency with data modified | 
 |   manually and __kuser_cmpxchg usage. | 
 |  | 
 | Usage example: | 
 |  | 
 | typedef void (__kuser_dmb_t)(void); | 
 | #define __kuser_dmb (*(__kuser_dmb_t *)0xffff0fa0) | 
 |  | 
 | Notes: | 
 |  | 
 |   - Valid only if __kuser_helper_version >= 3 (from kernel version 2.6.15). | 
 |  | 
 | kuser_cmpxchg64 | 
 | --------------- | 
 |  | 
 | Location:	0xffff0f60 | 
 |  | 
 | Reference prototype: | 
 |  | 
 |   int __kuser_cmpxchg64(const int64_t *oldval, | 
 |                         const int64_t *newval, | 
 |                         volatile int64_t *ptr); | 
 |  | 
 | Input: | 
 |  | 
 |   r0 = pointer to oldval | 
 |   r1 = pointer to newval | 
 |   r2 = pointer to target value | 
 |   lr = return address | 
 |  | 
 | Output: | 
 |  | 
 |   r0 = success code (zero or non-zero) | 
 |   C flag = set if r0 == 0, clear if r0 != 0 | 
 |  | 
 | Clobbered registers: | 
 |  | 
 |   r3, lr, flags | 
 |  | 
 | Definition: | 
 |  | 
 |   Atomically store the 64-bit value pointed by *newval in *ptr only if *ptr | 
 |   is equal to the 64-bit value pointed by *oldval.  Return zero if *ptr was | 
 |   changed or non-zero if no exchange happened. | 
 |  | 
 |   The C flag is also set if *ptr was changed to allow for assembly | 
 |   optimization in the calling code. | 
 |  | 
 | Usage example: | 
 |  | 
 | typedef int (__kuser_cmpxchg64_t)(const int64_t *oldval, | 
 |                                   const int64_t *newval, | 
 |                                   volatile int64_t *ptr); | 
 | #define __kuser_cmpxchg64 (*(__kuser_cmpxchg64_t *)0xffff0f60) | 
 |  | 
 | int64_t atomic_add64(volatile int64_t *ptr, int64_t val) | 
 | { | 
 | 	int64_t old, new; | 
 |  | 
 | 	do { | 
 | 		old = *ptr; | 
 | 		new = old + val; | 
 | 	} while(__kuser_cmpxchg64(&old, &new, ptr)); | 
 |  | 
 | 	return new; | 
 | } | 
 |  | 
 | Notes: | 
 |  | 
 |   - This routine already includes memory barriers as needed. | 
 |  | 
 |   - Due to the length of this sequence, this spans 2 conventional kuser | 
 |     "slots", therefore 0xffff0f80 is not used as a valid entry point. | 
 |  | 
 |   - Valid only if __kuser_helper_version >= 5 (from kernel version 3.1). |