Back to home page

OSCL-LXR

 
 

    


0001 Chinese translated version of Documentation/arm/kernel_user_helpers.rst
0002 
0003 If you have any comment or update to the content, please contact the
0004 original document maintainer directly.  However, if you have a problem
0005 communicating in English you can also ask the Chinese maintainer for
0006 help.  Contact the Chinese maintainer if this translation is outdated
0007 or if there is a problem with the translation.
0008 
0009 Maintainer: Nicolas Pitre <nicolas.pitre@linaro.org>
0010                 Dave Martin <dave.martin@linaro.org>
0011 Chinese maintainer: Fu Wei <tekkamanninja@gmail.com>
0012 ---------------------------------------------------------------------
0013 Documentation/arm/kernel_user_helpers.rst 的中文翻译
0014 
0015 如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
0016 交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
0017 译存在问题,请联系中文版维护者。
0018 英文版维护者: Nicolas Pitre <nicolas.pitre@linaro.org>
0019                 Dave Martin <dave.martin@linaro.org>
0020 中文版维护者: 傅炜 Fu Wei <tekkamanninja@gmail.com>
0021 中文版翻译者: 傅炜 Fu Wei <tekkamanninja@gmail.com>
0022 中文版校译者: 宋冬生 Dongsheng Song <dongshneg.song@gmail.com>
0023                 傅炜 Fu Wei <tekkamanninja@gmail.com>
0024 
0025 
0026 以下为正文
0027 ---------------------------------------------------------------------
0028 内核提供的用户空间辅助代码
0029 =========================
0030 
0031 在内核内存空间的固定地址处,有一个由内核提供并可从用户空间访问的代码
0032 段。它用于向用户空间提供因在许多 ARM CPU 中未实现的特性和/或指令而需
0033 内核提供帮助的某些操作。这些代码直接在用户模式下执行的想法是为了获得
0034 最佳效率,但那些与内核计数器联系过于紧密的部分,则被留给了用户库实现。
0035 事实上,此代码甚至可能因不同的 CPU 而异,这取决于其可用的指令集或它
0036 是否为 SMP 系统。换句话说,内核保留在不作出警告的情况下根据需要更改
0037 这些代码的权利。只有本文档描述的入口及其结果是保证稳定的。
0038 
0039 这与完全成熟的 VDSO 实现不同(但两者并不冲突),尽管如此,VDSO 可阻止
0040 某些通过常量高效跳转到那些代码段的汇编技巧。且由于那些代码段在返回用户
0041 代码前仅使用少量的代码周期,则一个 VDSO 间接远程调用将会在这些简单的
0042 操作上增加一个可测量的开销。
0043 
0044 在对那些拥有原生支持的新型处理器进行代码优化时,仅在已为其他操作使用
0045 了类似的新增指令,而导致二进制结果已与早期 ARM 处理器不兼容的情况下,
0046 用户空间才应绕过这些辅助代码,并在内联函数中实现这些操作(无论是通过
0047 编译器在代码中直接放置,还是作为库函数调用实现的一部分)。也就是说,
0048 如果你编译的代码不会为了其他目的使用新指令,则不要仅为了避免使用这些
0049 内核辅助代码,导致二进制程序无法在早期处理器上运行。
0050 
0051 新的辅助代码可能随着时间的推移而增加,所以新内核中的某些辅助代码在旧
0052 内核中可能不存在。因此,程序必须在对任何辅助代码调用假设是安全之前,
0053 检测 __kuser_helper_version 的值(见下文)。理想情况下,这种检测应该
0054 只在进程启动时执行一次;如果内核版本不支持所需辅助代码,则该进程可尽早
0055 中止执行。
0056 
0057 kuser_helper_version
0058 --------------------
0059 
0060 位置: 0xffff0ffc
0061 
0062 参考声明:
0063 
0064   extern int32_t __kuser_helper_version;
0065 
0066 定义:
0067 
0068   这个区域包含了当前运行内核实现的辅助代码版本号。用户空间可以通过读
0069   取此版本号以确定特定的辅助代码是否存在。
0070 
0071 使用范例:
0072 
0073 #define __kuser_helper_version (*(int32_t *)0xffff0ffc)
0074 
0075 void check_kuser_version(void)
0076 {
0077         if (__kuser_helper_version < 2) {
0078                 fprintf(stderr, "can't do atomic operations, kernel too old\n");
0079                 abort();
0080         }
0081 }
0082 
0083 注意:
0084 
0085   用户空间可以假设这个域的值不会在任何单个进程的生存期内改变。也就
0086   是说,这个域可以仅在库的初始化阶段或进程启动阶段读取一次。
0087 
0088 kuser_get_tls
0089 -------------
0090 
0091 位置: 0xffff0fe0
0092 
0093 参考原型:
0094 
0095   void * __kuser_get_tls(void);
0096 
0097 输入:
0098 
0099   lr = 返回地址
0100 
0101 输出:
0102 
0103   r0 = TLS 值
0104 
0105 被篡改的寄存器:
0106 
01070108 
0109 定义:
0110 
0111   获取之前通过 __ARM_NR_set_tls 系统调用设置的 TLS 值。
0112 
0113 使用范例:
0114 
0115 typedef void * (__kuser_get_tls_t)(void);
0116 #define __kuser_get_tls (*(__kuser_get_tls_t *)0xffff0fe0)
0117 
0118 void foo()
0119 {
0120         void *tls = __kuser_get_tls();
0121         printf("TLS = %p\n", tls);
0122 }
0123 
0124 注意:
0125 
0126   - 仅在 __kuser_helper_version >= 1 时,此辅助代码存在
0127     (从内核版本 2.6.12 开始)。
0128 
0129 kuser_cmpxchg
0130 -------------
0131 
0132 位置: 0xffff0fc0
0133 
0134 参考原型:
0135 
0136   int __kuser_cmpxchg(int32_t oldval, int32_t newval, volatile int32_t *ptr);
0137 
0138 输入:
0139 
0140   r0 = oldval
0141   r1 = newval
0142   r2 = ptr
0143   lr = 返回地址
0144 
0145 输出:
0146 
0147   r0 = 成功代码 (零或非零)
0148   C flag = 如果 r0 == 0 则置 1,如果 r0 != 0 则清零。
0149 
0150 被篡改的寄存器:
0151 
0152   r3, ip, flags
0153 
0154 定义:
0155 
0156   仅在 *ptr 为 oldval 时原子保存 newval 于 *ptr 中。
0157   如果 *ptr 被改变,则返回值为零,否则为非零值。
0158   如果 *ptr 被改变,则 C flag 也会被置 1,以实现调用代码中的汇编
0159   优化。
0160 
0161 使用范例:
0162 
0163 typedef int (__kuser_cmpxchg_t)(int oldval, int newval, volatile int *ptr);
0164 #define __kuser_cmpxchg (*(__kuser_cmpxchg_t *)0xffff0fc0)
0165 
0166 int atomic_add(volatile int *ptr, int val)
0167 {
0168         int old, new;
0169 
0170         do {
0171                 old = *ptr;
0172                 new = old + val;
0173         } while(__kuser_cmpxchg(old, new, ptr));
0174 
0175         return new;
0176 }
0177 
0178 注意:
0179 
0180   - 这个例程已根据需要包含了内存屏障。
0181 
0182   - 仅在 __kuser_helper_version >= 2 时,此辅助代码存在
0183     (从内核版本 2.6.12 开始)。
0184 
0185 kuser_memory_barrier
0186 --------------------
0187 
0188 位置: 0xffff0fa0
0189 
0190 参考原型:
0191 
0192   void __kuser_memory_barrier(void);
0193 
0194 输入:
0195 
0196   lr = 返回地址
0197 
0198 输出:
0199 
02000201 
0202 被篡改的寄存器:
0203 
02040205 
0206 定义:
0207 
0208   应用于任何需要内存屏障以防止手动数据修改带来的一致性问题,以及
0209   __kuser_cmpxchg 中。
0210 
0211 使用范例:
0212 
0213 typedef void (__kuser_dmb_t)(void);
0214 #define __kuser_dmb (*(__kuser_dmb_t *)0xffff0fa0)
0215 
0216 注意:
0217 
0218   - 仅在 __kuser_helper_version >= 3 时,此辅助代码存在
0219     (从内核版本 2.6.15 开始)。
0220 
0221 kuser_cmpxchg64
0222 ---------------
0223 
0224 位置: 0xffff0f60
0225 
0226 参考原型:
0227 
0228   int __kuser_cmpxchg64(const int64_t *oldval,
0229                         const int64_t *newval,
0230                         volatile int64_t *ptr);
0231 
0232 输入:
0233 
0234   r0 = 指向 oldval
0235   r1 = 指向 newval
0236   r2 = 指向目标值
0237   lr = 返回地址
0238 
0239 输出:
0240 
0241   r0 = 成功代码 (零或非零)
0242   C flag = 如果 r0 == 0 则置 1,如果 r0 != 0 则清零。
0243 
0244 被篡改的寄存器:
0245 
0246   r3, lr, flags
0247 
0248 定义:
0249 
0250   仅在 *ptr 等于 *oldval 指向的 64 位值时,原子保存 *newval
0251   指向的 64 位值于 *ptr 中。如果 *ptr 被改变,则返回值为零,
0252   否则为非零值。
0253 
0254   如果 *ptr 被改变,则 C flag 也会被置 1,以实现调用代码中的汇编
0255   优化。
0256 
0257 使用范例:
0258 
0259 typedef int (__kuser_cmpxchg64_t)(const int64_t *oldval,
0260                                   const int64_t *newval,
0261                                   volatile int64_t *ptr);
0262 #define __kuser_cmpxchg64 (*(__kuser_cmpxchg64_t *)0xffff0f60)
0263 
0264 int64_t atomic_add64(volatile int64_t *ptr, int64_t val)
0265 {
0266         int64_t old, new;
0267 
0268         do {
0269                 old = *ptr;
0270                 new = old + val;
0271         } while(__kuser_cmpxchg64(&old, &new, ptr));
0272 
0273         return new;
0274 }
0275 
0276 注意:
0277 
0278   - 这个例程已根据需要包含了内存屏障。
0279 
0280   - 由于这个过程的代码长度(此辅助代码跨越 2 个常规的 kuser “槽”),
0281     因此 0xffff0f80 不被作为有效的入口点。
0282 
0283   - 仅在 __kuser_helper_version >= 5 时,此辅助代码存在
0284     (从内核版本 3.1 开始)。