1 #ifndef _IPXE_UACCESS_H
2 #define _IPXE_UACCESS_H
3
4 /**
5 * @file
6 *
7 * Access to external ("user") memory
8 *
9 * iPXE often needs to transfer data between internal and external
10 * buffers. On i386, the external buffers may require access via a
11 * different segment, and the buffer address cannot be encoded into a
12 * simple void * pointer. The @c userptr_t type encapsulates the
13 * information needed to identify an external buffer, and the
14 * copy_to_user() and copy_from_user() functions provide methods for
15 * transferring data between internal and external buffers.
16 *
17 * Note that userptr_t is an opaque type; in particular, performing
18 * arithmetic upon a userptr_t is not allowed.
19 *
20 */
21
22 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
23
24 #include <stdint.h>
25 #include <string.h>
26 #include <ipxe/api.h>
27 #include <config/ioapi.h>
28
29 /**
30 * A pointer to a user buffer
31 *
32 */
33 typedef unsigned long userptr_t;
34
35 /** Equivalent of NULL for user pointers */
36 #define UNULL ( ( userptr_t ) 0 )
37
38 /**
39 * @defgroup uaccess_trivial Trivial user access API implementations
40 *
41 * User access API implementations that can be used by environments in
42 * which virtual addresses allow access to all of memory.
43 *
44 * @{
45 *
46 */
47
48 /**
49 * Convert virtual address to user pointer
50 *
51 * @v addr Virtual address
52 * @ret userptr User pointer
53 */
54 static inline __always_inline userptr_t
trivial_virt_to_user(volatile const void * addr)55 trivial_virt_to_user ( volatile const void *addr ) {
56 return ( ( userptr_t ) addr );
57 }
58
59 /**
60 * Convert user pointer to virtual address
61 *
62 * @v userptr User pointer
63 * @v offset Offset from user pointer
64 * @ret addr Virtual address
65 *
66 * This operation is not available under all memory models.
67 */
68 static inline __always_inline void *
trivial_user_to_virt(userptr_t userptr,off_t offset)69 trivial_user_to_virt ( userptr_t userptr, off_t offset ) {
70 return ( ( void * ) userptr + offset );
71 }
72
73 /**
74 * Add offset to user pointer
75 *
76 * @v userptr User pointer
77 * @v offset Offset
78 * @ret userptr New pointer value
79 */
80 static inline __always_inline userptr_t
trivial_userptr_add(userptr_t userptr,off_t offset)81 trivial_userptr_add ( userptr_t userptr, off_t offset ) {
82 return ( userptr + offset );
83 }
84
85 /**
86 * Subtract user pointers
87 *
88 * @v userptr User pointer
89 * @v subtrahend User pointer to be subtracted
90 * @ret offset Offset
91 */
92 static inline __always_inline off_t
trivial_userptr_sub(userptr_t userptr,userptr_t subtrahend)93 trivial_userptr_sub ( userptr_t userptr, userptr_t subtrahend ) {
94 return ( userptr - subtrahend );
95 }
96
97 /**
98 * Copy data between user buffers
99 *
100 * @v dest Destination
101 * @v dest_off Destination offset
102 * @v src Source
103 * @v src_off Source offset
104 * @v len Length
105 */
106 static inline __always_inline void
trivial_memcpy_user(userptr_t dest,off_t dest_off,userptr_t src,off_t src_off,size_t len)107 trivial_memcpy_user ( userptr_t dest, off_t dest_off,
108 userptr_t src, off_t src_off, size_t len ) {
109 memcpy ( ( ( void * ) dest + dest_off ),
110 ( ( void * ) src + src_off ), len );
111 }
112
113 /**
114 * Copy data between user buffers, allowing for overlap
115 *
116 * @v dest Destination
117 * @v dest_off Destination offset
118 * @v src Source
119 * @v src_off Source offset
120 * @v len Length
121 */
122 static inline __always_inline void
trivial_memmove_user(userptr_t dest,off_t dest_off,userptr_t src,off_t src_off,size_t len)123 trivial_memmove_user ( userptr_t dest, off_t dest_off,
124 userptr_t src, off_t src_off, size_t len ) {
125 memmove ( ( ( void * ) dest + dest_off ),
126 ( ( void * ) src + src_off ), len );
127 }
128
129 /**
130 * Compare data between user buffers
131 *
132 * @v first First buffer
133 * @v first_off First buffer offset
134 * @v second Second buffer
135 * @v second_off Second buffer offset
136 * @v len Length
137 * @ret diff Difference
138 */
139 static inline __always_inline int
trivial_memcmp_user(userptr_t first,off_t first_off,userptr_t second,off_t second_off,size_t len)140 trivial_memcmp_user ( userptr_t first, off_t first_off,
141 userptr_t second, off_t second_off, size_t len ) {
142 return memcmp ( ( ( void * ) first + first_off ),
143 ( ( void * ) second + second_off ), len );
144 }
145
146 /**
147 * Fill user buffer with a constant byte
148 *
149 * @v buffer User buffer
150 * @v offset Offset within buffer
151 * @v c Constant byte with which to fill
152 * @v len Length
153 */
154 static inline __always_inline void
trivial_memset_user(userptr_t buffer,off_t offset,int c,size_t len)155 trivial_memset_user ( userptr_t buffer, off_t offset, int c, size_t len ) {
156 memset ( ( ( void * ) buffer + offset ), c, len );
157 }
158
159 /**
160 * Find length of NUL-terminated string in user buffer
161 *
162 * @v buffer User buffer
163 * @v offset Offset within buffer
164 * @ret len Length of string (excluding NUL)
165 */
166 static inline __always_inline size_t
trivial_strlen_user(userptr_t buffer,off_t offset)167 trivial_strlen_user ( userptr_t buffer, off_t offset ) {
168 return strlen ( ( void * ) buffer + offset );
169 }
170
171 /**
172 * Find character in user buffer
173 *
174 * @v buffer User buffer
175 * @v offset Starting offset within buffer
176 * @v c Character to search for
177 * @v len Length of user buffer
178 * @ret offset Offset of character, or <0 if not found
179 */
180 static inline __always_inline off_t
trivial_memchr_user(userptr_t buffer,off_t offset,int c,size_t len)181 trivial_memchr_user ( userptr_t buffer, off_t offset, int c, size_t len ) {
182 void *found;
183
184 found = memchr ( ( ( void * ) buffer + offset ), c, len );
185 return ( found ? ( found - ( void * ) buffer ) : -1 );
186 }
187
188 /** @} */
189
190 /**
191 * Calculate static inline user access API function name
192 *
193 * @v _prefix Subsystem prefix
194 * @v _api_func API function
195 * @ret _subsys_func Subsystem API function
196 */
197 #define UACCESS_INLINE( _subsys, _api_func ) \
198 SINGLE_API_INLINE ( UACCESS_PREFIX_ ## _subsys, _api_func )
199
200 /**
201 * Provide an user access API implementation
202 *
203 * @v _prefix Subsystem prefix
204 * @v _api_func API function
205 * @v _func Implementing function
206 */
207 #define PROVIDE_UACCESS( _subsys, _api_func, _func ) \
208 PROVIDE_SINGLE_API ( UACCESS_PREFIX_ ## _subsys, _api_func, _func )
209
210 /**
211 * Provide a static inline user access API implementation
212 *
213 * @v _prefix Subsystem prefix
214 * @v _api_func API function
215 */
216 #define PROVIDE_UACCESS_INLINE( _subsys, _api_func ) \
217 PROVIDE_SINGLE_API_INLINE ( UACCESS_PREFIX_ ## _subsys, _api_func )
218
219 /* Include all architecture-independent user access API headers */
220 #include <ipxe/efi/efi_uaccess.h>
221 #include <ipxe/linux/linux_uaccess.h>
222
223 /* Include all architecture-dependent user access API headers */
224 #include <bits/uaccess.h>
225
226 /**
227 * Convert physical address to user pointer
228 *
229 * @v phys_addr Physical address
230 * @ret userptr User pointer
231 */
232 userptr_t phys_to_user ( unsigned long phys_addr );
233
234 /**
235 * Convert user pointer to physical address
236 *
237 * @v userptr User pointer
238 * @v offset Offset from user pointer
239 * @ret phys_addr Physical address
240 */
241 unsigned long user_to_phys ( userptr_t userptr, off_t offset );
242
243 /**
244 * Convert virtual address to user pointer
245 *
246 * @v addr Virtual address
247 * @ret userptr User pointer
248 */
249 userptr_t virt_to_user ( volatile const void *addr );
250
251 /**
252 * Convert user pointer to virtual address
253 *
254 * @v userptr User pointer
255 * @v offset Offset from user pointer
256 * @ret addr Virtual address
257 *
258 * This operation is not available under all memory models.
259 */
260 void * user_to_virt ( userptr_t userptr, off_t offset );
261
262 /**
263 * Add offset to user pointer
264 *
265 * @v userptr User pointer
266 * @v offset Offset
267 * @ret userptr New pointer value
268 */
269 userptr_t userptr_add ( userptr_t userptr, off_t offset );
270
271 /**
272 * Subtract user pointers
273 *
274 * @v userptr User pointer
275 * @v subtrahend User pointer to be subtracted
276 * @ret offset Offset
277 */
278 off_t userptr_sub ( userptr_t userptr, userptr_t subtrahend );
279
280 /**
281 * Convert virtual address to a physical address
282 *
283 * @v addr Virtual address
284 * @ret phys_addr Physical address
285 */
286 static inline __always_inline unsigned long
virt_to_phys(volatile const void * addr)287 virt_to_phys ( volatile const void *addr ) {
288 return user_to_phys ( virt_to_user ( addr ), 0 );
289 }
290
291 /**
292 * Convert physical address to a virtual address
293 *
294 * @v addr Virtual address
295 * @ret phys_addr Physical address
296 *
297 * This operation is not available under all memory models.
298 */
phys_to_virt(unsigned long phys_addr)299 static inline __always_inline void * phys_to_virt ( unsigned long phys_addr ) {
300 return user_to_virt ( phys_to_user ( phys_addr ), 0 );
301 }
302
303 /**
304 * Copy data between user buffers
305 *
306 * @v dest Destination
307 * @v dest_off Destination offset
308 * @v src Source
309 * @v src_off Source offset
310 * @v len Length
311 */
312 void memcpy_user ( userptr_t dest, off_t dest_off,
313 userptr_t src, off_t src_off, size_t len );
314
315 /**
316 * Copy data to user buffer
317 *
318 * @v dest Destination
319 * @v dest_off Destination offset
320 * @v src Source
321 * @v len Length
322 */
323 static inline __always_inline void
copy_to_user(userptr_t dest,off_t dest_off,const void * src,size_t len)324 copy_to_user ( userptr_t dest, off_t dest_off, const void *src, size_t len ) {
325 memcpy_user ( dest, dest_off, virt_to_user ( src ), 0, len );
326 }
327
328 /**
329 * Copy data from user buffer
330 *
331 * @v dest Destination
332 * @v src Source
333 * @v src_off Source offset
334 * @v len Length
335 */
336 static inline __always_inline void
copy_from_user(void * dest,userptr_t src,off_t src_off,size_t len)337 copy_from_user ( void *dest, userptr_t src, off_t src_off, size_t len ) {
338 memcpy_user ( virt_to_user ( dest ), 0, src, src_off, len );
339 }
340
341 /**
342 * Copy data between user buffers, allowing for overlap
343 *
344 * @v dest Destination
345 * @v dest_off Destination offset
346 * @v src Source
347 * @v src_off Source offset
348 * @v len Length
349 */
350 void memmove_user ( userptr_t dest, off_t dest_off,
351 userptr_t src, off_t src_off, size_t len );
352
353 /**
354 * Compare data between user buffers
355 *
356 * @v first First buffer
357 * @v first_off First buffer offset
358 * @v second Second buffer
359 * @v second_off Second buffer offset
360 * @v len Length
361 * @ret diff Difference
362 */
363 int memcmp_user ( userptr_t first, off_t first_off,
364 userptr_t second, off_t second_off, size_t len );
365
366 /**
367 * Fill user buffer with a constant byte
368 *
369 * @v userptr User buffer
370 * @v offset Offset within buffer
371 * @v c Constant byte with which to fill
372 * @v len Length
373 */
374 void memset_user ( userptr_t userptr, off_t offset, int c, size_t len );
375
376 /**
377 * Find length of NUL-terminated string in user buffer
378 *
379 * @v userptr User buffer
380 * @v offset Offset within buffer
381 * @ret len Length of string (excluding NUL)
382 */
383 size_t strlen_user ( userptr_t userptr, off_t offset );
384
385 /**
386 * Find character in user buffer
387 *
388 * @v userptr User buffer
389 * @v offset Starting offset within buffer
390 * @v c Character to search for
391 * @v len Length of user buffer
392 * @ret offset Offset of character, or <0 if not found
393 */
394 off_t memchr_user ( userptr_t userptr, off_t offset, int c, size_t len );
395
396 #endif /* _IPXE_UACCESS_H */
397