iPXE
uaccess.h
Go to the documentation of this file.
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 #ifdef UACCESS_FLAT
30 #define UACCESS_PREFIX_flat
31 #else
32 #define UACCESS_PREFIX_flat __flat_
33 #endif
34 
35 /**
36  * A pointer to a user buffer
37  *
38  */
39 typedef unsigned long userptr_t;
40 
41 /** Equivalent of NULL for user pointers */
42 #define UNULL ( ( userptr_t ) 0 )
43 
44 /**
45  * @defgroup uaccess_trivial Trivial user access API implementations
46  *
47  * User access API implementations that can be used by environments in
48  * which virtual addresses allow access to all of memory.
49  *
50  * @{
51  *
52  */
53 
54 /**
55  * Convert virtual address to user pointer
56  *
57  * @v addr Virtual address
58  * @ret userptr User pointer
59  */
60 static inline __always_inline userptr_t
61 trivial_virt_to_user ( volatile const void *addr ) {
62  return ( ( userptr_t ) addr );
63 }
64 
65 /**
66  * Convert user pointer to virtual address
67  *
68  * @v userptr User pointer
69  * @v offset Offset from user pointer
70  * @ret addr Virtual address
71  *
72  * This operation is not available under all memory models.
73  */
74 static inline __always_inline void *
76  return ( ( void * ) userptr + offset );
77 }
78 
79 /**
80  * Add offset to user pointer
81  *
82  * @v userptr User pointer
83  * @v offset Offset
84  * @ret userptr New pointer value
85  */
86 static inline __always_inline userptr_t
88  return ( userptr + offset );
89 }
90 
91 /**
92  * Subtract user pointers
93  *
94  * @v userptr User pointer
95  * @v subtrahend User pointer to be subtracted
96  * @ret offset Offset
97  */
98 static inline __always_inline off_t
100  return ( userptr - subtrahend );
101 }
102 
103 /**
104  * Copy data between user buffers
105  *
106  * @v dest Destination
107  * @v dest_off Destination offset
108  * @v src Source
109  * @v src_off Source offset
110  * @v len Length
111  */
112 static inline __always_inline void
114  userptr_t src, off_t src_off, size_t len ) {
115  memcpy ( ( ( void * ) dest + dest_off ),
116  ( ( void * ) src + src_off ), len );
117 }
118 
119 /**
120  * Copy data between user buffers, allowing for overlap
121  *
122  * @v dest Destination
123  * @v dest_off Destination offset
124  * @v src Source
125  * @v src_off Source offset
126  * @v len Length
127  */
128 static inline __always_inline void
130  userptr_t src, off_t src_off, size_t len ) {
131  memmove ( ( ( void * ) dest + dest_off ),
132  ( ( void * ) src + src_off ), len );
133 }
134 
135 /**
136  * Compare data between user buffers
137  *
138  * @v first First buffer
139  * @v first_off First buffer offset
140  * @v second Second buffer
141  * @v second_off Second buffer offset
142  * @v len Length
143  * @ret diff Difference
144  */
145 static inline __always_inline int
147  userptr_t second, off_t second_off, size_t len ) {
148  return memcmp ( ( ( void * ) first + first_off ),
149  ( ( void * ) second + second_off ), len );
150 }
151 
152 /**
153  * Fill user buffer with a constant byte
154  *
155  * @v buffer User buffer
156  * @v offset Offset within buffer
157  * @v c Constant byte with which to fill
158  * @v len Length
159  */
160 static inline __always_inline void
162  memset ( ( ( void * ) buffer + offset ), c, len );
163 }
164 
165 /**
166  * Find length of NUL-terminated string in user buffer
167  *
168  * @v buffer User buffer
169  * @v offset Offset within buffer
170  * @ret len Length of string (excluding NUL)
171  */
172 static inline __always_inline size_t
174  return strlen ( ( void * ) buffer + offset );
175 }
176 
177 /**
178  * Find character in user buffer
179  *
180  * @v buffer User buffer
181  * @v offset Starting offset within buffer
182  * @v c Character to search for
183  * @v len Length of user buffer
184  * @ret offset Offset of character, or <0 if not found
185  */
186 static inline __always_inline off_t
188  void *found;
189 
190  found = memchr ( ( ( void * ) buffer + offset ), c, len );
191  return ( found ? ( found - ( void * ) buffer ) : -1 );
192 }
193 
194 /** @} */
195 
196 /**
197  * Calculate static inline user access API function name
198  *
199  * @v _prefix Subsystem prefix
200  * @v _api_func API function
201  * @ret _subsys_func Subsystem API function
202  */
203 #define UACCESS_INLINE( _subsys, _api_func ) \
204  SINGLE_API_INLINE ( UACCESS_PREFIX_ ## _subsys, _api_func )
205 
206 /**
207  * Provide an user access API implementation
208  *
209  * @v _prefix Subsystem prefix
210  * @v _api_func API function
211  * @v _func Implementing function
212  */
213 #define PROVIDE_UACCESS( _subsys, _api_func, _func ) \
214  PROVIDE_SINGLE_API ( UACCESS_PREFIX_ ## _subsys, _api_func, _func )
215 
216 /**
217  * Provide a static inline user access API implementation
218  *
219  * @v _prefix Subsystem prefix
220  * @v _api_func API function
221  */
222 #define PROVIDE_UACCESS_INLINE( _subsys, _api_func ) \
223  PROVIDE_SINGLE_API_INLINE ( UACCESS_PREFIX_ ## _subsys, _api_func )
224 
225 static inline __always_inline userptr_t
226 UACCESS_INLINE ( flat, phys_to_user ) ( unsigned long phys_addr ) {
227  return phys_addr;
228 }
229 
230 static inline __always_inline unsigned long
232  return ( userptr + offset );
233 }
234 
235 static inline __always_inline userptr_t
236 UACCESS_INLINE ( flat, virt_to_user ) ( volatile const void *addr ) {
237  return trivial_virt_to_user ( addr );
238 }
239 
240 static inline __always_inline void *
241 UACCESS_INLINE ( flat, user_to_virt ) ( userptr_t userptr, off_t offset ) {
242  return trivial_user_to_virt ( userptr, offset );
243 }
244 
245 static inline __always_inline userptr_t
246 UACCESS_INLINE ( flat, userptr_add ) ( userptr_t userptr, off_t offset ) {
247  return trivial_userptr_add ( userptr, offset );
248 }
249 
250 static inline __always_inline off_t
251 UACCESS_INLINE ( flat, userptr_sub ) ( userptr_t userptr,
253  return trivial_userptr_sub ( userptr, subtrahend );
254 }
255 
256 static inline __always_inline void
259  size_t len ) {
261 }
262 
263 static inline __always_inline void
266  size_t len ) {
268 }
269 
270 static inline __always_inline int
273  size_t len ) {
275 }
276 
277 static inline __always_inline void
279  int c, size_t len ) {
281 }
282 
283 static inline __always_inline size_t
285  return trivial_strlen_user ( buffer, offset );
286 }
287 
288 static inline __always_inline off_t
290  int c, size_t len ) {
291  return trivial_memchr_user ( buffer, offset, c, len );
292 }
293 
294 /* Include all architecture-independent user access API headers */
296 
297 /* Include all architecture-dependent user access API headers */
298 #include <bits/uaccess.h>
299 
300 /**
301  * Convert physical address to user pointer
302  *
303  * @v phys_addr Physical address
304  * @ret userptr User pointer
305  */
306 userptr_t phys_to_user ( unsigned long phys_addr );
307 
308 /**
309  * Convert user pointer to physical address
310  *
311  * @v userptr User pointer
312  * @v offset Offset from user pointer
313  * @ret phys_addr Physical address
314  */
315 unsigned long user_to_phys ( userptr_t userptr, off_t offset );
316 
317 /**
318  * Convert virtual address to user pointer
319  *
320  * @v addr Virtual address
321  * @ret userptr User pointer
322  */
323 userptr_t virt_to_user ( volatile const void *addr );
324 
325 /**
326  * Convert user pointer to virtual address
327  *
328  * @v userptr User pointer
329  * @v offset Offset from user pointer
330  * @ret addr Virtual address
331  *
332  * This operation is not available under all memory models.
333  */
334 void * user_to_virt ( userptr_t userptr, off_t offset );
335 
336 /**
337  * Add offset to user pointer
338  *
339  * @v userptr User pointer
340  * @v offset Offset
341  * @ret userptr New pointer value
342  */
344 
345 /**
346  * Subtract user pointers
347  *
348  * @v userptr User pointer
349  * @v subtrahend User pointer to be subtracted
350  * @ret offset Offset
351  */
353 
354 /**
355  * Convert virtual address to a physical address
356  *
357  * @v addr Virtual address
358  * @ret phys_addr Physical address
359  */
360 static inline __always_inline unsigned long
361 virt_to_phys ( volatile const void *addr ) {
362  return user_to_phys ( virt_to_user ( addr ), 0 );
363 }
364 
365 /**
366  * Convert physical address to a virtual address
367  *
368  * @v addr Virtual address
369  * @ret phys_addr Physical address
370  *
371  * This operation is not available under all memory models.
372  */
373 static inline __always_inline void * phys_to_virt ( unsigned long phys_addr ) {
374  return user_to_virt ( phys_to_user ( phys_addr ), 0 );
375 }
376 
377 /**
378  * Copy data between user buffers
379  *
380  * @v dest Destination
381  * @v dest_off Destination offset
382  * @v src Source
383  * @v src_off Source offset
384  * @v len Length
385  */
387  userptr_t src, off_t src_off, size_t len );
388 
389 /**
390  * Copy data to user buffer
391  *
392  * @v dest Destination
393  * @v dest_off Destination offset
394  * @v src Source
395  * @v len Length
396  */
397 static inline __always_inline void
398 copy_to_user ( userptr_t dest, off_t dest_off, const void *src, size_t len ) {
400 }
401 
402 /**
403  * Copy data from user buffer
404  *
405  * @v dest Destination
406  * @v src Source
407  * @v src_off Source offset
408  * @v len Length
409  */
410 static inline __always_inline void
412  memcpy_user ( virt_to_user ( dest ), 0, src, src_off, len );
413 }
414 
415 /**
416  * Copy data between user buffers, allowing for overlap
417  *
418  * @v dest Destination
419  * @v dest_off Destination offset
420  * @v src Source
421  * @v src_off Source offset
422  * @v len Length
423  */
425  userptr_t src, off_t src_off, size_t len );
426 
427 /**
428  * Compare data between user buffers
429  *
430  * @v first First buffer
431  * @v first_off First buffer offset
432  * @v second Second buffer
433  * @v second_off Second buffer offset
434  * @v len Length
435  * @ret diff Difference
436  */
438  userptr_t second, off_t second_off, size_t len );
439 
440 /**
441  * Fill user buffer with a constant byte
442  *
443  * @v userptr User buffer
444  * @v offset Offset within buffer
445  * @v c Constant byte with which to fill
446  * @v len Length
447  */
448 void memset_user ( userptr_t userptr, off_t offset, int c, size_t len );
449 
450 /**
451  * Find length of NUL-terminated string in user buffer
452  *
453  * @v userptr User buffer
454  * @v offset Offset within buffer
455  * @ret len Length of string (excluding NUL)
456  */
457 size_t strlen_user ( userptr_t userptr, off_t offset );
458 
459 /**
460  * Find character in user buffer
461  *
462  * @v userptr User buffer
463  * @v offset Starting offset within buffer
464  * @v c Character to search for
465  * @v len Length of user buffer
466  * @ret offset Offset of character, or <0 if not found
467  */
468 off_t memchr_user ( userptr_t userptr, off_t offset, int c, size_t len );
469 
470 #endif /* _IPXE_UACCESS_H */
static __always_inline void off_t userptr_t off_t size_t len
Definition: uaccess.h:259
static __always_inline size_t trivial_strlen_user(userptr_t buffer, off_t offset)
Find length of NUL-terminated string in user buffer.
Definition: uaccess.h:173
iPXE internal APIs
static __always_inline int trivial_memcmp_user(userptr_t first, off_t first_off, userptr_t second, off_t second_off, size_t len)
Compare data between user buffers.
Definition: uaccess.h:146
static __always_inline void off_t userptr_t src
Definition: uaccess.h:257
uint32_t first
First block in range.
Definition: pccrr.h:14
static __always_inline void * trivial_user_to_virt(userptr_t userptr, off_t offset)
Convert user pointer to virtual address.
Definition: uaccess.h:75
off_t memchr_user(userptr_t userptr, off_t offset, int c, size_t len)
Find character in user buffer.
static __always_inline void copy_from_user(void *dest, userptr_t src, off_t src_off, size_t len)
Copy data from user buffer.
Definition: uaccess.h:411
unsigned long user_to_phys(userptr_t userptr, off_t offset)
Convert user pointer to physical address.
iPXE user access API for Linux
static __always_inline userptr_t trivial_userptr_add(userptr_t userptr, off_t offset)
Add offset to user pointer.
Definition: uaccess.h:87
userptr_t phys_to_user(unsigned long phys_addr)
Convert physical address to user pointer.
static __always_inline void trivial_memmove_user(userptr_t dest, off_t dest_off, userptr_t src, off_t src_off, size_t len)
Copy data between user buffers, allowing for overlap.
Definition: uaccess.h:129
uint32_t buffer
Buffer index (or NETVSC_RNDIS_NO_BUFFER)
Definition: netvsc.h:16
static __always_inline unsigned long virt_to_phys(volatile const void *addr)
Convert virtual address to a physical address.
Definition: uaccess.h:361
static __always_inline off_t trivial_memchr_user(userptr_t buffer, off_t offset, int c, size_t len)
Find character in user buffer.
Definition: uaccess.h:187
void * memchr(const void *src, int character, size_t len)
Find character within a memory region.
Definition: string.c:135
off_t userptr_sub(userptr_t userptr, userptr_t subtrahend)
Subtract user pointers.
static __always_inline void * phys_to_virt(unsigned long phys_addr)
Convert physical address to a virtual address.
Definition: uaccess.h:373
void memset_user(userptr_t userptr, off_t offset, int c, size_t len)
Fill user buffer with a constant byte.
userptr_t userptr_add(userptr_t userptr, off_t offset)
Add offset to user pointer.
void * memcpy(void *dest, const void *src, size_t len) __nonnull
uint32_t userptr_t
A pointer to a user buffer.
Definition: libkir.h:159
static __always_inline void off_t dest_off
Definition: uaccess.h:257
static __always_inline void off_t userptr_t off_t src_off
Definition: uaccess.h:257
#define __always_inline
Declare a function to be always inline.
Definition: compiler.h:611
static __always_inline void copy_to_user(userptr_t dest, off_t dest_off, const void *src, size_t len)
Copy data to user buffer.
Definition: uaccess.h:398
size_t strlen(const char *src)
Get length of string.
Definition: string.c:243
FILE_LICENCE(GPL2_OR_LATER_OR_UBDL)
void * memmove(void *dest, const void *src, size_t len) __nonnull
static __always_inline int off_t first_off
Definition: uaccess.h:271
static __always_inline unsigned long off_t offset
Definition: uaccess.h:231
static __always_inline off_t trivial_userptr_sub(userptr_t userptr, userptr_t subtrahend)
Subtract user pointers.
Definition: uaccess.h:99
size_t strlen_user(userptr_t userptr, off_t offset)
Find length of NUL-terminated string in user buffer.
signed long off_t
Definition: stdint.h:8
I/O API configuration.
#define UACCESS_INLINE(_subsys, _api_func)
Calculate static inline user access API function name.
Definition: uaccess.h:203
int memcmp_user(userptr_t first, off_t first_off, userptr_t second, off_t second_off, size_t len)
Compare data between user buffers.
static __always_inline int off_t userptr_t second
Definition: uaccess.h:271
u32 addr
Definition: sky2.h:8
static __always_inline void trivial_memcpy_user(userptr_t dest, off_t dest_off, userptr_t src, off_t src_off, size_t len)
Copy data between user buffers.
Definition: uaccess.h:113
userptr_t virt_to_user(volatile const void *addr)
Convert virtual address to user pointer.
void * user_to_virt(userptr_t userptr, off_t offset)
Convert user pointer to virtual address.
if(len >=6 *4) __asm__ __volatile__("movsl" if(len >=5 *4) __asm__ __volatile__("movsl" if(len >=4 *4) __asm__ __volatile__("movsl" if(len >=3 *4) __asm__ __volatile__("movsl" if(len >=2 *4) __asm__ __volatile__("movsl" if(len >=1 *4) __asm__ __volatile__("movsl" if((len % 4) >=2) __asm__ __volatile__("movsw" if((len % 2) >=1) __asm__ __volatile__("movsb" return dest
Definition: string.h:150
static __always_inline off_t userptr_t subtrahend
Definition: uaccess.h:252
void memmove_user(userptr_t dest, off_t dest_off, userptr_t src, off_t src_off, size_t len)
Copy data between user buffers, allowing for overlap.
static __always_inline void off_t int c
Definition: uaccess.h:278
static __always_inline int off_t userptr_t off_t second_off
Definition: uaccess.h:271
static __always_inline userptr_t trivial_virt_to_user(volatile const void *addr)
Convert virtual address to user pointer.
Definition: uaccess.h:61
int memcmp(const void *first, const void *second, size_t len)
Compare memory regions.
Definition: string.c:114
void memcpy_user(userptr_t dest, off_t dest_off, userptr_t src, off_t src_off, size_t len)
Copy data between user buffers.
String functions.
unsigned long userptr_t
A pointer to a user buffer.
Definition: uaccess.h:39
static __always_inline void trivial_memset_user(userptr_t buffer, off_t offset, int c, size_t len)
Fill user buffer with a constant byte.
Definition: uaccess.h:161
void * memset(void *dest, int character, size_t len) __nonnull