brintos

brintos / linux-shallow public Read only

0
0
Text · 6.7 KiB · eb6f3d9 Raw
269 lines · plain
1============================2Kernel-provided User Helpers3============================4 5These are segment of kernel provided user code reachable from user space6at a fixed address in kernel memory.  This is used to provide user space7with some operations which require kernel help because of unimplemented8native feature and/or instructions in many ARM CPUs. The idea is for this9code to be executed directly in user mode for best efficiency but which is10too intimate with the kernel counter part to be left to user libraries.11In fact this code might even differ from one CPU to another depending on12the available instruction set, or whether it is a SMP systems. In other13words, the kernel reserves the right to change this code as needed without14warning. Only the entry points and their results as documented here are15guaranteed to be stable.16 17This is different from (but doesn't preclude) a full blown VDSO18implementation, however a VDSO would prevent some assembly tricks with19constants that allows for efficient branching to those code segments. And20since those code segments only use a few cycles before returning to user21code, the overhead of a VDSO indirect far call would add a measurable22overhead to such minimalistic operations.23 24User space is expected to bypass those helpers and implement those things25inline (either in the code emitted directly by the compiler, or part of26the implementation of a library call) when optimizing for a recent enough27processor that has the necessary native support, but only if resulting28binaries are already to be incompatible with earlier ARM processors due to29usage of similar native instructions for other things.  In other words30don't make binaries unable to run on earlier processors just for the sake31of not using these kernel helpers if your compiled code is not going to32use new instructions for other purpose.33 34New helpers may be added over time, so an older kernel may be missing some35helpers present in a newer kernel.  For this reason, programs must check36the value of __kuser_helper_version (see below) before assuming that it is37safe to call any particular helper.  This check should ideally be38performed only once at process startup time, and execution aborted early39if the required helpers are not provided by the kernel version that40process is running on.41 42kuser_helper_version43--------------------44 45Location:	0xffff0ffc46 47Reference declaration::48 49  extern int32_t __kuser_helper_version;50 51Definition:52 53  This field contains the number of helpers being implemented by the54  running kernel.  User space may read this to determine the availability55  of a particular helper.56 57Usage 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 69Notes:70 71  User space may assume that the value of this field never changes72  during the lifetime of any single process.  This means that this73  field can be read once during the initialisation of a library or74  startup phase of a program.75 76kuser_get_tls77-------------78 79Location:	0xffff0fe080 81Reference prototype::82 83  void * __kuser_get_tls(void);84 85Input:86 87  lr = return address88 89Output:90 91  r0 = TLS value92 93Clobbered registers:94 95  none96 97Definition:98 99  Get the TLS value as previously set via the __ARM_NR_set_tls syscall.100 101Usage 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 112Notes:113 114  - Valid only if __kuser_helper_version >= 1 (from kernel version 2.6.12).115 116kuser_cmpxchg117-------------118 119Location:	0xffff0fc0120 121Reference prototype::122 123  int __kuser_cmpxchg(int32_t oldval, int32_t newval, volatile int32_t *ptr);124 125Input:126 127  r0 = oldval128  r1 = newval129  r2 = ptr130  lr = return address131 132Output:133 134  r0 = success code (zero or non-zero)135  C flag = set if r0 == 0, clear if r0 != 0136 137Clobbered registers:138 139  r3, ip, flags140 141Definition: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 assembly146  optimization in the calling code.147 148Usage 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 165Notes: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 171kuser_memory_barrier172--------------------173 174Location:	0xffff0fa0175 176Reference prototype::177 178  void __kuser_memory_barrier(void);179 180Input:181 182  lr = return address183 184Output:185 186  none187 188Clobbered registers:189 190  none191 192Definition:193 194  Apply any needed memory barrier to preserve consistency with data modified195  manually and __kuser_cmpxchg usage.196 197Usage example::198 199  typedef void (__kuser_dmb_t)(void);200  #define __kuser_dmb (*(__kuser_dmb_t *)0xffff0fa0)201 202Notes:203 204  - Valid only if __kuser_helper_version >= 3 (from kernel version 2.6.15).205 206kuser_cmpxchg64207---------------208 209Location:	0xffff0f60210 211Reference prototype::212 213  int __kuser_cmpxchg64(const int64_t *oldval,214                        const int64_t *newval,215                        volatile int64_t *ptr);216 217Input:218 219  r0 = pointer to oldval220  r1 = pointer to newval221  r2 = pointer to target value222  lr = return address223 224Output:225 226  r0 = success code (zero or non-zero)227  C flag = set if r0 == 0, clear if r0 != 0228 229Clobbered registers:230 231  r3, lr, flags232 233Definition: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` was237  changed or non-zero if no exchange happened.238 239  The C flag is also set if `*ptr` was changed to allow for assembly240  optimization in the calling code.241 242Usage 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 261Notes:262 263  - This routine already includes memory barriers as needed.264 265  - Due to the length of this sequence, this spans 2 conventional kuser266    "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).269