Home | History | Annotate | Download | only in gpxe
      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