cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

kernel_user_helpers.rst (6820B)


      1============================
      2Kernel-provided User Helpers
      3============================
      4
      5These are segment of kernel provided user code reachable from user space
      6at a fixed address in kernel memory.  This is used to provide user space
      7with some operations which require kernel help because of unimplemented
      8native feature and/or instructions in many ARM CPUs. The idea is for this
      9code to be executed directly in user mode for best efficiency but which is
     10too 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 on
     12the available instruction set, or whether it is a SMP systems. In other
     13words, the kernel reserves the right to change this code as needed without
     14warning. Only the entry points and their results as documented here are
     15guaranteed to be stable.
     16
     17This is different from (but doesn't preclude) a full blown VDSO
     18implementation, however a VDSO would prevent some assembly tricks with
     19constants that allows for efficient branching to those code segments. And
     20since those code segments only use a few cycles before returning to user
     21code, the overhead of a VDSO indirect far call would add a measurable
     22overhead to such minimalistic operations.
     23
     24User space is expected to bypass those helpers and implement those things
     25inline (either in the code emitted directly by the compiler, or part of
     26the implementation of a library call) when optimizing for a recent enough
     27processor that has the necessary native support, but only if resulting
     28binaries are already to be incompatible with earlier ARM processors due to
     29usage of similar native instructions for other things.  In other words
     30don't make binaries unable to run on earlier processors just for the sake
     31of not using these kernel helpers if your compiled code is not going to
     32use new instructions for other purpose.
     33
     34New helpers may be added over time, so an older kernel may be missing some
     35helpers present in a newer kernel.  For this reason, programs must check
     36the value of __kuser_helper_version (see below) before assuming that it is
     37safe to call any particular helper.  This check should ideally be
     38performed only once at process startup time, and execution aborted early
     39if the required helpers are not provided by the kernel version that
     40process is running on.
     41
     42kuser_helper_version
     43--------------------
     44
     45Location:	0xffff0ffc
     46
     47Reference declaration::
     48
     49  extern int32_t __kuser_helper_version;
     50
     51Definition:
     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
     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 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
     76kuser_get_tls
     77-------------
     78
     79Location:	0xffff0fe0
     80
     81Reference prototype::
     82
     83  void * __kuser_get_tls(void);
     84
     85Input:
     86
     87  lr = return address
     88
     89Output:
     90
     91  r0 = TLS value
     92
     93Clobbered registers:
     94
     95  none
     96
     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_cmpxchg
    117-------------
    118
    119Location:	0xffff0fc0
    120
    121Reference prototype::
    122
    123  int __kuser_cmpxchg(int32_t oldval, int32_t newval, volatile int32_t *ptr);
    124
    125Input:
    126
    127  r0 = oldval
    128  r1 = newval
    129  r2 = ptr
    130  lr = return address
    131
    132Output:
    133
    134  r0 = success code (zero or non-zero)
    135  C flag = set if r0 == 0, clear if r0 != 0
    136
    137Clobbered registers:
    138
    139  r3, ip, flags
    140
    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 assembly
    146  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_barrier
    172--------------------
    173
    174Location:	0xffff0fa0
    175
    176Reference prototype::
    177
    178  void __kuser_memory_barrier(void);
    179
    180Input:
    181
    182  lr = return address
    183
    184Output:
    185
    186  none
    187
    188Clobbered registers:
    189
    190  none
    191
    192Definition:
    193
    194  Apply any needed memory barrier to preserve consistency with data modified
    195  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_cmpxchg64
    207---------------
    208
    209Location:	0xffff0f60
    210
    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 oldval
    220  r1 = pointer to newval
    221  r2 = pointer to target value
    222  lr = return address
    223
    224Output:
    225
    226  r0 = success code (zero or non-zero)
    227  C flag = set if r0 == 0, clear if r0 != 0
    228
    229Clobbered registers:
    230
    231  r3, lr, flags
    232
    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` 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
    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 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).