1 #ifndef _GPXE_UACCESS_H
2 #define _GPXE_UACCESS_H
3
4 /**
5 * @file
6 *
7 * Access to external ("user") memory
8 *
9 * gPXE 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 );
23
24 #include <stdint.h>
25 #include <string.h>
26 #include <gpxe/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 * Copy data between user buffers
87 *
88 * @v dest Destination
89 * @v dest_off Destination offset
90 * @v src Source
91 * @v src_off Source offset
92 * @v len Length
93 */
94 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)95 trivial_memcpy_user ( userptr_t dest, off_t dest_off,
96 userptr_t src, off_t src_off, size_t len ) {
97 memcpy ( ( ( void * ) dest + dest_off ),
98 ( ( void * ) src + src_off ), len );
99 }
100
101 /**
102 * Copy data between user buffers, allowing for overlap
103 *
104 * @v dest Destination
105 * @v dest_off Destination offset
106 * @v src Source
107 * @v src_off Source offset
108 * @v len Length
109 */
110 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)111 trivial_memmove_user ( userptr_t dest, off_t dest_off,
112 userptr_t src, off_t src_off, size_t len ) {
113 memmove ( ( ( void * ) dest + dest_off ),
114 ( ( void * ) src + src_off ), len );
115 }
116
117 /**
118 * Fill user buffer with a constant byte
119 *
120 * @v buffer User buffer
121 * @v offset Offset within buffer
122 * @v c Constant byte with which to fill
123 * @v len Length
124 */
125 static inline __always_inline void
trivial_memset_user(userptr_t buffer,off_t offset,int c,size_t len)126 trivial_memset_user ( userptr_t buffer, off_t offset, int c, size_t len ) {
127 memset ( ( ( void * ) buffer + offset ), c, len );
128 }
129
130 /**
131 * Find length of NUL-terminated string in user buffer
132 *
133 * @v buffer User buffer
134 * @v offset Offset within buffer
135 * @ret len Length of string (excluding NUL)
136 */
137 static inline __always_inline size_t
trivial_strlen_user(userptr_t buffer,off_t offset)138 trivial_strlen_user ( userptr_t buffer, off_t offset ) {
139 return strlen ( ( void * ) buffer + offset );
140 }
141
142 /**
143 * Find character in user buffer
144 *
145 * @v buffer User buffer
146 * @v offset Starting offset within buffer
147 * @v c Character to search for
148 * @v len Length of user buffer
149 * @ret offset Offset of character, or <0 if not found
150 */
151 static inline __always_inline off_t
trivial_memchr_user(userptr_t buffer,off_t offset,int c,size_t len)152 trivial_memchr_user ( userptr_t buffer, off_t offset, int c, size_t len ) {
153 void *found;
154
155 found = memchr ( ( ( void * ) buffer + offset ), c, len );
156 return ( found ? ( found - ( void * ) buffer ) : -1 );
157 }
158
159 /** @} */
160
161 /**
162 * Calculate static inline user access API function name
163 *
164 * @v _prefix Subsystem prefix
165 * @v _api_func API function
166 * @ret _subsys_func Subsystem API function
167 */
168 #define UACCESS_INLINE( _subsys, _api_func ) \
169 SINGLE_API_INLINE ( UACCESS_PREFIX_ ## _subsys, _api_func )
170
171 /**
172 * Provide an user access API implementation
173 *
174 * @v _prefix Subsystem prefix
175 * @v _api_func API function
176 * @v _func Implementing function
177 */
178 #define PROVIDE_UACCESS( _subsys, _api_func, _func ) \
179 PROVIDE_SINGLE_API ( UACCESS_PREFIX_ ## _subsys, _api_func, _func )
180
181 /**
182 * Provide a static inline user access API implementation
183 *
184 * @v _prefix Subsystem prefix
185 * @v _api_func API function
186 */
187 #define PROVIDE_UACCESS_INLINE( _subsys, _api_func ) \
188 PROVIDE_SINGLE_API_INLINE ( UACCESS_PREFIX_ ## _subsys, _api_func )
189
190 /* Include all architecture-independent user access API headers */
191 #include <gpxe/efi/efi_uaccess.h>
192
193 /* Include all architecture-dependent user access API headers */
194 #include <bits/uaccess.h>
195
196 /**
197 * Convert physical address to user pointer
198 *
199 * @v phys_addr Physical address
200 * @ret userptr User pointer
201 */
202 userptr_t phys_to_user ( unsigned long phys_addr );
203
204 /**
205 * Convert user pointer to physical address
206 *
207 * @v userptr User pointer
208 * @v offset Offset from user pointer
209 * @ret phys_addr Physical address
210 */
211 unsigned long user_to_phys ( userptr_t userptr, off_t offset );
212
213 /**
214 * Convert virtual address to user pointer
215 *
216 * @v addr Virtual address
217 * @ret userptr User pointer
218 */
219 userptr_t virt_to_user ( volatile const void *addr );
220
221 /**
222 * Convert user pointer to virtual address
223 *
224 * @v userptr User pointer
225 * @v offset Offset from user pointer
226 * @ret addr Virtual address
227 *
228 * This operation is not available under all memory models.
229 */
230 void * user_to_virt ( userptr_t userptr, off_t offset );
231
232 /**
233 * Add offset to user pointer
234 *
235 * @v userptr User pointer
236 * @v offset Offset
237 * @ret userptr New pointer value
238 */
239 userptr_t userptr_add ( userptr_t userptr, off_t offset );
240
241 /**
242 * Convert virtual address to a physical address
243 *
244 * @v addr Virtual address
245 * @ret phys_addr Physical address
246 */
247 static inline __always_inline unsigned long
virt_to_phys(volatile const void * addr)248 virt_to_phys ( volatile const void *addr ) {
249 return user_to_phys ( virt_to_user ( addr ), 0 );
250 }
251
252 /**
253 * Convert physical address to a virtual address
254 *
255 * @v addr Virtual address
256 * @ret phys_addr Physical address
257 *
258 * This operation is not available under all memory models.
259 */
phys_to_virt(unsigned long phys_addr)260 static inline __always_inline void * phys_to_virt ( unsigned long phys_addr ) {
261 return user_to_virt ( phys_to_user ( phys_addr ), 0 );
262 }
263
264 /**
265 * Copy data between user buffers
266 *
267 * @v dest Destination
268 * @v dest_off Destination offset
269 * @v src Source
270 * @v src_off Source offset
271 * @v len Length
272 */
273 void memcpy_user ( userptr_t dest, off_t dest_off,
274 userptr_t src, off_t src_off, size_t len );
275
276 /**
277 * Copy data to user buffer
278 *
279 * @v dest Destination
280 * @v dest_off Destination offset
281 * @v src Source
282 * @v len Length
283 */
284 static inline __always_inline void
copy_to_user(userptr_t dest,off_t dest_off,const void * src,size_t len)285 copy_to_user ( userptr_t dest, off_t dest_off, const void *src, size_t len ) {
286 memcpy_user ( dest, dest_off, virt_to_user ( src ), 0, len );
287 }
288
289 /**
290 * Copy data from user buffer
291 *
292 * @v dest Destination
293 * @v src Source
294 * @v src_off Source offset
295 * @v len Length
296 */
297 static inline __always_inline void
copy_from_user(void * dest,userptr_t src,off_t src_off,size_t len)298 copy_from_user ( void *dest, userptr_t src, off_t src_off, size_t len ) {
299 memcpy_user ( virt_to_user ( dest ), 0, src, src_off, len );
300 }
301
302 /**
303 * Copy data between user buffers, allowing for overlap
304 *
305 * @v dest Destination
306 * @v dest_off Destination offset
307 * @v src Source
308 * @v src_off Source offset
309 * @v len Length
310 */
311 void memmove_user ( userptr_t dest, off_t dest_off,
312 userptr_t src, off_t src_off, size_t len );
313
314 /**
315 * Fill user buffer with a constant byte
316 *
317 * @v userptr User buffer
318 * @v offset Offset within buffer
319 * @v c Constant byte with which to fill
320 * @v len Length
321 */
322 void memset_user ( userptr_t userptr, off_t offset, int c, size_t len );
323
324 /**
325 * Find length of NUL-terminated string in user buffer
326 *
327 * @v userptr User buffer
328 * @v offset Offset within buffer
329 * @ret len Length of string (excluding NUL)
330 */
331 size_t strlen_user ( userptr_t userptr, off_t offset );
332
333 /**
334 * Find character in user buffer
335 *
336 * @v userptr User buffer
337 * @v offset Starting offset within buffer
338 * @v c Character to search for
339 * @v len Length of user buffer
340 * @ret offset Offset of character, or <0 if not found
341 */
342 off_t memchr_user ( userptr_t userptr, off_t offset, int c, size_t len );
343
344 #endif /* _GPXE_UACCESS_H */
345