iPXE
uaccess.h
Go to the documentation of this file.
00001 #ifndef _IPXE_UACCESS_H
00002 #define _IPXE_UACCESS_H
00003 
00004 /**
00005  * @file
00006  *
00007  * Access to external ("user") memory
00008  *
00009  * iPXE often needs to transfer data between internal and external
00010  * buffers.  On i386, the external buffers may require access via a
00011  * different segment, and the buffer address cannot be encoded into a
00012  * simple void * pointer.  The @c userptr_t type encapsulates the
00013  * information needed to identify an external buffer, and the
00014  * copy_to_user() and copy_from_user() functions provide methods for
00015  * transferring data between internal and external buffers.
00016  *
00017  * Note that userptr_t is an opaque type; in particular, performing
00018  * arithmetic upon a userptr_t is not allowed.
00019  *
00020  */
00021 
00022 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
00023 
00024 #include <stdint.h>
00025 #include <string.h>
00026 #include <ipxe/api.h>
00027 #include <config/ioapi.h>
00028 
00029 /**
00030  * A pointer to a user buffer
00031  *
00032  */
00033 typedef unsigned long userptr_t;
00034 
00035 /** Equivalent of NULL for user pointers */
00036 #define UNULL ( ( userptr_t ) 0 )
00037 
00038 /**
00039  * @defgroup uaccess_trivial Trivial user access API implementations
00040  *
00041  * User access API implementations that can be used by environments in
00042  * which virtual addresses allow access to all of memory.
00043  *
00044  * @{
00045  *
00046  */
00047 
00048 /**
00049  * Convert virtual address to user pointer
00050  *
00051  * @v addr              Virtual address
00052  * @ret userptr         User pointer
00053  */
00054 static inline __always_inline userptr_t
00055 trivial_virt_to_user ( volatile const void *addr ) {
00056         return ( ( userptr_t ) addr );
00057 }
00058 
00059 /**
00060  * Convert user pointer to virtual address
00061  *
00062  * @v userptr           User pointer
00063  * @v offset            Offset from user pointer
00064  * @ret addr            Virtual address
00065  *
00066  * This operation is not available under all memory models.
00067  */
00068 static inline __always_inline void *
00069 trivial_user_to_virt ( userptr_t userptr, off_t offset ) {
00070         return ( ( void * ) userptr + offset );
00071 }
00072 
00073 /**
00074  * Add offset to user pointer
00075  *
00076  * @v userptr           User pointer
00077  * @v offset            Offset
00078  * @ret userptr         New pointer value
00079  */
00080 static inline __always_inline userptr_t
00081 trivial_userptr_add ( userptr_t userptr, off_t offset ) {
00082         return ( userptr + offset );
00083 }
00084 
00085 /**
00086  * Subtract user pointers
00087  *
00088  * @v userptr           User pointer
00089  * @v subtrahend        User pointer to be subtracted
00090  * @ret offset          Offset
00091  */
00092 static inline __always_inline off_t
00093 trivial_userptr_sub ( userptr_t userptr, userptr_t subtrahend ) {
00094         return ( userptr - subtrahend );
00095 }
00096 
00097 /**
00098  * Copy data between user buffers
00099  *
00100  * @v dest              Destination
00101  * @v dest_off          Destination offset
00102  * @v src               Source
00103  * @v src_off           Source offset
00104  * @v len               Length
00105  */
00106 static inline __always_inline void
00107 trivial_memcpy_user ( userptr_t dest, off_t dest_off,
00108                       userptr_t src, off_t src_off, size_t len ) {
00109         memcpy ( ( ( void * ) dest + dest_off ),
00110                  ( ( void * ) src + src_off ), len );
00111 }
00112 
00113 /**
00114  * Copy data between user buffers, allowing for overlap
00115  *
00116  * @v dest              Destination
00117  * @v dest_off          Destination offset
00118  * @v src               Source
00119  * @v src_off           Source offset
00120  * @v len               Length
00121  */
00122 static inline __always_inline void
00123 trivial_memmove_user ( userptr_t dest, off_t dest_off,
00124                        userptr_t src, off_t src_off, size_t len ) {
00125         memmove ( ( ( void * ) dest + dest_off ),
00126                   ( ( void * ) src + src_off ), len );
00127 }
00128 
00129 /**
00130  * Compare data between user buffers
00131  *
00132  * @v first             First buffer
00133  * @v first_off         First buffer offset
00134  * @v second            Second buffer
00135  * @v second_off        Second buffer offset
00136  * @v len               Length
00137  * @ret diff            Difference
00138  */
00139 static inline __always_inline int
00140 trivial_memcmp_user ( userptr_t first, off_t first_off,
00141                       userptr_t second, off_t second_off, size_t len ) {
00142         return memcmp ( ( ( void * ) first + first_off ),
00143                         ( ( void * ) second + second_off ), len );
00144 }
00145 
00146 /**
00147  * Fill user buffer with a constant byte
00148  *
00149  * @v buffer            User buffer
00150  * @v offset            Offset within buffer
00151  * @v c                 Constant byte with which to fill
00152  * @v len               Length
00153  */
00154 static inline __always_inline void
00155 trivial_memset_user ( userptr_t buffer, off_t offset, int c, size_t len ) {
00156         memset ( ( ( void * ) buffer + offset ), c, len );
00157 }
00158 
00159 /**
00160  * Find length of NUL-terminated string in user buffer
00161  *
00162  * @v buffer            User buffer
00163  * @v offset            Offset within buffer
00164  * @ret len             Length of string (excluding NUL)
00165  */
00166 static inline __always_inline size_t
00167 trivial_strlen_user ( userptr_t buffer, off_t offset ) {
00168         return strlen ( ( void * ) buffer + offset );
00169 }
00170 
00171 /**
00172  * Find character in user buffer
00173  *
00174  * @v buffer            User buffer
00175  * @v offset            Starting offset within buffer
00176  * @v c                 Character to search for
00177  * @v len               Length of user buffer
00178  * @ret offset          Offset of character, or <0 if not found
00179  */
00180 static inline __always_inline off_t
00181 trivial_memchr_user ( userptr_t buffer, off_t offset, int c, size_t len ) {
00182         void *found;
00183 
00184         found = memchr ( ( ( void * ) buffer + offset ), c, len );
00185         return ( found ? ( found - ( void * ) buffer ) : -1 );
00186 }
00187 
00188 /** @} */
00189 
00190 /**
00191  * Calculate static inline user access API function name
00192  *
00193  * @v _prefix           Subsystem prefix
00194  * @v _api_func         API function
00195  * @ret _subsys_func    Subsystem API function
00196  */
00197 #define UACCESS_INLINE( _subsys, _api_func ) \
00198         SINGLE_API_INLINE ( UACCESS_PREFIX_ ## _subsys, _api_func )
00199 
00200 /**
00201  * Provide an user access API implementation
00202  *
00203  * @v _prefix           Subsystem prefix
00204  * @v _api_func         API function
00205  * @v _func             Implementing function
00206  */
00207 #define PROVIDE_UACCESS( _subsys, _api_func, _func ) \
00208         PROVIDE_SINGLE_API ( UACCESS_PREFIX_ ## _subsys, _api_func, _func )
00209 
00210 /**
00211  * Provide a static inline user access API implementation
00212  *
00213  * @v _prefix           Subsystem prefix
00214  * @v _api_func         API function
00215  */
00216 #define PROVIDE_UACCESS_INLINE( _subsys, _api_func ) \
00217         PROVIDE_SINGLE_API_INLINE ( UACCESS_PREFIX_ ## _subsys, _api_func )
00218 
00219 /* Include all architecture-independent user access API headers */
00220 #include <ipxe/efi/efi_uaccess.h>
00221 #include <ipxe/linux/linux_uaccess.h>
00222 
00223 /* Include all architecture-dependent user access API headers */
00224 #include <bits/uaccess.h>
00225 
00226 /**
00227  * Convert physical address to user pointer
00228  *
00229  * @v phys_addr         Physical address
00230  * @ret userptr         User pointer
00231  */
00232 userptr_t phys_to_user ( unsigned long phys_addr );
00233 
00234 /**
00235  * Convert user pointer to physical address
00236  *
00237  * @v userptr           User pointer
00238  * @v offset            Offset from user pointer
00239  * @ret phys_addr       Physical address
00240  */
00241 unsigned long user_to_phys ( userptr_t userptr, off_t offset );
00242 
00243 /**
00244  * Convert virtual address to user pointer
00245  *
00246  * @v addr              Virtual address
00247  * @ret userptr         User pointer
00248  */
00249 userptr_t virt_to_user ( volatile const void *addr );
00250 
00251 /**
00252  * Convert user pointer to virtual address
00253  *
00254  * @v userptr           User pointer
00255  * @v offset            Offset from user pointer
00256  * @ret addr            Virtual address
00257  *
00258  * This operation is not available under all memory models.
00259  */
00260 void * user_to_virt ( userptr_t userptr, off_t offset );
00261 
00262 /**
00263  * Add offset to user pointer
00264  *
00265  * @v userptr           User pointer
00266  * @v offset            Offset
00267  * @ret userptr         New pointer value
00268  */
00269 userptr_t userptr_add ( userptr_t userptr, off_t offset );
00270 
00271 /**
00272  * Subtract user pointers
00273  *
00274  * @v userptr           User pointer
00275  * @v subtrahend        User pointer to be subtracted
00276  * @ret offset          Offset
00277  */
00278 off_t userptr_sub ( userptr_t userptr, userptr_t subtrahend );
00279 
00280 /**
00281  * Convert virtual address to a physical address
00282  *
00283  * @v addr              Virtual address
00284  * @ret phys_addr       Physical address
00285  */
00286 static inline __always_inline unsigned long
00287 virt_to_phys ( volatile const void *addr ) {
00288         return user_to_phys ( virt_to_user ( addr ), 0 );
00289 }
00290 
00291 /**
00292  * Convert physical address to a virtual address
00293  *
00294  * @v addr              Virtual address
00295  * @ret phys_addr       Physical address
00296  *
00297  * This operation is not available under all memory models.
00298  */
00299 static inline __always_inline void * phys_to_virt ( unsigned long phys_addr ) {
00300         return user_to_virt ( phys_to_user ( phys_addr ), 0 );
00301 }
00302 
00303 /**
00304  * Copy data between user buffers
00305  *
00306  * @v dest              Destination
00307  * @v dest_off          Destination offset
00308  * @v src               Source
00309  * @v src_off           Source offset
00310  * @v len               Length
00311  */
00312 void memcpy_user ( userptr_t dest, off_t dest_off,
00313                    userptr_t src, off_t src_off, size_t len );
00314 
00315 /**
00316  * Copy data to user buffer
00317  *
00318  * @v dest              Destination
00319  * @v dest_off          Destination offset
00320  * @v src               Source
00321  * @v len               Length
00322  */
00323 static inline __always_inline void
00324 copy_to_user ( userptr_t dest, off_t dest_off, const void *src, size_t len ) {
00325         memcpy_user ( dest, dest_off, virt_to_user ( src ), 0, len );
00326 }
00327 
00328 /**
00329  * Copy data from user buffer
00330  *
00331  * @v dest              Destination
00332  * @v src               Source
00333  * @v src_off           Source offset
00334  * @v len               Length
00335  */
00336 static inline __always_inline void
00337 copy_from_user ( void *dest, userptr_t src, off_t src_off, size_t len ) {
00338         memcpy_user ( virt_to_user ( dest ), 0, src, src_off, len );
00339 }
00340 
00341 /**
00342  * Copy data between user buffers, allowing for overlap
00343  *
00344  * @v dest              Destination
00345  * @v dest_off          Destination offset
00346  * @v src               Source
00347  * @v src_off           Source offset
00348  * @v len               Length
00349  */
00350 void memmove_user ( userptr_t dest, off_t dest_off,
00351                     userptr_t src, off_t src_off, size_t len );
00352 
00353 /**
00354  * Compare data between user buffers
00355  *
00356  * @v first             First buffer
00357  * @v first_off         First buffer offset
00358  * @v second            Second buffer
00359  * @v second_off        Second buffer offset
00360  * @v len               Length
00361  * @ret diff            Difference
00362  */
00363 int memcmp_user ( userptr_t first, off_t first_off,
00364                   userptr_t second, off_t second_off, size_t len );
00365 
00366 /**
00367  * Fill user buffer with a constant byte
00368  *
00369  * @v userptr           User buffer
00370  * @v offset            Offset within buffer
00371  * @v c                 Constant byte with which to fill
00372  * @v len               Length
00373  */
00374 void memset_user ( userptr_t userptr, off_t offset, int c, size_t len );
00375 
00376 /**
00377  * Find length of NUL-terminated string in user buffer
00378  *
00379  * @v userptr           User buffer
00380  * @v offset            Offset within buffer
00381  * @ret len             Length of string (excluding NUL)
00382  */
00383 size_t strlen_user ( userptr_t userptr, off_t offset );
00384 
00385 /**
00386  * Find character in user buffer
00387  *
00388  * @v userptr           User buffer
00389  * @v offset            Starting offset within buffer
00390  * @v c                 Character to search for
00391  * @v len               Length of user buffer
00392  * @ret offset          Offset of character, or <0 if not found
00393  */
00394 off_t memchr_user ( userptr_t userptr, off_t offset, int c, size_t len );
00395 
00396 #endif /* _IPXE_UACCESS_H */