Home | History | Annotate | Download | only in gpxe
      1 #ifndef _GPXE_BITOPS_H
      2 #define _GPXE_BITOPS_H
      3 
      4 /*
      5  * Copyright (C) 2008 Michael Brown <mbrown (at) fensystems.co.uk>.
      6  *
      7  * This program is free software; you can redistribute it and/or
      8  * modify it under the terms of the GNU General Public License as
      9  * published by the Free Software Foundation; either version 2 of the
     10  * License, or any later version.
     11  *
     12  * This program is distributed in the hope that it will be useful, but
     13  * WITHOUT ANY WARRANTY; without even the implied warranty of
     14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     15  * General Public License for more details.
     16  *
     17  * You should have received a copy of the GNU General Public License
     18  * along with this program; if not, write to the Free Software
     19  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
     20  */
     21 
     22 FILE_LICENCE ( GPL2_OR_LATER );
     23 
     24 /**
     25  * @file
     26  *
     27  * Bit operations
     28  *
     29  */
     30 
     31 #include <stdint.h>
     32 #include <byteswap.h>
     33 
     34 /* Endianness selection.
     35  *
     36  * This is a property of the NIC, not a property of the host CPU.
     37  */
     38 #ifdef BITOPS_LITTLE_ENDIAN
     39 #define cpu_to_BIT64	cpu_to_le64
     40 #define cpu_to_BIT32	cpu_to_le32
     41 #define BIT64_to_cpu	le64_to_cpu
     42 #define BIT32_to_cpu	le32_to_cpu
     43 #endif
     44 #ifdef BITOPS_BIG_ENDIAN
     45 #define cpu_to_BIT64	cpu_to_be64
     46 #define cpu_to_BIT32	cpu_to_be32
     47 #define BIT64_to_cpu	be64_to_cpu
     48 #define BIT32_to_cpu	be32_to_cpu
     49 #endif
     50 
     51 /** Datatype used to represent a bit in the pseudo-structures */
     52 typedef unsigned char pseudo_bit_t;
     53 
     54 /**
     55  * Wrapper structure for pseudo_bit_t structures
     56  *
     57  * This structure provides a wrapper around pseudo_bit_t structures.
     58  * It has the correct size, and also encapsulates type information
     59  * about the underlying pseudo_bit_t-based structure, which allows the
     60  * BIT_FILL() etc. macros to work without requiring explicit type
     61  * information.
     62  */
     63 #define PSEUDO_BIT_STRUCT( _structure )					      \
     64 	union {								      \
     65 		uint8_t bytes[ sizeof ( _structure ) / 8 ];		      \
     66 		uint32_t dwords[ sizeof ( _structure ) / 32 ];		      \
     67 		uint64_t qwords[ sizeof ( _structure ) / 64 ];		      \
     68 		_structure *dummy[0];					      \
     69 	} u
     70 
     71 /** Get pseudo_bit_t structure type from wrapper structure pointer */
     72 #define PSEUDO_BIT_STRUCT_TYPE( _ptr )					      \
     73 	typeof ( *((_ptr)->u.dummy[0]) )
     74 
     75 /** Bit offset of a field within a pseudo_bit_t structure */
     76 #define BIT_OFFSET( _ptr, _field )					      \
     77 	offsetof ( PSEUDO_BIT_STRUCT_TYPE ( _ptr ), _field )
     78 
     79 /** Bit width of a field within a pseudo_bit_t structure */
     80 #define BIT_WIDTH( _ptr, _field )					      \
     81 	sizeof ( ( ( PSEUDO_BIT_STRUCT_TYPE ( _ptr ) * ) NULL )->_field )
     82 
     83 /** Qword offset of a field within a pseudo_bit_t structure */
     84 #define QWORD_OFFSET( _ptr, _field )					      \
     85 	( BIT_OFFSET ( _ptr, _field ) / 64 )
     86 
     87 /** Qword bit offset of a field within a pseudo_bit_t structure */
     88 #define QWORD_BIT_OFFSET( _ptr, _index, _field )			      \
     89 	( BIT_OFFSET ( _ptr, _field ) - ( 64 * (_index) ) )
     90 
     91 /** Bit mask for a field within a pseudo_bit_t structure */
     92 #define BIT_MASK( _ptr, _field )					      \
     93 	( ( ~( ( uint64_t ) 0 ) ) >>					      \
     94 	  ( 64 - BIT_WIDTH ( _ptr, _field ) ) )
     95 
     96 /*
     97  * Assemble native-endian qword from named fields and values
     98  *
     99  */
    100 
    101 #define BIT_ASSEMBLE_1( _ptr, _index, _field, _value )			      \
    102 	( ( ( uint64_t) (_value) ) <<					      \
    103 	  QWORD_BIT_OFFSET ( _ptr, _index, _field ) )
    104 
    105 #define BIT_ASSEMBLE_2( _ptr, _index, _field, _value, ... )		      \
    106 	( BIT_ASSEMBLE_1 ( _ptr, _index, _field, _value ) |		      \
    107 	  BIT_ASSEMBLE_1 ( _ptr, _index, __VA_ARGS__ ) )
    108 
    109 #define BIT_ASSEMBLE_3( _ptr, _index, _field, _value, ... )		      \
    110 	( BIT_ASSEMBLE_1 ( _ptr, _index, _field, _value ) |		      \
    111 	  BIT_ASSEMBLE_2 ( _ptr, _index, __VA_ARGS__ ) )
    112 
    113 #define BIT_ASSEMBLE_4( _ptr, _index, _field, _value, ... )		      \
    114 	( BIT_ASSEMBLE_1 ( _ptr, _index, _field, _value ) |		      \
    115 	  BIT_ASSEMBLE_3 ( _ptr, _index, __VA_ARGS__ ) )
    116 
    117 #define BIT_ASSEMBLE_5( _ptr, _index, _field, _value, ... )		      \
    118 	( BIT_ASSEMBLE_1 ( _ptr, _index, _field, _value ) |		      \
    119 	  BIT_ASSEMBLE_4 ( _ptr, _index, __VA_ARGS__ ) )
    120 
    121 #define BIT_ASSEMBLE_6( _ptr, _index, _field, _value, ... )		      \
    122 	( BIT_ASSEMBLE_1 ( _ptr, _index, _field, _value ) |		      \
    123 	  BIT_ASSEMBLE_5 ( _ptr, _index, __VA_ARGS__ ) )
    124 
    125 #define BIT_ASSEMBLE_7( _ptr, _index, _field, _value, ... )		      \
    126 	( BIT_ASSEMBLE_1 ( _ptr, _index, _field, _value ) |		      \
    127 	  BIT_ASSEMBLE_6 ( _ptr, _index, __VA_ARGS__ ) )
    128 
    129 /*
    130  * Build native-endian (positive) qword bitmasks from named fields
    131  *
    132  */
    133 
    134 #define BIT_MASK_1( _ptr, _index, _field )				      \
    135 	( BIT_MASK ( _ptr, _field ) <<					      \
    136 	  QWORD_BIT_OFFSET ( _ptr, _index, _field ) )
    137 
    138 #define BIT_MASK_2( _ptr, _index, _field, ... )				      \
    139 	( BIT_MASK_1 ( _ptr, _index, _field ) |				      \
    140 	  BIT_MASK_1 ( _ptr, _index, __VA_ARGS__ ) )
    141 
    142 #define BIT_MASK_3( _ptr, _index, _field, ... )				      \
    143 	( BIT_MASK_1 ( _ptr, _index, _field ) |				      \
    144 	  BIT_MASK_2 ( _ptr, _index, __VA_ARGS__ ) )
    145 
    146 #define BIT_MASK_4( _ptr, _index, _field, ... )				      \
    147 	( BIT_MASK_1 ( _ptr, _index, _field ) |				      \
    148 	  BIT_MASK_3 ( _ptr, _index, __VA_ARGS__ ) )
    149 
    150 #define BIT_MASK_5( _ptr, _index, _field, ... )				      \
    151 	( BIT_MASK_1 ( _ptr, _index, _field ) |				      \
    152 	  BIT_MASK_4 ( _ptr, _index, __VA_ARGS__ ) )
    153 
    154 #define BIT_MASK_6( _ptr, _index, _field, ... )				      \
    155 	( BIT_MASK_1 ( _ptr, _index, _field ) |				      \
    156 	  BIT_MASK_5 ( _ptr, _index, __VA_ARGS__ ) )
    157 
    158 #define BIT_MASK_7( _ptr, _index, _field, ... )				      \
    159 	( BIT_MASK_1 ( _ptr, _index, _field ) |				      \
    160 	  BIT_MASK_6 ( _ptr, _index, __VA_ARGS__ ) )
    161 
    162 /*
    163  * Populate little-endian qwords from named fields and values
    164  *
    165  */
    166 
    167 #define BIT_FILL( _ptr, _index, _assembled ) do {			      \
    168 		uint64_t *__ptr = &(_ptr)->u.qwords[(_index)];		      \
    169 		uint64_t __assembled = (_assembled);			      \
    170 		*__ptr = cpu_to_BIT64 ( __assembled );			      \
    171 	} while ( 0 )
    172 
    173 #define BIT_FILL_1( _ptr, _field1, ... )				      \
    174 	BIT_FILL ( _ptr, QWORD_OFFSET ( _ptr, _field1 ),		      \
    175 		   BIT_ASSEMBLE_1 ( _ptr, QWORD_OFFSET ( _ptr, _field1 ),     \
    176 				    _field1, __VA_ARGS__ ) )
    177 
    178 #define BIT_FILL_2( _ptr, _field1, ... )				      \
    179 	BIT_FILL ( _ptr, QWORD_OFFSET ( _ptr, _field1 ),		      \
    180 		   BIT_ASSEMBLE_2 ( _ptr, QWORD_OFFSET ( _ptr, _field1 ),     \
    181 				    _field1, __VA_ARGS__ ) )
    182 
    183 #define BIT_FILL_3( _ptr, _field1, ... )				      \
    184 	BIT_FILL ( _ptr, QWORD_OFFSET ( _ptr, _field1 ),		      \
    185 		   BIT_ASSEMBLE_3 ( _ptr, QWORD_OFFSET ( _ptr, _field1 ),     \
    186 				    _field1, __VA_ARGS__ ) )
    187 
    188 #define BIT_FILL_4( _ptr, _field1, ... )				      \
    189 	BIT_FILL ( _ptr, QWORD_OFFSET ( _ptr, _field1 ),		      \
    190 		   BIT_ASSEMBLE_4 ( _ptr, QWORD_OFFSET ( _ptr, _field1 ),     \
    191 				    _field1, __VA_ARGS__ ) )
    192 
    193 #define BIT_FILL_5( _ptr, _field1, ... )				      \
    194 	BIT_FILL ( _ptr, QWORD_OFFSET ( _ptr, _field1 ),		      \
    195 		   BIT_ASSEMBLE_5 ( _ptr, QWORD_OFFSET ( _ptr, _field1 ),     \
    196 				    _field1, __VA_ARGS__ ) )
    197 
    198 #define BIT_FILL_6( _ptr, _field1, ... )				      \
    199 	BIT_FILL ( _ptr, QWORD_OFFSET ( _ptr, _field1 ),		      \
    200 		   BIT_ASSEMBLE_6 ( _ptr, QWORD_OFFSET ( _ptr, _field1 ),     \
    201 				    _field1, __VA_ARGS__ ) )
    202 
    203 /** Extract value of named field */
    204 #define BIT_GET64( _ptr, _field )					      \
    205 	( {								      \
    206 		unsigned int __index = QWORD_OFFSET ( _ptr, _field );	      \
    207 		uint64_t *__ptr = &(_ptr)->u.qwords[__index];		      \
    208 		uint64_t __value = BIT64_to_cpu ( *__ptr );		      \
    209 		__value >>=						      \
    210 		    QWORD_BIT_OFFSET ( _ptr, __index, _field );		      \
    211 		__value &= BIT_MASK ( _ptr, _field );			      \
    212 		__value;						      \
    213 	} )
    214 
    215 /** Extract value of named field (for fields up to the size of a long) */
    216 #define BIT_GET( _ptr, _field )						      \
    217 	( ( unsigned long ) BIT_GET64 ( _ptr, _field ) )
    218 
    219 #define BIT_SET( _ptr, _field, _value ) do {				      \
    220 		unsigned int __index = QWORD_OFFSET ( _ptr, _field );	      \
    221 		uint64_t *__ptr = &(_ptr)->u.qwords[__index];		      \
    222 		unsigned int __shift =					      \
    223 			QWORD_BIT_OFFSET ( _ptr, __index, _field );	      \
    224 		uint64_t __value = (_value);				      \
    225 		*__ptr &= cpu_to_BIT64 ( ~( BIT_MASK ( _ptr, _field ) <<      \
    226 					    __shift ) );		      \
    227 		*__ptr |= cpu_to_BIT64 ( __value << __shift );		      \
    228 	} while ( 0 )
    229 
    230 #endif /* _GPXE_BITOPS_H */
    231