You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

bitops.h 8.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. #ifndef _IPXE_BITOPS_H
  2. #define _IPXE_BITOPS_H
  3. /*
  4. * Copyright (C) 2008 Michael Brown <mbrown@fensystems.co.uk>.
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public License as
  8. * published by the Free Software Foundation; either version 2 of the
  9. * License, or any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful, but
  12. * WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, write to the Free Software
  18. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  19. * 02110-1301, USA.
  20. *
  21. * You can also choose to distribute this program under the terms of
  22. * the Unmodified Binary Distribution Licence (as given in the file
  23. * COPYING.UBDL), provided that you have satisfied its requirements.
  24. */
  25. FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
  26. /**
  27. * @file
  28. *
  29. * Bit operations
  30. *
  31. */
  32. #include <stdint.h>
  33. #include <byteswap.h>
  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. /** Datatype used to represent a bit in the pseudo-structures */
  51. typedef unsigned char pseudo_bit_t;
  52. /**
  53. * Wrapper structure for pseudo_bit_t structures
  54. *
  55. * This structure provides a wrapper around pseudo_bit_t structures.
  56. * It has the correct size, and also encapsulates type information
  57. * about the underlying pseudo_bit_t-based structure, which allows the
  58. * BIT_FILL() etc. macros to work without requiring explicit type
  59. * information.
  60. */
  61. #define PSEUDO_BIT_STRUCT( _structure ) \
  62. union { \
  63. uint8_t bytes[ sizeof ( _structure ) / 8 ]; \
  64. uint32_t dwords[ sizeof ( _structure ) / 32 ]; \
  65. uint64_t qwords[ sizeof ( _structure ) / 64 ]; \
  66. _structure *dummy[0]; \
  67. } __attribute__ (( packed )) u
  68. /** Get pseudo_bit_t structure type from wrapper structure pointer */
  69. #define PSEUDO_BIT_STRUCT_TYPE( _ptr ) \
  70. typeof ( *((_ptr)->u.dummy[0]) )
  71. /** Bit offset of a field within a pseudo_bit_t structure */
  72. #define BIT_OFFSET( _ptr, _field ) \
  73. offsetof ( PSEUDO_BIT_STRUCT_TYPE ( _ptr ), _field )
  74. /** Bit width of a field within a pseudo_bit_t structure */
  75. #define BIT_WIDTH( _ptr, _field ) \
  76. sizeof ( ( ( PSEUDO_BIT_STRUCT_TYPE ( _ptr ) * ) NULL )->_field )
  77. /** Qword offset of a field within a pseudo_bit_t structure */
  78. #define QWORD_OFFSET( _ptr, _field ) \
  79. ( BIT_OFFSET ( _ptr, _field ) / 64 )
  80. /** Qword bit offset of a field within a pseudo_bit_t structure */
  81. #define QWORD_BIT_OFFSET( _ptr, _index, _field ) \
  82. ( BIT_OFFSET ( _ptr, _field ) - ( 64 * (_index) ) )
  83. /** Bit mask for a field within a pseudo_bit_t structure */
  84. #define BIT_MASK( _ptr, _field ) \
  85. ( ( ~( ( uint64_t ) 0 ) ) >> \
  86. ( 64 - BIT_WIDTH ( _ptr, _field ) ) )
  87. /*
  88. * Assemble native-endian qword from named fields and values
  89. *
  90. */
  91. #define BIT_ASSEMBLE_1( _ptr, _index, _field, _value ) \
  92. ( ( ( uint64_t) (_value) ) << \
  93. QWORD_BIT_OFFSET ( _ptr, _index, _field ) )
  94. #define BIT_ASSEMBLE_2( _ptr, _index, _field, _value, ... ) \
  95. ( BIT_ASSEMBLE_1 ( _ptr, _index, _field, _value ) | \
  96. BIT_ASSEMBLE_1 ( _ptr, _index, __VA_ARGS__ ) )
  97. #define BIT_ASSEMBLE_3( _ptr, _index, _field, _value, ... ) \
  98. ( BIT_ASSEMBLE_1 ( _ptr, _index, _field, _value ) | \
  99. BIT_ASSEMBLE_2 ( _ptr, _index, __VA_ARGS__ ) )
  100. #define BIT_ASSEMBLE_4( _ptr, _index, _field, _value, ... ) \
  101. ( BIT_ASSEMBLE_1 ( _ptr, _index, _field, _value ) | \
  102. BIT_ASSEMBLE_3 ( _ptr, _index, __VA_ARGS__ ) )
  103. #define BIT_ASSEMBLE_5( _ptr, _index, _field, _value, ... ) \
  104. ( BIT_ASSEMBLE_1 ( _ptr, _index, _field, _value ) | \
  105. BIT_ASSEMBLE_4 ( _ptr, _index, __VA_ARGS__ ) )
  106. #define BIT_ASSEMBLE_6( _ptr, _index, _field, _value, ... ) \
  107. ( BIT_ASSEMBLE_1 ( _ptr, _index, _field, _value ) | \
  108. BIT_ASSEMBLE_5 ( _ptr, _index, __VA_ARGS__ ) )
  109. #define BIT_ASSEMBLE_7( _ptr, _index, _field, _value, ... ) \
  110. ( BIT_ASSEMBLE_1 ( _ptr, _index, _field, _value ) | \
  111. BIT_ASSEMBLE_6 ( _ptr, _index, __VA_ARGS__ ) )
  112. /*
  113. * Build native-endian (positive) qword bitmasks from named fields
  114. *
  115. */
  116. #define BIT_MASK_1( _ptr, _index, _field ) \
  117. ( BIT_MASK ( _ptr, _field ) << \
  118. QWORD_BIT_OFFSET ( _ptr, _index, _field ) )
  119. #define BIT_MASK_2( _ptr, _index, _field, ... ) \
  120. ( BIT_MASK_1 ( _ptr, _index, _field ) | \
  121. BIT_MASK_1 ( _ptr, _index, __VA_ARGS__ ) )
  122. #define BIT_MASK_3( _ptr, _index, _field, ... ) \
  123. ( BIT_MASK_1 ( _ptr, _index, _field ) | \
  124. BIT_MASK_2 ( _ptr, _index, __VA_ARGS__ ) )
  125. #define BIT_MASK_4( _ptr, _index, _field, ... ) \
  126. ( BIT_MASK_1 ( _ptr, _index, _field ) | \
  127. BIT_MASK_3 ( _ptr, _index, __VA_ARGS__ ) )
  128. #define BIT_MASK_5( _ptr, _index, _field, ... ) \
  129. ( BIT_MASK_1 ( _ptr, _index, _field ) | \
  130. BIT_MASK_4 ( _ptr, _index, __VA_ARGS__ ) )
  131. #define BIT_MASK_6( _ptr, _index, _field, ... ) \
  132. ( BIT_MASK_1 ( _ptr, _index, _field ) | \
  133. BIT_MASK_5 ( _ptr, _index, __VA_ARGS__ ) )
  134. #define BIT_MASK_7( _ptr, _index, _field, ... ) \
  135. ( BIT_MASK_1 ( _ptr, _index, _field ) | \
  136. BIT_MASK_6 ( _ptr, _index, __VA_ARGS__ ) )
  137. /*
  138. * Populate little-endian qwords from named fields and values
  139. *
  140. */
  141. #define BIT_FILL( _ptr, _index, _assembled ) do { \
  142. uint64_t *__ptr = &(_ptr)->u.qwords[(_index)]; \
  143. uint64_t __assembled = (_assembled); \
  144. *__ptr = cpu_to_BIT64 ( __assembled ); \
  145. } while ( 0 )
  146. #define BIT_FILL_1( _ptr, _field1, ... ) \
  147. BIT_FILL ( _ptr, QWORD_OFFSET ( _ptr, _field1 ), \
  148. BIT_ASSEMBLE_1 ( _ptr, QWORD_OFFSET ( _ptr, _field1 ), \
  149. _field1, __VA_ARGS__ ) )
  150. #define BIT_FILL_2( _ptr, _field1, ... ) \
  151. BIT_FILL ( _ptr, QWORD_OFFSET ( _ptr, _field1 ), \
  152. BIT_ASSEMBLE_2 ( _ptr, QWORD_OFFSET ( _ptr, _field1 ), \
  153. _field1, __VA_ARGS__ ) )
  154. #define BIT_FILL_3( _ptr, _field1, ... ) \
  155. BIT_FILL ( _ptr, QWORD_OFFSET ( _ptr, _field1 ), \
  156. BIT_ASSEMBLE_3 ( _ptr, QWORD_OFFSET ( _ptr, _field1 ), \
  157. _field1, __VA_ARGS__ ) )
  158. #define BIT_FILL_4( _ptr, _field1, ... ) \
  159. BIT_FILL ( _ptr, QWORD_OFFSET ( _ptr, _field1 ), \
  160. BIT_ASSEMBLE_4 ( _ptr, QWORD_OFFSET ( _ptr, _field1 ), \
  161. _field1, __VA_ARGS__ ) )
  162. #define BIT_FILL_5( _ptr, _field1, ... ) \
  163. BIT_FILL ( _ptr, QWORD_OFFSET ( _ptr, _field1 ), \
  164. BIT_ASSEMBLE_5 ( _ptr, QWORD_OFFSET ( _ptr, _field1 ), \
  165. _field1, __VA_ARGS__ ) )
  166. #define BIT_FILL_6( _ptr, _field1, ... ) \
  167. BIT_FILL ( _ptr, QWORD_OFFSET ( _ptr, _field1 ), \
  168. BIT_ASSEMBLE_6 ( _ptr, QWORD_OFFSET ( _ptr, _field1 ), \
  169. _field1, __VA_ARGS__ ) )
  170. /** Extract value of named field */
  171. #define BIT_GET64( _ptr, _field ) \
  172. ( { \
  173. unsigned int __index = QWORD_OFFSET ( _ptr, _field ); \
  174. uint64_t *__ptr = &(_ptr)->u.qwords[__index]; \
  175. uint64_t __value = BIT64_to_cpu ( *__ptr ); \
  176. __value >>= \
  177. QWORD_BIT_OFFSET ( _ptr, __index, _field ); \
  178. __value &= BIT_MASK ( _ptr, _field ); \
  179. __value; \
  180. } )
  181. /** Extract value of named field (for fields up to the size of a long) */
  182. #define BIT_GET( _ptr, _field ) \
  183. ( ( unsigned long ) BIT_GET64 ( _ptr, _field ) )
  184. #define BIT_SET( _ptr, _field, _value ) do { \
  185. unsigned int __index = QWORD_OFFSET ( _ptr, _field ); \
  186. uint64_t *__ptr = &(_ptr)->u.qwords[__index]; \
  187. unsigned int __shift = \
  188. QWORD_BIT_OFFSET ( _ptr, __index, _field ); \
  189. uint64_t __value = (_value); \
  190. *__ptr &= cpu_to_BIT64 ( ~( BIT_MASK ( _ptr, _field ) << \
  191. __shift ) ); \
  192. *__ptr |= cpu_to_BIT64 ( __value << __shift ); \
  193. } while ( 0 )
  194. #endif /* _IPXE_BITOPS_H */