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 Corbet108*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 Corbet201*e790a4ceSJonathan Corbet
202*e790a4ceSJonathan Corbet被篡改的寄存器:
203*e790a4ceSJonathan Corbet
204*e790a4ceSJonathan Corbet205*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