18c2ecf20Sopenharmony_ci============================ 28c2ecf20Sopenharmony_ciKernel-provided User Helpers 38c2ecf20Sopenharmony_ci============================ 48c2ecf20Sopenharmony_ci 58c2ecf20Sopenharmony_ciThese are segment of kernel provided user code reachable from user space 68c2ecf20Sopenharmony_ciat a fixed address in kernel memory. This is used to provide user space 78c2ecf20Sopenharmony_ciwith some operations which require kernel help because of unimplemented 88c2ecf20Sopenharmony_cinative feature and/or instructions in many ARM CPUs. The idea is for this 98c2ecf20Sopenharmony_cicode to be executed directly in user mode for best efficiency but which is 108c2ecf20Sopenharmony_citoo intimate with the kernel counter part to be left to user libraries. 118c2ecf20Sopenharmony_ciIn fact this code might even differ from one CPU to another depending on 128c2ecf20Sopenharmony_cithe available instruction set, or whether it is a SMP systems. In other 138c2ecf20Sopenharmony_ciwords, the kernel reserves the right to change this code as needed without 148c2ecf20Sopenharmony_ciwarning. Only the entry points and their results as documented here are 158c2ecf20Sopenharmony_ciguaranteed to be stable. 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ciThis is different from (but doesn't preclude) a full blown VDSO 188c2ecf20Sopenharmony_ciimplementation, however a VDSO would prevent some assembly tricks with 198c2ecf20Sopenharmony_ciconstants that allows for efficient branching to those code segments. And 208c2ecf20Sopenharmony_cisince those code segments only use a few cycles before returning to user 218c2ecf20Sopenharmony_cicode, the overhead of a VDSO indirect far call would add a measurable 228c2ecf20Sopenharmony_cioverhead to such minimalistic operations. 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ciUser space is expected to bypass those helpers and implement those things 258c2ecf20Sopenharmony_ciinline (either in the code emitted directly by the compiler, or part of 268c2ecf20Sopenharmony_cithe implementation of a library call) when optimizing for a recent enough 278c2ecf20Sopenharmony_ciprocessor that has the necessary native support, but only if resulting 288c2ecf20Sopenharmony_cibinaries are already to be incompatible with earlier ARM processors due to 298c2ecf20Sopenharmony_ciusage of similar native instructions for other things. In other words 308c2ecf20Sopenharmony_cidon't make binaries unable to run on earlier processors just for the sake 318c2ecf20Sopenharmony_ciof not using these kernel helpers if your compiled code is not going to 328c2ecf20Sopenharmony_ciuse new instructions for other purpose. 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ciNew helpers may be added over time, so an older kernel may be missing some 358c2ecf20Sopenharmony_cihelpers present in a newer kernel. For this reason, programs must check 368c2ecf20Sopenharmony_cithe value of __kuser_helper_version (see below) before assuming that it is 378c2ecf20Sopenharmony_cisafe to call any particular helper. This check should ideally be 388c2ecf20Sopenharmony_ciperformed only once at process startup time, and execution aborted early 398c2ecf20Sopenharmony_ciif the required helpers are not provided by the kernel version that 408c2ecf20Sopenharmony_ciprocess is running on. 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_cikuser_helper_version 438c2ecf20Sopenharmony_ci-------------------- 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ciLocation: 0xffff0ffc 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ciReference declaration:: 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci extern int32_t __kuser_helper_version; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ciDefinition: 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci This field contains the number of helpers being implemented by the 548c2ecf20Sopenharmony_ci running kernel. User space may read this to determine the availability 558c2ecf20Sopenharmony_ci of a particular helper. 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ciUsage example:: 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci #define __kuser_helper_version (*(int32_t *)0xffff0ffc) 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci void check_kuser_version(void) 628c2ecf20Sopenharmony_ci { 638c2ecf20Sopenharmony_ci if (__kuser_helper_version < 2) { 648c2ecf20Sopenharmony_ci fprintf(stderr, "can't do atomic operations, kernel too old\n"); 658c2ecf20Sopenharmony_ci abort(); 668c2ecf20Sopenharmony_ci } 678c2ecf20Sopenharmony_ci } 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ciNotes: 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci User space may assume that the value of this field never changes 728c2ecf20Sopenharmony_ci during the lifetime of any single process. This means that this 738c2ecf20Sopenharmony_ci field can be read once during the initialisation of a library or 748c2ecf20Sopenharmony_ci startup phase of a program. 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_cikuser_get_tls 778c2ecf20Sopenharmony_ci------------- 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ciLocation: 0xffff0fe0 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ciReference prototype:: 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci void * __kuser_get_tls(void); 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ciInput: 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci lr = return address 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ciOutput: 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci r0 = TLS value 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ciClobbered registers: 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci none 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ciDefinition: 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci Get the TLS value as previously set via the __ARM_NR_set_tls syscall. 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ciUsage example:: 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci typedef void * (__kuser_get_tls_t)(void); 1048c2ecf20Sopenharmony_ci #define __kuser_get_tls (*(__kuser_get_tls_t *)0xffff0fe0) 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci void foo() 1078c2ecf20Sopenharmony_ci { 1088c2ecf20Sopenharmony_ci void *tls = __kuser_get_tls(); 1098c2ecf20Sopenharmony_ci printf("TLS = %p\n", tls); 1108c2ecf20Sopenharmony_ci } 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ciNotes: 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci - Valid only if __kuser_helper_version >= 1 (from kernel version 2.6.12). 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_cikuser_cmpxchg 1178c2ecf20Sopenharmony_ci------------- 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ciLocation: 0xffff0fc0 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ciReference prototype:: 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci int __kuser_cmpxchg(int32_t oldval, int32_t newval, volatile int32_t *ptr); 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ciInput: 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci r0 = oldval 1288c2ecf20Sopenharmony_ci r1 = newval 1298c2ecf20Sopenharmony_ci r2 = ptr 1308c2ecf20Sopenharmony_ci lr = return address 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ciOutput: 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci r0 = success code (zero or non-zero) 1358c2ecf20Sopenharmony_ci C flag = set if r0 == 0, clear if r0 != 0 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ciClobbered registers: 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci r3, ip, flags 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ciDefinition: 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci Atomically store newval in `*ptr` only if `*ptr` is equal to oldval. 1448c2ecf20Sopenharmony_ci Return zero if `*ptr` was changed or non-zero if no exchange happened. 1458c2ecf20Sopenharmony_ci The C flag is also set if `*ptr` was changed to allow for assembly 1468c2ecf20Sopenharmony_ci optimization in the calling code. 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ciUsage example:: 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci typedef int (__kuser_cmpxchg_t)(int oldval, int newval, volatile int *ptr); 1518c2ecf20Sopenharmony_ci #define __kuser_cmpxchg (*(__kuser_cmpxchg_t *)0xffff0fc0) 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci int atomic_add(volatile int *ptr, int val) 1548c2ecf20Sopenharmony_ci { 1558c2ecf20Sopenharmony_ci int old, new; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci do { 1588c2ecf20Sopenharmony_ci old = *ptr; 1598c2ecf20Sopenharmony_ci new = old + val; 1608c2ecf20Sopenharmony_ci } while(__kuser_cmpxchg(old, new, ptr)); 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci return new; 1638c2ecf20Sopenharmony_ci } 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ciNotes: 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci - This routine already includes memory barriers as needed. 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci - Valid only if __kuser_helper_version >= 2 (from kernel version 2.6.12). 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_cikuser_memory_barrier 1728c2ecf20Sopenharmony_ci-------------------- 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ciLocation: 0xffff0fa0 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ciReference prototype:: 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci void __kuser_memory_barrier(void); 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ciInput: 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci lr = return address 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ciOutput: 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci none 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ciClobbered registers: 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci none 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ciDefinition: 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci Apply any needed memory barrier to preserve consistency with data modified 1958c2ecf20Sopenharmony_ci manually and __kuser_cmpxchg usage. 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ciUsage example:: 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci typedef void (__kuser_dmb_t)(void); 2008c2ecf20Sopenharmony_ci #define __kuser_dmb (*(__kuser_dmb_t *)0xffff0fa0) 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ciNotes: 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci - Valid only if __kuser_helper_version >= 3 (from kernel version 2.6.15). 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_cikuser_cmpxchg64 2078c2ecf20Sopenharmony_ci--------------- 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ciLocation: 0xffff0f60 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ciReference prototype:: 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci int __kuser_cmpxchg64(const int64_t *oldval, 2148c2ecf20Sopenharmony_ci const int64_t *newval, 2158c2ecf20Sopenharmony_ci volatile int64_t *ptr); 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ciInput: 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci r0 = pointer to oldval 2208c2ecf20Sopenharmony_ci r1 = pointer to newval 2218c2ecf20Sopenharmony_ci r2 = pointer to target value 2228c2ecf20Sopenharmony_ci lr = return address 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ciOutput: 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci r0 = success code (zero or non-zero) 2278c2ecf20Sopenharmony_ci C flag = set if r0 == 0, clear if r0 != 0 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ciClobbered registers: 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci r3, lr, flags 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ciDefinition: 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci Atomically store the 64-bit value pointed by `*newval` in `*ptr` only if `*ptr` 2368c2ecf20Sopenharmony_ci is equal to the 64-bit value pointed by `*oldval`. Return zero if `*ptr` was 2378c2ecf20Sopenharmony_ci changed or non-zero if no exchange happened. 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci The C flag is also set if `*ptr` was changed to allow for assembly 2408c2ecf20Sopenharmony_ci optimization in the calling code. 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ciUsage example:: 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci typedef int (__kuser_cmpxchg64_t)(const int64_t *oldval, 2458c2ecf20Sopenharmony_ci const int64_t *newval, 2468c2ecf20Sopenharmony_ci volatile int64_t *ptr); 2478c2ecf20Sopenharmony_ci #define __kuser_cmpxchg64 (*(__kuser_cmpxchg64_t *)0xffff0f60) 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci int64_t atomic_add64(volatile int64_t *ptr, int64_t val) 2508c2ecf20Sopenharmony_ci { 2518c2ecf20Sopenharmony_ci int64_t old, new; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci do { 2548c2ecf20Sopenharmony_ci old = *ptr; 2558c2ecf20Sopenharmony_ci new = old + val; 2568c2ecf20Sopenharmony_ci } while(__kuser_cmpxchg64(&old, &new, ptr)); 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci return new; 2598c2ecf20Sopenharmony_ci } 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ciNotes: 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci - This routine already includes memory barriers as needed. 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci - Due to the length of this sequence, this spans 2 conventional kuser 2668c2ecf20Sopenharmony_ci "slots", therefore 0xffff0f80 is not used as a valid entry point. 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci - Valid only if __kuser_helper_version >= 5 (from kernel version 3.1). 269