iPXE
pseudobit.h
Go to the documentation of this file.
00001 #ifndef _IPXE_PSEUDOBIT_H
00002 #define _IPXE_PSEUDOBIT_H
00003 
00004 /*
00005  * Copyright (C) 2008 Michael Brown <mbrown@fensystems.co.uk>.
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License as
00009  * published by the Free Software Foundation; either version 2 of the
00010  * License, or any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful, but
00013  * WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00020  * 02110-1301, USA.
00021  *
00022  * You can also choose to distribute this program under the terms of
00023  * the Unmodified Binary Distribution Licence (as given in the file
00024  * COPYING.UBDL), provided that you have satisfied its requirements.
00025  */
00026 
00027 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
00028 
00029 /**
00030  * @file
00031  *
00032  * Pseudo-bit structures
00033  *
00034  */
00035 
00036 #include <stdint.h>
00037 #include <byteswap.h>
00038 
00039 /* Endianness selection.
00040  *
00041  * This is a property of the device, not a property of the host CPU.
00042  */
00043 #ifdef PSEUDOBIT_LITTLE_ENDIAN
00044 #define cpu_to_BIT64    cpu_to_le64
00045 #define cpu_to_BIT32    cpu_to_le32
00046 #define BIT64_to_cpu    le64_to_cpu
00047 #define BIT32_to_cpu    le32_to_cpu
00048 #define QWORD_SHIFT( offset, width ) (offset)
00049 #endif
00050 #ifdef PSEUDOBIT_BIG_ENDIAN
00051 #define cpu_to_BIT64    cpu_to_be64
00052 #define cpu_to_BIT32    cpu_to_be32
00053 #define BIT64_to_cpu    be64_to_cpu
00054 #define BIT32_to_cpu    be32_to_cpu
00055 #define QWORD_SHIFT( offset, width ) ( 64 - (offset) - (width) )
00056 #endif
00057 
00058 /** Datatype used to represent a bit in the pseudo-structures */
00059 typedef unsigned char pseudo_bit_t;
00060 
00061 /**
00062  * Wrapper structure for pseudo_bit_t structures
00063  *
00064  * This structure provides a wrapper around pseudo_bit_t structures.
00065  * It has the correct size, and also encapsulates type information
00066  * about the underlying pseudo_bit_t-based structure, which allows the
00067  * BIT_FILL() etc. macros to work without requiring explicit type
00068  * information.
00069  */
00070 #define PSEUDO_BIT_STRUCT( _structure )                                       \
00071         union {                                                               \
00072                 uint8_t bytes[ sizeof ( _structure ) / 8 ];                   \
00073                 uint32_t dwords[ sizeof ( _structure ) / 32 ];                \
00074                 uint64_t qwords[ sizeof ( _structure ) / 64 ];                \
00075                 _structure *dummy[0];                                         \
00076         } __attribute__ (( packed )) u
00077 
00078 /** Get pseudo_bit_t structure type from wrapper structure pointer */
00079 #define PSEUDO_BIT_STRUCT_TYPE( _ptr )                                        \
00080         typeof ( *((_ptr)->u.dummy[0]) )
00081 
00082 /** Bit offset of a field within a pseudo_bit_t structure */
00083 #define BIT_OFFSET( _ptr, _field )                                            \
00084         offsetof ( PSEUDO_BIT_STRUCT_TYPE ( _ptr ), _field )
00085 
00086 /** Bit width of a field within a pseudo_bit_t structure */
00087 #define BIT_WIDTH( _ptr, _field )                                             \
00088         sizeof ( ( ( PSEUDO_BIT_STRUCT_TYPE ( _ptr ) * ) NULL )->_field )
00089 
00090 /** Qword offset of a field within a pseudo_bit_t structure */
00091 #define QWORD_OFFSET( _ptr, _field )                                          \
00092         ( BIT_OFFSET ( _ptr, _field ) / 64 )
00093 
00094 /** Qword bit offset of a field within a pseudo_bit_t structure */
00095 #define QWORD_BIT_OFFSET( _ptr, _index, _field )                              \
00096         ( BIT_OFFSET ( _ptr, _field ) - ( 64 * (_index) ) )
00097 
00098 /** Qword bit shift for a field within a pseudo_bit_t structure */
00099 #define QWORD_BIT_SHIFT( _ptr, _index, _field )                               \
00100         QWORD_SHIFT ( QWORD_BIT_OFFSET ( _ptr, _index, _field ),              \
00101                       BIT_WIDTH ( _ptr, _field ) )
00102 
00103 /** Bit mask for a field within a pseudo_bit_t structure */
00104 #define BIT_MASK( _ptr, _field )                                              \
00105         ( ( ~( ( uint64_t ) 0 ) ) >>                                          \
00106           ( 64 - BIT_WIDTH ( _ptr, _field ) ) )
00107 
00108 /*
00109  * Assemble native-endian qword from named fields and values
00110  *
00111  */
00112 
00113 #define BIT_ASSEMBLE_1( _ptr, _index, _field, _value )                        \
00114         ( ( ( uint64_t) (_value) ) <<                                         \
00115           QWORD_BIT_SHIFT ( _ptr, _index, _field ) )
00116 
00117 #define BIT_ASSEMBLE_2( _ptr, _index, _field, _value, ... )                   \
00118         ( BIT_ASSEMBLE_1 ( _ptr, _index, _field, _value ) |                   \
00119           BIT_ASSEMBLE_1 ( _ptr, _index, __VA_ARGS__ ) )
00120 
00121 #define BIT_ASSEMBLE_3( _ptr, _index, _field, _value, ... )                   \
00122         ( BIT_ASSEMBLE_1 ( _ptr, _index, _field, _value ) |                   \
00123           BIT_ASSEMBLE_2 ( _ptr, _index, __VA_ARGS__ ) )
00124 
00125 #define BIT_ASSEMBLE_4( _ptr, _index, _field, _value, ... )                   \
00126         ( BIT_ASSEMBLE_1 ( _ptr, _index, _field, _value ) |                   \
00127           BIT_ASSEMBLE_3 ( _ptr, _index, __VA_ARGS__ ) )
00128 
00129 #define BIT_ASSEMBLE_5( _ptr, _index, _field, _value, ... )                   \
00130         ( BIT_ASSEMBLE_1 ( _ptr, _index, _field, _value ) |                   \
00131           BIT_ASSEMBLE_4 ( _ptr, _index, __VA_ARGS__ ) )
00132 
00133 #define BIT_ASSEMBLE_6( _ptr, _index, _field, _value, ... )                   \
00134         ( BIT_ASSEMBLE_1 ( _ptr, _index, _field, _value ) |                   \
00135           BIT_ASSEMBLE_5 ( _ptr, _index, __VA_ARGS__ ) )
00136 
00137 #define BIT_ASSEMBLE_7( _ptr, _index, _field, _value, ... )                   \
00138         ( BIT_ASSEMBLE_1 ( _ptr, _index, _field, _value ) |                   \
00139           BIT_ASSEMBLE_6 ( _ptr, _index, __VA_ARGS__ ) )
00140 
00141 /*
00142  * Build native-endian (positive) qword bitmasks from named fields
00143  *
00144  */
00145 
00146 #define BIT_MASK_1( _ptr, _index, _field )                                    \
00147         ( BIT_MASK ( _ptr, _field ) <<                                        \
00148           QWORD_BIT_SHIFT ( _ptr, _index, _field ) )
00149 
00150 #define BIT_MASK_2( _ptr, _index, _field, ... )                               \
00151         ( BIT_MASK_1 ( _ptr, _index, _field ) |                               \
00152           BIT_MASK_1 ( _ptr, _index, __VA_ARGS__ ) )
00153 
00154 #define BIT_MASK_3( _ptr, _index, _field, ... )                               \
00155         ( BIT_MASK_1 ( _ptr, _index, _field ) |                               \
00156           BIT_MASK_2 ( _ptr, _index, __VA_ARGS__ ) )
00157 
00158 #define BIT_MASK_4( _ptr, _index, _field, ... )                               \
00159         ( BIT_MASK_1 ( _ptr, _index, _field ) |                               \
00160           BIT_MASK_3 ( _ptr, _index, __VA_ARGS__ ) )
00161 
00162 #define BIT_MASK_5( _ptr, _index, _field, ... )                               \
00163         ( BIT_MASK_1 ( _ptr, _index, _field ) |                               \
00164           BIT_MASK_4 ( _ptr, _index, __VA_ARGS__ ) )
00165 
00166 #define BIT_MASK_6( _ptr, _index, _field, ... )                               \
00167         ( BIT_MASK_1 ( _ptr, _index, _field ) |                               \
00168           BIT_MASK_5 ( _ptr, _index, __VA_ARGS__ ) )
00169 
00170 #define BIT_MASK_7( _ptr, _index, _field, ... )                               \
00171         ( BIT_MASK_1 ( _ptr, _index, _field ) |                               \
00172           BIT_MASK_6 ( _ptr, _index, __VA_ARGS__ ) )
00173 
00174 /*
00175  * Populate device-endian qwords from named fields and values
00176  *
00177  */
00178 
00179 #define BIT_FILL( _ptr, _index, _assembled ) do {                             \
00180                 uint64_t *__ptr = &(_ptr)->u.qwords[(_index)];                \
00181                 uint64_t __assembled = (_assembled);                          \
00182                 *__ptr = cpu_to_BIT64 ( __assembled );                        \
00183         } while ( 0 )
00184 
00185 #define BIT_FILL_1( _ptr, _field1, ... )                                      \
00186         BIT_FILL ( _ptr, QWORD_OFFSET ( _ptr, _field1 ),                      \
00187                    BIT_ASSEMBLE_1 ( _ptr, QWORD_OFFSET ( _ptr, _field1 ),     \
00188                                     _field1, __VA_ARGS__ ) )
00189 
00190 #define BIT_FILL_2( _ptr, _field1, ... )                                      \
00191         BIT_FILL ( _ptr, QWORD_OFFSET ( _ptr, _field1 ),                      \
00192                    BIT_ASSEMBLE_2 ( _ptr, QWORD_OFFSET ( _ptr, _field1 ),     \
00193                                     _field1, __VA_ARGS__ ) )
00194 
00195 #define BIT_FILL_3( _ptr, _field1, ... )                                      \
00196         BIT_FILL ( _ptr, QWORD_OFFSET ( _ptr, _field1 ),                      \
00197                    BIT_ASSEMBLE_3 ( _ptr, QWORD_OFFSET ( _ptr, _field1 ),     \
00198                                     _field1, __VA_ARGS__ ) )
00199 
00200 #define BIT_FILL_4( _ptr, _field1, ... )                                      \
00201         BIT_FILL ( _ptr, QWORD_OFFSET ( _ptr, _field1 ),                      \
00202                    BIT_ASSEMBLE_4 ( _ptr, QWORD_OFFSET ( _ptr, _field1 ),     \
00203                                     _field1, __VA_ARGS__ ) )
00204 
00205 #define BIT_FILL_5( _ptr, _field1, ... )                                      \
00206         BIT_FILL ( _ptr, QWORD_OFFSET ( _ptr, _field1 ),                      \
00207                    BIT_ASSEMBLE_5 ( _ptr, QWORD_OFFSET ( _ptr, _field1 ),     \
00208                                     _field1, __VA_ARGS__ ) )
00209 
00210 #define BIT_FILL_6( _ptr, _field1, ... )                                      \
00211         BIT_FILL ( _ptr, QWORD_OFFSET ( _ptr, _field1 ),                      \
00212                    BIT_ASSEMBLE_6 ( _ptr, QWORD_OFFSET ( _ptr, _field1 ),     \
00213                                     _field1, __VA_ARGS__ ) )
00214 
00215 #define BIT_QWORD_PTR( _ptr, _field )                                         \
00216         ( {                                                                   \
00217                 unsigned int __index = QWORD_OFFSET ( _ptr, _field );         \
00218                 uint64_t *__ptr = &(_ptr)->u.qwords[__index];                 \
00219                 __ptr;                                                        \
00220         } )
00221 
00222 /** Extract value of named field */
00223 #define BIT_GET64( _ptr, _field )                                             \
00224         ( {                                                                   \
00225                 unsigned int __index = QWORD_OFFSET ( _ptr, _field );         \
00226                 uint64_t *__ptr = &(_ptr)->u.qwords[__index];                 \
00227                 uint64_t __value = BIT64_to_cpu ( *__ptr );                   \
00228                 __value >>=                                                   \
00229                     QWORD_BIT_SHIFT ( _ptr, __index, _field );                \
00230                 __value &= BIT_MASK ( _ptr, _field );                         \
00231                 __value;                                                      \
00232         } )
00233 
00234 /** Extract value of named field (for fields up to the size of a long) */
00235 #define BIT_GET( _ptr, _field )                                               \
00236         ( ( unsigned long ) BIT_GET64 ( _ptr, _field ) )
00237 
00238 #define BIT_SET( _ptr, _field, _value ) do {                                  \
00239                 unsigned int __index = QWORD_OFFSET ( _ptr, _field );         \
00240                 uint64_t *__ptr = &(_ptr)->u.qwords[__index];                 \
00241                 unsigned int __shift =                                        \
00242                         QWORD_BIT_SHIFT ( _ptr, __index, _field );            \
00243                 uint64_t __value = (_value);                                  \
00244                 *__ptr &= cpu_to_BIT64 ( ~( BIT_MASK ( _ptr, _field ) <<      \
00245                                             __shift ) );                      \
00246                 *__ptr |= cpu_to_BIT64 ( __value << __shift );                \
00247         } while ( 0 )
00248 
00249 #endif /* _IPXE_PSEUDOBIT_H */