Fu Wei | 83ca897 | 2012-11-16 01:01:56 +0800 | [diff] [blame] | 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 开始)。 |