Back to home page

OSCL-LXR

 
 

    


0001 ============================
0002 Kernel-provided User Helpers
0003 ============================
0004 
0005 These are segment of kernel provided user code reachable from user space
0006 at a fixed address in kernel memory.  This is used to provide user space
0007 with some operations which require kernel help because of unimplemented
0008 native feature and/or instructions in many ARM CPUs. The idea is for this
0009 code to be executed directly in user mode for best efficiency but which is
0010 too intimate with the kernel counter part to be left to user libraries.
0011 In fact this code might even differ from one CPU to another depending on
0012 the available instruction set, or whether it is a SMP systems. In other
0013 words, the kernel reserves the right to change this code as needed without
0014 warning. Only the entry points and their results as documented here are
0015 guaranteed to be stable.
0016 
0017 This is different from (but doesn't preclude) a full blown VDSO
0018 implementation, however a VDSO would prevent some assembly tricks with
0019 constants that allows for efficient branching to those code segments. And
0020 since those code segments only use a few cycles before returning to user
0021 code, the overhead of a VDSO indirect far call would add a measurable
0022 overhead to such minimalistic operations.
0023 
0024 User space is expected to bypass those helpers and implement those things
0025 inline (either in the code emitted directly by the compiler, or part of
0026 the implementation of a library call) when optimizing for a recent enough
0027 processor that has the necessary native support, but only if resulting
0028 binaries are already to be incompatible with earlier ARM processors due to
0029 usage of similar native instructions for other things.  In other words
0030 don't make binaries unable to run on earlier processors just for the sake
0031 of not using these kernel helpers if your compiled code is not going to
0032 use new instructions for other purpose.
0033 
0034 New helpers may be added over time, so an older kernel may be missing some
0035 helpers present in a newer kernel.  For this reason, programs must check
0036 the value of __kuser_helper_version (see below) before assuming that it is
0037 safe to call any particular helper.  This check should ideally be
0038 performed only once at process startup time, and execution aborted early
0039 if the required helpers are not provided by the kernel version that
0040 process is running on.
0041 
0042 kuser_helper_version
0043 --------------------
0044 
0045 Location:       0xffff0ffc
0046 
0047 Reference declaration::
0048 
0049   extern int32_t __kuser_helper_version;
0050 
0051 Definition:
0052 
0053   This field contains the number of helpers being implemented by the
0054   running kernel.  User space may read this to determine the availability
0055   of a particular helper.
0056 
0057 Usage example::
0058 
0059   #define __kuser_helper_version (*(int32_t *)0xffff0ffc)
0060 
0061   void check_kuser_version(void)
0062   {
0063         if (__kuser_helper_version < 2) {
0064                 fprintf(stderr, "can't do atomic operations, kernel too old\n");
0065                 abort();
0066         }
0067   }
0068 
0069 Notes:
0070 
0071   User space may assume that the value of this field never changes
0072   during the lifetime of any single process.  This means that this
0073   field can be read once during the initialisation of a library or
0074   startup phase of a program.
0075 
0076 kuser_get_tls
0077 -------------
0078 
0079 Location:       0xffff0fe0
0080 
0081 Reference prototype::
0082 
0083   void * __kuser_get_tls(void);
0084 
0085 Input:
0086 
0087   lr = return address
0088 
0089 Output:
0090 
0091   r0 = TLS value
0092 
0093 Clobbered registers:
0094 
0095   none
0096 
0097 Definition:
0098 
0099   Get the TLS value as previously set via the __ARM_NR_set_tls syscall.
0100 
0101 Usage example::
0102 
0103   typedef void * (__kuser_get_tls_t)(void);
0104   #define __kuser_get_tls (*(__kuser_get_tls_t *)0xffff0fe0)
0105 
0106   void foo()
0107   {
0108         void *tls = __kuser_get_tls();
0109         printf("TLS = %p\n", tls);
0110   }
0111 
0112 Notes:
0113 
0114   - Valid only if __kuser_helper_version >= 1 (from kernel version 2.6.12).
0115 
0116 kuser_cmpxchg
0117 -------------
0118 
0119 Location:       0xffff0fc0
0120 
0121 Reference prototype::
0122 
0123   int __kuser_cmpxchg(int32_t oldval, int32_t newval, volatile int32_t *ptr);
0124 
0125 Input:
0126 
0127   r0 = oldval
0128   r1 = newval
0129   r2 = ptr
0130   lr = return address
0131 
0132 Output:
0133 
0134   r0 = success code (zero or non-zero)
0135   C flag = set if r0 == 0, clear if r0 != 0
0136 
0137 Clobbered registers:
0138 
0139   r3, ip, flags
0140 
0141 Definition:
0142 
0143   Atomically store newval in `*ptr` only if `*ptr` is equal to oldval.
0144   Return zero if `*ptr` was changed or non-zero if no exchange happened.
0145   The C flag is also set if `*ptr` was changed to allow for assembly
0146   optimization in the calling code.
0147 
0148 Usage example::
0149 
0150   typedef int (__kuser_cmpxchg_t)(int oldval, int newval, volatile int *ptr);
0151   #define __kuser_cmpxchg (*(__kuser_cmpxchg_t *)0xffff0fc0)
0152 
0153   int atomic_add(volatile int *ptr, int val)
0154   {
0155         int old, new;
0156 
0157         do {
0158                 old = *ptr;
0159                 new = old + val;
0160         } while(__kuser_cmpxchg(old, new, ptr));
0161 
0162         return new;
0163   }
0164 
0165 Notes:
0166 
0167   - This routine already includes memory barriers as needed.
0168 
0169   - Valid only if __kuser_helper_version >= 2 (from kernel version 2.6.12).
0170 
0171 kuser_memory_barrier
0172 --------------------
0173 
0174 Location:       0xffff0fa0
0175 
0176 Reference prototype::
0177 
0178   void __kuser_memory_barrier(void);
0179 
0180 Input:
0181 
0182   lr = return address
0183 
0184 Output:
0185 
0186   none
0187 
0188 Clobbered registers:
0189 
0190   none
0191 
0192 Definition:
0193 
0194   Apply any needed memory barrier to preserve consistency with data modified
0195   manually and __kuser_cmpxchg usage.
0196 
0197 Usage example::
0198 
0199   typedef void (__kuser_dmb_t)(void);
0200   #define __kuser_dmb (*(__kuser_dmb_t *)0xffff0fa0)
0201 
0202 Notes:
0203 
0204   - Valid only if __kuser_helper_version >= 3 (from kernel version 2.6.15).
0205 
0206 kuser_cmpxchg64
0207 ---------------
0208 
0209 Location:       0xffff0f60
0210 
0211 Reference prototype::
0212 
0213   int __kuser_cmpxchg64(const int64_t *oldval,
0214                         const int64_t *newval,
0215                         volatile int64_t *ptr);
0216 
0217 Input:
0218 
0219   r0 = pointer to oldval
0220   r1 = pointer to newval
0221   r2 = pointer to target value
0222   lr = return address
0223 
0224 Output:
0225 
0226   r0 = success code (zero or non-zero)
0227   C flag = set if r0 == 0, clear if r0 != 0
0228 
0229 Clobbered registers:
0230 
0231   r3, lr, flags
0232 
0233 Definition:
0234 
0235   Atomically store the 64-bit value pointed by `*newval` in `*ptr` only if `*ptr`
0236   is equal to the 64-bit value pointed by `*oldval`.  Return zero if `*ptr` was
0237   changed or non-zero if no exchange happened.
0238 
0239   The C flag is also set if `*ptr` was changed to allow for assembly
0240   optimization in the calling code.
0241 
0242 Usage example::
0243 
0244   typedef int (__kuser_cmpxchg64_t)(const int64_t *oldval,
0245                                     const int64_t *newval,
0246                                     volatile int64_t *ptr);
0247   #define __kuser_cmpxchg64 (*(__kuser_cmpxchg64_t *)0xffff0f60)
0248 
0249   int64_t atomic_add64(volatile int64_t *ptr, int64_t val)
0250   {
0251         int64_t old, new;
0252 
0253         do {
0254                 old = *ptr;
0255                 new = old + val;
0256         } while(__kuser_cmpxchg64(&old, &new, ptr));
0257 
0258         return new;
0259   }
0260 
0261 Notes:
0262 
0263   - This routine already includes memory barriers as needed.
0264 
0265   - Due to the length of this sequence, this spans 2 conventional kuser
0266     "slots", therefore 0xffff0f80 is not used as a valid entry point.
0267 
0268   - Valid only if __kuser_helper_version >= 5 (from kernel version 3.1).