1*e790a4ceSJonathan CorbetChinese translated version of Documentation/arch/arm/kernel_user_helpers.rst 2*e790a4ceSJonathan Corbet 3*e790a4ceSJonathan CorbetIf you have any comment or update to the content, please contact the 4*e790a4ceSJonathan Corbetoriginal document maintainer directly. However, if you have a problem 5*e790a4ceSJonathan Corbetcommunicating in English you can also ask the Chinese maintainer for 6*e790a4ceSJonathan Corbethelp. Contact the Chinese maintainer if this translation is outdated 7*e790a4ceSJonathan Corbetor if there is a problem with the translation. 8*e790a4ceSJonathan Corbet 9*e790a4ceSJonathan CorbetMaintainer: Nicolas Pitre <nicolas.pitre@linaro.org> 10*e790a4ceSJonathan Corbet Dave Martin <dave.martin@linaro.org> 11*e790a4ceSJonathan CorbetChinese maintainer: Fu Wei <tekkamanninja@gmail.com> 12*e790a4ceSJonathan Corbet--------------------------------------------------------------------- 13*e790a4ceSJonathan CorbetDocumentation/arch/arm/kernel_user_helpers.rst 的中文翻译 14*e790a4ceSJonathan Corbet 15*e790a4ceSJonathan Corbet如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文 16*e790a4ceSJonathan Corbet交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻 17*e790a4ceSJonathan Corbet译存在问题,请联系中文版维护者。 18*e790a4ceSJonathan Corbet英文版维护者: Nicolas Pitre <nicolas.pitre@linaro.org> 19*e790a4ceSJonathan Corbet Dave Martin <dave.martin@linaro.org> 20*e790a4ceSJonathan Corbet中文版维护者: 傅炜 Fu Wei <tekkamanninja@gmail.com> 21*e790a4ceSJonathan Corbet中文版翻译者: 傅炜 Fu Wei <tekkamanninja@gmail.com> 22*e790a4ceSJonathan Corbet中文版校译者: 宋冬生 Dongsheng Song <dongshneg.song@gmail.com> 23*e790a4ceSJonathan Corbet 傅炜 Fu Wei <tekkamanninja@gmail.com> 24*e790a4ceSJonathan Corbet 25*e790a4ceSJonathan Corbet 26*e790a4ceSJonathan Corbet以下为正文 27*e790a4ceSJonathan Corbet--------------------------------------------------------------------- 28*e790a4ceSJonathan Corbet内核提供的用户空间辅助代码 29*e790a4ceSJonathan Corbet========================= 30*e790a4ceSJonathan Corbet 31*e790a4ceSJonathan Corbet在内核内存空间的固定地址处,有一个由内核提供并可从用户空间访问的代码 32*e790a4ceSJonathan Corbet段。它用于向用户空间提供因在许多 ARM CPU 中未实现的特性和/或指令而需 33*e790a4ceSJonathan Corbet内核提供帮助的某些操作。这些代码直接在用户模式下执行的想法是为了获得 34*e790a4ceSJonathan Corbet最佳效率,但那些与内核计数器联系过于紧密的部分,则被留给了用户库实现。 35*e790a4ceSJonathan Corbet事实上,此代码甚至可能因不同的 CPU 而异,这取决于其可用的指令集或它 36*e790a4ceSJonathan Corbet是否为 SMP 系统。换句话说,内核保留在不作出警告的情况下根据需要更改 37*e790a4ceSJonathan Corbet这些代码的权利。只有本文档描述的入口及其结果是保证稳定的。 38*e790a4ceSJonathan Corbet 39*e790a4ceSJonathan Corbet这与完全成熟的 VDSO 实现不同(但两者并不冲突),尽管如此,VDSO 可阻止 40*e790a4ceSJonathan Corbet某些通过常量高效跳转到那些代码段的汇编技巧。且由于那些代码段在返回用户 41*e790a4ceSJonathan Corbet代码前仅使用少量的代码周期,则一个 VDSO 间接远程调用将会在这些简单的 42*e790a4ceSJonathan Corbet操作上增加一个可测量的开销。 43*e790a4ceSJonathan Corbet 44*e790a4ceSJonathan Corbet在对那些拥有原生支持的新型处理器进行代码优化时,仅在已为其他操作使用 45*e790a4ceSJonathan Corbet了类似的新增指令,而导致二进制结果已与早期 ARM 处理器不兼容的情况下, 46*e790a4ceSJonathan Corbet用户空间才应绕过这些辅助代码,并在内联函数中实现这些操作(无论是通过 47*e790a4ceSJonathan Corbet编译器在代码中直接放置,还是作为库函数调用实现的一部分)。也就是说, 48*e790a4ceSJonathan Corbet如果你编译的代码不会为了其他目的使用新指令,则不要仅为了避免使用这些 49*e790a4ceSJonathan Corbet内核辅助代码,导致二进制程序无法在早期处理器上运行。 50*e790a4ceSJonathan Corbet 51*e790a4ceSJonathan Corbet新的辅助代码可能随着时间的推移而增加,所以新内核中的某些辅助代码在旧 52*e790a4ceSJonathan Corbet内核中可能不存在。因此,程序必须在对任何辅助代码调用假设是安全之前, 53*e790a4ceSJonathan Corbet检测 __kuser_helper_version 的值(见下文)。理想情况下,这种检测应该 54*e790a4ceSJonathan Corbet只在进程启动时执行一次;如果内核版本不支持所需辅助代码,则该进程可尽早 55*e790a4ceSJonathan Corbet中止执行。 56*e790a4ceSJonathan Corbet 57*e790a4ceSJonathan Corbetkuser_helper_version 58*e790a4ceSJonathan Corbet-------------------- 59*e790a4ceSJonathan Corbet 60*e790a4ceSJonathan Corbet位置: 0xffff0ffc 61*e790a4ceSJonathan Corbet 62*e790a4ceSJonathan Corbet参考声明: 63*e790a4ceSJonathan Corbet 64*e790a4ceSJonathan Corbet extern int32_t __kuser_helper_version; 65*e790a4ceSJonathan Corbet 66*e790a4ceSJonathan Corbet定义: 67*e790a4ceSJonathan Corbet 68*e790a4ceSJonathan Corbet 这个区域包含了当前运行内核实现的辅助代码版本号。用户空间可以通过读 69*e790a4ceSJonathan Corbet 取此版本号以确定特定的辅助代码是否存在。 70*e790a4ceSJonathan Corbet 71*e790a4ceSJonathan Corbet使用范例: 72*e790a4ceSJonathan Corbet 73*e790a4ceSJonathan Corbet#define __kuser_helper_version (*(int32_t *)0xffff0ffc) 74*e790a4ceSJonathan Corbet 75*e790a4ceSJonathan Corbetvoid check_kuser_version(void) 76*e790a4ceSJonathan Corbet{ 77*e790a4ceSJonathan Corbet if (__kuser_helper_version < 2) { 78*e790a4ceSJonathan Corbet fprintf(stderr, "can't do atomic operations, kernel too old\n"); 79*e790a4ceSJonathan Corbet abort(); 80*e790a4ceSJonathan Corbet } 81*e790a4ceSJonathan Corbet} 82*e790a4ceSJonathan Corbet 83*e790a4ceSJonathan Corbet注意: 84*e790a4ceSJonathan Corbet 85*e790a4ceSJonathan Corbet 用户空间可以假设这个域的值不会在任何单个进程的生存期内改变。也就 86*e790a4ceSJonathan Corbet 是说,这个域可以仅在库的初始化阶段或进程启动阶段读取一次。 87*e790a4ceSJonathan Corbet 88*e790a4ceSJonathan Corbetkuser_get_tls 89*e790a4ceSJonathan Corbet------------- 90*e790a4ceSJonathan Corbet 91*e790a4ceSJonathan Corbet位置: 0xffff0fe0 92*e790a4ceSJonathan Corbet 93*e790a4ceSJonathan Corbet参考原型: 94*e790a4ceSJonathan Corbet 95*e790a4ceSJonathan Corbet void * __kuser_get_tls(void); 96*e790a4ceSJonathan Corbet 97*e790a4ceSJonathan Corbet输入: 98*e790a4ceSJonathan Corbet 99*e790a4ceSJonathan Corbet lr = 返回地址 100*e790a4ceSJonathan Corbet 101*e790a4ceSJonathan Corbet输出: 102*e790a4ceSJonathan Corbet 103*e790a4ceSJonathan Corbet r0 = TLS 值 104*e790a4ceSJonathan Corbet 105*e790a4ceSJonathan Corbet被篡改的寄存器: 106*e790a4ceSJonathan Corbet 107*e790a4ceSJonathan Corbet 无 108*e790a4ceSJonathan Corbet 109*e790a4ceSJonathan Corbet定义: 110*e790a4ceSJonathan Corbet 111*e790a4ceSJonathan Corbet 获取之前通过 __ARM_NR_set_tls 系统调用设置的 TLS 值。 112*e790a4ceSJonathan Corbet 113*e790a4ceSJonathan Corbet使用范例: 114*e790a4ceSJonathan Corbet 115*e790a4ceSJonathan Corbettypedef void * (__kuser_get_tls_t)(void); 116*e790a4ceSJonathan Corbet#define __kuser_get_tls (*(__kuser_get_tls_t *)0xffff0fe0) 117*e790a4ceSJonathan Corbet 118*e790a4ceSJonathan Corbetvoid foo() 119*e790a4ceSJonathan Corbet{ 120*e790a4ceSJonathan Corbet void *tls = __kuser_get_tls(); 121*e790a4ceSJonathan Corbet printf("TLS = %p\n", tls); 122*e790a4ceSJonathan Corbet} 123*e790a4ceSJonathan Corbet 124*e790a4ceSJonathan Corbet注意: 125*e790a4ceSJonathan Corbet 126*e790a4ceSJonathan Corbet - 仅在 __kuser_helper_version >= 1 时,此辅助代码存在 127*e790a4ceSJonathan Corbet (从内核版本 2.6.12 开始)。 128*e790a4ceSJonathan Corbet 129*e790a4ceSJonathan Corbetkuser_cmpxchg 130*e790a4ceSJonathan Corbet------------- 131*e790a4ceSJonathan Corbet 132*e790a4ceSJonathan Corbet位置: 0xffff0fc0 133*e790a4ceSJonathan Corbet 134*e790a4ceSJonathan Corbet参考原型: 135*e790a4ceSJonathan Corbet 136*e790a4ceSJonathan Corbet int __kuser_cmpxchg(int32_t oldval, int32_t newval, volatile int32_t *ptr); 137*e790a4ceSJonathan Corbet 138*e790a4ceSJonathan Corbet输入: 139*e790a4ceSJonathan Corbet 140*e790a4ceSJonathan Corbet r0 = oldval 141*e790a4ceSJonathan Corbet r1 = newval 142*e790a4ceSJonathan Corbet r2 = ptr 143*e790a4ceSJonathan Corbet lr = 返回地址 144*e790a4ceSJonathan Corbet 145*e790a4ceSJonathan Corbet输出: 146*e790a4ceSJonathan Corbet 147*e790a4ceSJonathan Corbet r0 = 成功代码 (零或非零) 148*e790a4ceSJonathan Corbet C flag = 如果 r0 == 0 则置 1,如果 r0 != 0 则清零。 149*e790a4ceSJonathan Corbet 150*e790a4ceSJonathan Corbet被篡改的寄存器: 151*e790a4ceSJonathan Corbet 152*e790a4ceSJonathan Corbet r3, ip, flags 153*e790a4ceSJonathan Corbet 154*e790a4ceSJonathan Corbet定义: 155*e790a4ceSJonathan Corbet 156*e790a4ceSJonathan Corbet 仅在 *ptr 为 oldval 时原子保存 newval 于 *ptr 中。 157*e790a4ceSJonathan Corbet 如果 *ptr 被改变,则返回值为零,否则为非零值。 158*e790a4ceSJonathan Corbet 如果 *ptr 被改变,则 C flag 也会被置 1,以实现调用代码中的汇编 159*e790a4ceSJonathan Corbet 优化。 160*e790a4ceSJonathan Corbet 161*e790a4ceSJonathan Corbet使用范例: 162*e790a4ceSJonathan Corbet 163*e790a4ceSJonathan Corbettypedef int (__kuser_cmpxchg_t)(int oldval, int newval, volatile int *ptr); 164*e790a4ceSJonathan Corbet#define __kuser_cmpxchg (*(__kuser_cmpxchg_t *)0xffff0fc0) 165*e790a4ceSJonathan Corbet 166*e790a4ceSJonathan Corbetint atomic_add(volatile int *ptr, int val) 167*e790a4ceSJonathan Corbet{ 168*e790a4ceSJonathan Corbet int old, new; 169*e790a4ceSJonathan Corbet 170*e790a4ceSJonathan Corbet do { 171*e790a4ceSJonathan Corbet old = *ptr; 172*e790a4ceSJonathan Corbet new = old + val; 173*e790a4ceSJonathan Corbet } while(__kuser_cmpxchg(old, new, ptr)); 174*e790a4ceSJonathan Corbet 175*e790a4ceSJonathan Corbet return new; 176*e790a4ceSJonathan Corbet} 177*e790a4ceSJonathan Corbet 178*e790a4ceSJonathan Corbet注意: 179*e790a4ceSJonathan Corbet 180*e790a4ceSJonathan Corbet - 这个例程已根据需要包含了内存屏障。 181*e790a4ceSJonathan Corbet 182*e790a4ceSJonathan Corbet - 仅在 __kuser_helper_version >= 2 时,此辅助代码存在 183*e790a4ceSJonathan Corbet (从内核版本 2.6.12 开始)。 184*e790a4ceSJonathan Corbet 185*e790a4ceSJonathan Corbetkuser_memory_barrier 186*e790a4ceSJonathan Corbet-------------------- 187*e790a4ceSJonathan Corbet 188*e790a4ceSJonathan Corbet位置: 0xffff0fa0 189*e790a4ceSJonathan Corbet 190*e790a4ceSJonathan Corbet参考原型: 191*e790a4ceSJonathan Corbet 192*e790a4ceSJonathan Corbet void __kuser_memory_barrier(void); 193*e790a4ceSJonathan Corbet 194*e790a4ceSJonathan Corbet输入: 195*e790a4ceSJonathan Corbet 196*e790a4ceSJonathan Corbet lr = 返回地址 197*e790a4ceSJonathan Corbet 198*e790a4ceSJonathan Corbet输出: 199*e790a4ceSJonathan Corbet 200*e790a4ceSJonathan Corbet 无 201*e790a4ceSJonathan Corbet 202*e790a4ceSJonathan Corbet被篡改的寄存器: 203*e790a4ceSJonathan Corbet 204*e790a4ceSJonathan Corbet 无 205*e790a4ceSJonathan Corbet 206*e790a4ceSJonathan Corbet定义: 207*e790a4ceSJonathan Corbet 208*e790a4ceSJonathan Corbet 应用于任何需要内存屏障以防止手动数据修改带来的一致性问题,以及 209*e790a4ceSJonathan Corbet __kuser_cmpxchg 中。 210*e790a4ceSJonathan Corbet 211*e790a4ceSJonathan Corbet使用范例: 212*e790a4ceSJonathan Corbet 213*e790a4ceSJonathan Corbettypedef void (__kuser_dmb_t)(void); 214*e790a4ceSJonathan Corbet#define __kuser_dmb (*(__kuser_dmb_t *)0xffff0fa0) 215*e790a4ceSJonathan Corbet 216*e790a4ceSJonathan Corbet注意: 217*e790a4ceSJonathan Corbet 218*e790a4ceSJonathan Corbet - 仅在 __kuser_helper_version >= 3 时,此辅助代码存在 219*e790a4ceSJonathan Corbet (从内核版本 2.6.15 开始)。 220*e790a4ceSJonathan Corbet 221*e790a4ceSJonathan Corbetkuser_cmpxchg64 222*e790a4ceSJonathan Corbet--------------- 223*e790a4ceSJonathan Corbet 224*e790a4ceSJonathan Corbet位置: 0xffff0f60 225*e790a4ceSJonathan Corbet 226*e790a4ceSJonathan Corbet参考原型: 227*e790a4ceSJonathan Corbet 228*e790a4ceSJonathan Corbet int __kuser_cmpxchg64(const int64_t *oldval, 229*e790a4ceSJonathan Corbet const int64_t *newval, 230*e790a4ceSJonathan Corbet volatile int64_t *ptr); 231*e790a4ceSJonathan Corbet 232*e790a4ceSJonathan Corbet输入: 233*e790a4ceSJonathan Corbet 234*e790a4ceSJonathan Corbet r0 = 指向 oldval 235*e790a4ceSJonathan Corbet r1 = 指向 newval 236*e790a4ceSJonathan Corbet r2 = 指向目标值 237*e790a4ceSJonathan Corbet lr = 返回地址 238*e790a4ceSJonathan Corbet 239*e790a4ceSJonathan Corbet输出: 240*e790a4ceSJonathan Corbet 241*e790a4ceSJonathan Corbet r0 = 成功代码 (零或非零) 242*e790a4ceSJonathan Corbet C flag = 如果 r0 == 0 则置 1,如果 r0 != 0 则清零。 243*e790a4ceSJonathan Corbet 244*e790a4ceSJonathan Corbet被篡改的寄存器: 245*e790a4ceSJonathan Corbet 246*e790a4ceSJonathan Corbet r3, lr, flags 247*e790a4ceSJonathan Corbet 248*e790a4ceSJonathan Corbet定义: 249*e790a4ceSJonathan Corbet 250*e790a4ceSJonathan Corbet 仅在 *ptr 等于 *oldval 指向的 64 位值时,原子保存 *newval 251*e790a4ceSJonathan Corbet 指向的 64 位值于 *ptr 中。如果 *ptr 被改变,则返回值为零, 252*e790a4ceSJonathan Corbet 否则为非零值。 253*e790a4ceSJonathan Corbet 254*e790a4ceSJonathan Corbet 如果 *ptr 被改变,则 C flag 也会被置 1,以实现调用代码中的汇编 255*e790a4ceSJonathan Corbet 优化。 256*e790a4ceSJonathan Corbet 257*e790a4ceSJonathan Corbet使用范例: 258*e790a4ceSJonathan Corbet 259*e790a4ceSJonathan Corbettypedef int (__kuser_cmpxchg64_t)(const int64_t *oldval, 260*e790a4ceSJonathan Corbet const int64_t *newval, 261*e790a4ceSJonathan Corbet volatile int64_t *ptr); 262*e790a4ceSJonathan Corbet#define __kuser_cmpxchg64 (*(__kuser_cmpxchg64_t *)0xffff0f60) 263*e790a4ceSJonathan Corbet 264*e790a4ceSJonathan Corbetint64_t atomic_add64(volatile int64_t *ptr, int64_t val) 265*e790a4ceSJonathan Corbet{ 266*e790a4ceSJonathan Corbet int64_t old, new; 267*e790a4ceSJonathan Corbet 268*e790a4ceSJonathan Corbet do { 269*e790a4ceSJonathan Corbet old = *ptr; 270*e790a4ceSJonathan Corbet new = old + val; 271*e790a4ceSJonathan Corbet } while(__kuser_cmpxchg64(&old, &new, ptr)); 272*e790a4ceSJonathan Corbet 273*e790a4ceSJonathan Corbet return new; 274*e790a4ceSJonathan Corbet} 275*e790a4ceSJonathan Corbet 276*e790a4ceSJonathan Corbet注意: 277*e790a4ceSJonathan Corbet 278*e790a4ceSJonathan Corbet - 这个例程已根据需要包含了内存屏障。 279*e790a4ceSJonathan Corbet 280*e790a4ceSJonathan Corbet - 由于这个过程的代码长度(此辅助代码跨越 2 个常规的 kuser “槽”), 281*e790a4ceSJonathan Corbet 因此 0xffff0f80 不被作为有效的入口点。 282*e790a4ceSJonathan Corbet 283*e790a4ceSJonathan Corbet - 仅在 __kuser_helper_version >= 5 时,此辅助代码存在 284*e790a4ceSJonathan Corbet (从内核版本 3.1 开始)。 285