About Kernel Documentation Linux Kernel Contact Linux Resources Linux Blog

Documentation / arm / kernel_user_helpers.txt


Based on kernel version 4.16.1. Page generated on 2018-04-09 11:52 EST.

1	Kernel-provided User Helpers
2	============================
3	
4	These are segment of kernel provided user code reachable from user space
5	at a fixed address in kernel memory.  This is used to provide user space
6	with some operations which require kernel help because of unimplemented
7	native feature and/or instructions in many ARM CPUs. The idea is for this
8	code to be executed directly in user mode for best efficiency but which is
9	too intimate with the kernel counter part to be left to user libraries.
10	In fact this code might even differ from one CPU to another depending on
11	the available instruction set, or whether it is a SMP systems. In other
12	words, the kernel reserves the right to change this code as needed without
13	warning. Only the entry points and their results as documented here are
14	guaranteed to be stable.
15	
16	This is different from (but doesn't preclude) a full blown VDSO
17	implementation, however a VDSO would prevent some assembly tricks with
18	constants that allows for efficient branching to those code segments. And
19	since those code segments only use a few cycles before returning to user
20	code, the overhead of a VDSO indirect far call would add a measurable
21	overhead to such minimalistic operations.
22	
23	User space is expected to bypass those helpers and implement those things
24	inline (either in the code emitted directly by the compiler, or part of
25	the implementation of a library call) when optimizing for a recent enough
26	processor that has the necessary native support, but only if resulting
27	binaries are already to be incompatible with earlier ARM processors due to
28	usage of similar native instructions for other things.  In other words
29	don't make binaries unable to run on earlier processors just for the sake
30	of not using these kernel helpers if your compiled code is not going to
31	use new instructions for other purpose.
32	
33	New helpers may be added over time, so an older kernel may be missing some
34	helpers present in a newer kernel.  For this reason, programs must check
35	the value of __kuser_helper_version (see below) before assuming that it is
36	safe to call any particular helper.  This check should ideally be
37	performed only once at process startup time, and execution aborted early
38	if the required helpers are not provided by the kernel version that
39	process is running on.
40	
41	kuser_helper_version
42	--------------------
43	
44	Location:	0xffff0ffc
45	
46	Reference declaration:
47	
48	  extern int32_t __kuser_helper_version;
49	
50	Definition:
51	
52	  This field contains the number of helpers being implemented by the
53	  running kernel.  User space may read this to determine the availability
54	  of a particular helper.
55	
56	Usage example:
57	
58	#define __kuser_helper_version (*(int32_t *)0xffff0ffc)
59	
60	void check_kuser_version(void)
61	{
62		if (__kuser_helper_version < 2) {
63			fprintf(stderr, "can't do atomic operations, kernel too old\n");
64			abort();
65		}
66	}
67	
68	Notes:
69	
70	  User space may assume that the value of this field never changes
71	  during the lifetime of any single process.  This means that this
72	  field can be read once during the initialisation of a library or
73	  startup phase of a program.
74	
75	kuser_get_tls
76	-------------
77	
78	Location:	0xffff0fe0
79	
80	Reference prototype:
81	
82	  void * __kuser_get_tls(void);
83	
84	Input:
85	
86	  lr = return address
87	
88	Output:
89	
90	  r0 = TLS value
91	
92	Clobbered registers:
93	
94	  none
95	
96	Definition:
97	
98	  Get the TLS value as previously set via the __ARM_NR_set_tls syscall.
99	
100	Usage example:
101	
102	typedef void * (__kuser_get_tls_t)(void);
103	#define __kuser_get_tls (*(__kuser_get_tls_t *)0xffff0fe0)
104	
105	void foo()
106	{
107		void *tls = __kuser_get_tls();
108		printf("TLS = %p\n", tls);
109	}
110	
111	Notes:
112	
113	  - Valid only if __kuser_helper_version >= 1 (from kernel version 2.6.12).
114	
115	kuser_cmpxchg
116	-------------
117	
118	Location:	0xffff0fc0
119	
120	Reference prototype:
121	
122	  int __kuser_cmpxchg(int32_t oldval, int32_t newval, volatile int32_t *ptr);
123	
124	Input:
125	
126	  r0 = oldval
127	  r1 = newval
128	  r2 = ptr
129	  lr = return address
130	
131	Output:
132	
133	  r0 = success code (zero or non-zero)
134	  C flag = set if r0 == 0, clear if r0 != 0
135	
136	Clobbered registers:
137	
138	  r3, ip, flags
139	
140	Definition:
141	
142	  Atomically store newval in *ptr only if *ptr is equal to oldval.
143	  Return zero if *ptr was changed or non-zero if no exchange happened.
144	  The C flag is also set if *ptr was changed to allow for assembly
145	  optimization in the calling code.
146	
147	Usage example:
148	
149	typedef int (__kuser_cmpxchg_t)(int oldval, int newval, volatile int *ptr);
150	#define __kuser_cmpxchg (*(__kuser_cmpxchg_t *)0xffff0fc0)
151	
152	int atomic_add(volatile int *ptr, int val)
153	{
154		int old, new;
155	
156		do {
157			old = *ptr;
158			new = old + val;
159		} while(__kuser_cmpxchg(old, new, ptr));
160	
161		return new;
162	}
163	
164	Notes:
165	
166	  - This routine already includes memory barriers as needed.
167	
168	  - Valid only if __kuser_helper_version >= 2 (from kernel version 2.6.12).
169	
170	kuser_memory_barrier
171	--------------------
172	
173	Location:	0xffff0fa0
174	
175	Reference prototype:
176	
177	  void __kuser_memory_barrier(void);
178	
179	Input:
180	
181	  lr = return address
182	
183	Output:
184	
185	  none
186	
187	Clobbered registers:
188	
189	  none
190	
191	Definition:
192	
193	  Apply any needed memory barrier to preserve consistency with data modified
194	  manually and __kuser_cmpxchg usage.
195	
196	Usage example:
197	
198	typedef void (__kuser_dmb_t)(void);
199	#define __kuser_dmb (*(__kuser_dmb_t *)0xffff0fa0)
200	
201	Notes:
202	
203	  - Valid only if __kuser_helper_version >= 3 (from kernel version 2.6.15).
204	
205	kuser_cmpxchg64
206	---------------
207	
208	Location:	0xffff0f60
209	
210	Reference prototype:
211	
212	  int __kuser_cmpxchg64(const int64_t *oldval,
213	                        const int64_t *newval,
214	                        volatile int64_t *ptr);
215	
216	Input:
217	
218	  r0 = pointer to oldval
219	  r1 = pointer to newval
220	  r2 = pointer to target value
221	  lr = return address
222	
223	Output:
224	
225	  r0 = success code (zero or non-zero)
226	  C flag = set if r0 == 0, clear if r0 != 0
227	
228	Clobbered registers:
229	
230	  r3, lr, flags
231	
232	Definition:
233	
234	  Atomically store the 64-bit value pointed by *newval in *ptr only if *ptr
235	  is equal to the 64-bit value pointed by *oldval.  Return zero if *ptr was
236	  changed or non-zero if no exchange happened.
237	
238	  The C flag is also set if *ptr was changed to allow for assembly
239	  optimization in the calling code.
240	
241	Usage example:
242	
243	typedef int (__kuser_cmpxchg64_t)(const int64_t *oldval,
244	                                  const int64_t *newval,
245	                                  volatile int64_t *ptr);
246	#define __kuser_cmpxchg64 (*(__kuser_cmpxchg64_t *)0xffff0f60)
247	
248	int64_t atomic_add64(volatile int64_t *ptr, int64_t val)
249	{
250		int64_t old, new;
251	
252		do {
253			old = *ptr;
254			new = old + val;
255		} while(__kuser_cmpxchg64(&old, &new, ptr));
256	
257		return new;
258	}
259	
260	Notes:
261	
262	  - This routine already includes memory barriers as needed.
263	
264	  - Due to the length of this sequence, this spans 2 conventional kuser
265	    "slots", therefore 0xffff0f80 is not used as a valid entry point.
266	
267	  - Valid only if __kuser_helper_version >= 5 (from kernel version 3.1).
Hide Line Numbers


About Kernel Documentation Linux Kernel Contact Linux Resources Linux Blog