• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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