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 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 * 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 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 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 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 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 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 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 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 */ 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 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 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