Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Documentation: Chinese translation of Documentation/arm/kernel_user_helpers.txt

This is a Chinese translated version of
Documentation/arm/kernel_user_helpers.txt

Signed-off-by: Fu Wei <tekkamanninja@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Fu Wei and committed by
Greg Kroah-Hartman
83ca897d 7dd2517c

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