1 #ifndef _IPXE_UACCESS_H
2 #define _IPXE_UACCESS_H
7 * Access to external ("user") memory
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.
17 * Note that userptr_t is an opaque type; in particular, performing
18 * arithmetic upon a userptr_t is not allowed.
22 FILE_LICENCE ( GPL2_OR_LATER );
27 #include <config/ioapi.h>
30 * A pointer to a user buffer
33 typedef unsigned long userptr_t;
35 /** Equivalent of NULL for user pointers */
36 #define UNULL ( ( userptr_t ) 0 )
39 * @defgroup uaccess_trivial Trivial user access API implementations
41 * User access API implementations that can be used by environments in
42 * which virtual addresses allow access to all of memory.
49 * Convert virtual address to user pointer
51 * @v addr Virtual address
52 * @ret userptr User pointer
54 static inline __always_inline userptr_t
55 trivial_virt_to_user ( volatile const void *addr ) {
56 return ( ( userptr_t ) addr );
60 * Convert user pointer to virtual address
62 * @v userptr User pointer
63 * @v offset Offset from user pointer
64 * @ret addr Virtual address
66 * This operation is not available under all memory models.
68 static inline __always_inline void *
69 trivial_user_to_virt ( userptr_t userptr, off_t offset ) {
70 return ( ( void * ) userptr + offset );
74 * Add offset to user pointer
76 * @v userptr User pointer
78 * @ret userptr New pointer value
80 static inline __always_inline userptr_t
81 trivial_userptr_add ( userptr_t userptr, off_t offset ) {
82 return ( userptr + offset );
86 * Subtract user pointers
88 * @v userptr User pointer
89 * @v subtrahend User pointer to be subtracted
92 static inline __always_inline off_t
93 trivial_userptr_sub ( userptr_t userptr, userptr_t subtrahend ) {
94 return ( userptr - subtrahend );
98 * Copy data between user buffers
100 * @v dest Destination
101 * @v dest_off Destination offset
103 * @v src_off Source offset
106 static inline __always_inline void
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 );
114 * Copy data between user buffers, allowing for overlap
116 * @v dest Destination
117 * @v dest_off Destination offset
119 * @v src_off Source offset
122 static inline __always_inline void
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 );
130 * Compare data between user buffers
132 * @v first First buffer
133 * @v first_off First buffer offset
134 * @v second Second buffer
135 * @v second_off Second buffer offset
137 * @ret diff Difference
139 static inline __always_inline int
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 );
147 * Fill user buffer with a constant byte
149 * @v buffer User buffer
150 * @v offset Offset within buffer
151 * @v c Constant byte with which to fill
154 static inline __always_inline void
155 trivial_memset_user ( userptr_t buffer, off_t offset, int c, size_t len ) {
156 memset ( ( ( void * ) buffer + offset ), c, len );
160 * Find length of NUL-terminated string in user buffer
162 * @v buffer User buffer
163 * @v offset Offset within buffer
164 * @ret len Length of string (excluding NUL)
166 static inline __always_inline size_t
167 trivial_strlen_user ( userptr_t buffer, off_t offset ) {
168 return strlen ( ( void * ) buffer + offset );
172 * Find character in user buffer
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
180 static inline __always_inline off_t
181 trivial_memchr_user ( userptr_t buffer, off_t offset, int c, size_t len ) {
184 found = memchr ( ( ( void * ) buffer + offset ), c, len );
185 return ( found ? ( found - ( void * ) buffer ) : -1 );
191 * Calculate static inline user access API function name
193 * @v _prefix Subsystem prefix
194 * @v _api_func API function
195 * @ret _subsys_func Subsystem API function
197 #define UACCESS_INLINE( _subsys, _api_func ) \
198 SINGLE_API_INLINE ( UACCESS_PREFIX_ ## _subsys, _api_func )
201 * Provide an user access API implementation
203 * @v _prefix Subsystem prefix
204 * @v _api_func API function
205 * @v _func Implementing function
207 #define PROVIDE_UACCESS( _subsys, _api_func, _func ) \
208 PROVIDE_SINGLE_API ( UACCESS_PREFIX_ ## _subsys, _api_func, _func )
211 * Provide a static inline user access API implementation
213 * @v _prefix Subsystem prefix
214 * @v _api_func API function
216 #define PROVIDE_UACCESS_INLINE( _subsys, _api_func ) \
217 PROVIDE_SINGLE_API_INLINE ( UACCESS_PREFIX_ ## _subsys, _api_func )
219 /* Include all architecture-independent user access API headers */
220 #include <ipxe/efi/efi_uaccess.h>
221 #include <ipxe/linux/linux_uaccess.h>
223 /* Include all architecture-dependent user access API headers */
224 #include <bits/uaccess.h>
227 * Convert physical address to user pointer
229 * @v phys_addr Physical address
230 * @ret userptr User pointer
232 userptr_t phys_to_user ( unsigned long phys_addr );
235 * Convert user pointer to physical address
237 * @v userptr User pointer
238 * @v offset Offset from user pointer
239 * @ret phys_addr Physical address
241 unsigned long user_to_phys ( userptr_t userptr, off_t offset );
244 * Convert virtual address to user pointer
246 * @v addr Virtual address
247 * @ret userptr User pointer
249 userptr_t virt_to_user ( volatile const void *addr );
252 * Convert user pointer to virtual address
254 * @v userptr User pointer
255 * @v offset Offset from user pointer
256 * @ret addr Virtual address
258 * This operation is not available under all memory models.
260 void * user_to_virt ( userptr_t userptr, off_t offset );
263 * Add offset to user pointer
265 * @v userptr User pointer
267 * @ret userptr New pointer value
269 userptr_t userptr_add ( userptr_t userptr, off_t offset );
272 * Subtract user pointers
274 * @v userptr User pointer
275 * @v subtrahend User pointer to be subtracted
278 off_t userptr_sub ( userptr_t userptr, userptr_t subtrahend );
281 * Convert virtual address to a physical address
283 * @v addr Virtual address
284 * @ret phys_addr Physical address
286 static inline __always_inline unsigned long
287 virt_to_phys ( volatile const void *addr ) {
288 return user_to_phys ( virt_to_user ( addr ), 0 );
292 * Convert physical address to a virtual address
294 * @v addr Virtual address
295 * @ret phys_addr Physical address
297 * This operation is not available under all memory models.
299 static inline __always_inline void * phys_to_virt ( unsigned long phys_addr ) {
300 return user_to_virt ( phys_to_user ( phys_addr ), 0 );
304 * Copy data between user buffers
306 * @v dest Destination
307 * @v dest_off Destination offset
309 * @v src_off Source offset
312 void memcpy_user ( userptr_t dest, off_t dest_off,
313 userptr_t src, off_t src_off, size_t len );
316 * Copy data to user buffer
318 * @v dest Destination
319 * @v dest_off Destination offset
323 static inline __always_inline void
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 );
329 * Copy data from user buffer
331 * @v dest Destination
333 * @v src_off Source offset
336 static inline __always_inline void
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 );
342 * Copy data between user buffers, allowing for overlap
344 * @v dest Destination
345 * @v dest_off Destination offset
347 * @v src_off Source offset
350 void memmove_user ( userptr_t dest, off_t dest_off,
351 userptr_t src, off_t src_off, size_t len );
354 * Compare data between user buffers
356 * @v first First buffer
357 * @v first_off First buffer offset
358 * @v second Second buffer
359 * @v second_off Second buffer offset
361 * @ret diff Difference
363 int memcmp_user ( userptr_t first, off_t first_off,
364 userptr_t second, off_t second_off, size_t len );
367 * Fill user buffer with a constant byte
369 * @v userptr User buffer
370 * @v offset Offset within buffer
371 * @v c Constant byte with which to fill
374 void memset_user ( userptr_t userptr, off_t offset, int c, size_t len );
377 * Find length of NUL-terminated string in user buffer
379 * @v userptr User buffer
380 * @v offset Offset within buffer
381 * @ret len Length of string (excluding NUL)
383 size_t strlen_user ( userptr_t userptr, off_t offset );
386 * Find character in user buffer
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
394 off_t memchr_user ( userptr_t userptr, off_t offset, int c, size_t len );
396 #endif /* _IPXE_UACCESS_H */