Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. #ifndef _GPXE_BITOPS_H
  2. #define _GPXE_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., 675 Mass Ave, Cambridge, MA 02139, USA.
  19. */
  20. /**
  21. * @file
  22. *
  23. * Bit operations
  24. *
  25. */
  26. #include <stdint.h>
  27. #include <byteswap.h>
  28. /* Endianness selection.
  29. *
  30. * This is a property of the NIC, not a property of the host CPU.
  31. */
  32. #ifdef BITOPS_LITTLE_ENDIAN
  33. #define cpu_to_BIT64 cpu_to_le64
  34. #define cpu_to_BIT32 cpu_to_le32
  35. #define BIT64_to_cpu le64_to_cpu
  36. #define BIT32_to_cpu le32_to_cpu
  37. #endif
  38. #ifdef BITOPS_BIG_ENDIAN
  39. #define cpu_to_BIT64 cpu_to_be64
  40. #define cpu_to_BIT32 cpu_to_be32
  41. #define BIT64_to_cpu be64_to_cpu
  42. #define BIT32_to_cpu be32_to_cpu
  43. #endif
  44. /** Datatype used to represent a bit in the pseudo-structures */
  45. typedef unsigned char pseudo_bit_t;
  46. /**
  47. * Wrapper structure for pseudo_bit_t structures
  48. *
  49. * This structure provides a wrapper around pseudo_bit_t structures.
  50. * It has the correct size, and also encapsulates type information
  51. * about the underlying pseudo_bit_t-based structure, which allows the
  52. * BIT_FILL() etc. macros to work without requiring explicit type
  53. * information.
  54. */
  55. #define PSEUDO_BIT_STRUCT( _structure ) \
  56. union { \
  57. uint8_t bytes[ sizeof ( _structure ) / 8 ]; \
  58. uint32_t dwords[ sizeof ( _structure ) / 32 ]; \
  59. uint64_t qwords[ sizeof ( _structure ) / 64 ]; \
  60. _structure *dummy[0]; \
  61. } u
  62. /** Get pseudo_bit_t structure type from wrapper structure pointer */
  63. #define PSEUDO_BIT_STRUCT_TYPE( _ptr ) \
  64. typeof ( *((_ptr)->u.dummy[0]) )
  65. /** Bit offset of a field within a pseudo_bit_t structure */
  66. #define BIT_OFFSET( _ptr, _field ) \
  67. offsetof ( PSEUDO_BIT_STRUCT_TYPE ( _ptr ), _field )
  68. /** Bit width of a field within a pseudo_bit_t structure */
  69. #define BIT_WIDTH( _ptr, _field ) \
  70. sizeof ( ( ( PSEUDO_BIT_STRUCT_TYPE ( _ptr ) * ) NULL )->_field )
  71. /** Qword offset of a field within a pseudo_bit_t structure */
  72. #define QWORD_OFFSET( _ptr, _field ) \
  73. ( BIT_OFFSET ( _ptr, _field ) / 64 )
  74. /** Qword bit offset of a field within a pseudo_bit_t structure */
  75. #define QWORD_BIT_OFFSET( _ptr, _index, _field ) \
  76. ( BIT_OFFSET ( _ptr, _field ) - ( 64 * (_index) ) )
  77. /** Bit mask for a field within a pseudo_bit_t structure */
  78. #define BIT_MASK( _ptr, _field ) \
  79. ( ( ~( ( uint64_t ) 0 ) ) >> \
  80. ( 64 - BIT_WIDTH ( _ptr, _field ) ) )
  81. /*
  82. * Assemble native-endian qword from named fields and values
  83. *
  84. */
  85. #define BIT_ASSEMBLE_1( _ptr, _index, _field, _value ) \
  86. ( ( ( uint64_t) (_value) ) << \
  87. QWORD_BIT_OFFSET ( _ptr, _index, _field ) )
  88. #define BIT_ASSEMBLE_2( _ptr, _index, _field, _value, ... ) \
  89. ( BIT_ASSEMBLE_1 ( _ptr, _index, _field, _value ) | \
  90. BIT_ASSEMBLE_1 ( _ptr, _index, __VA_ARGS__ ) )
  91. #define BIT_ASSEMBLE_3( _ptr, _index, _field, _value, ... ) \
  92. ( BIT_ASSEMBLE_1 ( _ptr, _index, _field, _value ) | \
  93. BIT_ASSEMBLE_2 ( _ptr, _index, __VA_ARGS__ ) )
  94. #define BIT_ASSEMBLE_4( _ptr, _index, _field, _value, ... ) \
  95. ( BIT_ASSEMBLE_1 ( _ptr, _index, _field, _value ) | \
  96. BIT_ASSEMBLE_3 ( _ptr, _index, __VA_ARGS__ ) )
  97. #define BIT_ASSEMBLE_5( _ptr, _index, _field, _value, ... ) \
  98. ( BIT_ASSEMBLE_1 ( _ptr, _index, _field, _value ) | \
  99. BIT_ASSEMBLE_4 ( _ptr, _index, __VA_ARGS__ ) )
  100. #define BIT_ASSEMBLE_6( _ptr, _index, _field, _value, ... ) \
  101. ( BIT_ASSEMBLE_1 ( _ptr, _index, _field, _value ) | \
  102. BIT_ASSEMBLE_5 ( _ptr, _index, __VA_ARGS__ ) )
  103. #define BIT_ASSEMBLE_7( _ptr, _index, _field, _value, ... ) \
  104. ( BIT_ASSEMBLE_1 ( _ptr, _index, _field, _value ) | \
  105. BIT_ASSEMBLE_6 ( _ptr, _index, __VA_ARGS__ ) )
  106. /*
  107. * Build native-endian (positive) qword bitmasks from named fields
  108. *
  109. */
  110. #define BIT_MASK_1( _ptr, _index, _field ) \
  111. ( BIT_MASK ( _ptr, _field ) << \
  112. QWORD_BIT_OFFSET ( _ptr, _index, _field ) )
  113. #define BIT_MASK_2( _ptr, _index, _field, ... ) \
  114. ( BIT_MASK_1 ( _ptr, _index, _field ) | \
  115. BIT_MASK_1 ( _ptr, _index, __VA_ARGS__ ) )
  116. #define BIT_MASK_3( _ptr, _index, _field, ... ) \
  117. ( BIT_MASK_1 ( _ptr, _index, _field ) | \
  118. BIT_MASK_2 ( _ptr, _index, __VA_ARGS__ ) )
  119. #define BIT_MASK_4( _ptr, _index, _field, ... ) \
  120. ( BIT_MASK_1 ( _ptr, _index, _field ) | \
  121. BIT_MASK_3 ( _ptr, _index, __VA_ARGS__ ) )
  122. #define BIT_MASK_5( _ptr, _index, _field, ... ) \
  123. ( BIT_MASK_1 ( _ptr, _index, _field ) | \
  124. BIT_MASK_4 ( _ptr, _index, __VA_ARGS__ ) )
  125. #define BIT_MASK_6( _ptr, _index, _field, ... ) \
  126. ( BIT_MASK_1 ( _ptr, _index, _field ) | \
  127. BIT_MASK_5 ( _ptr, _index, __VA_ARGS__ ) )
  128. #define BIT_MASK_7( _ptr, _index, _field, ... ) \
  129. ( BIT_MASK_1 ( _ptr, _index, _field ) | \
  130. BIT_MASK_6 ( _ptr, _index, __VA_ARGS__ ) )
  131. /*
  132. * Populate little-endian qwords from named fields and values
  133. *
  134. */
  135. #define BIT_FILL( _ptr, _index, _assembled ) do { \
  136. uint64_t *__ptr = &(_ptr)->u.qwords[(_index)]; \
  137. uint64_t __assembled = (_assembled); \
  138. *__ptr = cpu_to_BIT64 ( __assembled ); \
  139. } while ( 0 )
  140. #define BIT_FILL_1( _ptr, _field1, ... ) \
  141. BIT_FILL ( _ptr, QWORD_OFFSET ( _ptr, _field1 ), \
  142. BIT_ASSEMBLE_1 ( _ptr, QWORD_OFFSET ( _ptr, _field1 ), \
  143. _field1, __VA_ARGS__ ) )
  144. #define BIT_FILL_2( _ptr, _field1, ... ) \
  145. BIT_FILL ( _ptr, QWORD_OFFSET ( _ptr, _field1 ), \
  146. BIT_ASSEMBLE_2 ( _ptr, QWORD_OFFSET ( _ptr, _field1 ), \
  147. _field1, __VA_ARGS__ ) )
  148. #define BIT_FILL_3( _ptr, _field1, ... ) \
  149. BIT_FILL ( _ptr, QWORD_OFFSET ( _ptr, _field1 ), \
  150. BIT_ASSEMBLE_3 ( _ptr, QWORD_OFFSET ( _ptr, _field1 ), \
  151. _field1, __VA_ARGS__ ) )
  152. #define BIT_FILL_4( _ptr, _field1, ... ) \
  153. BIT_FILL ( _ptr, QWORD_OFFSET ( _ptr, _field1 ), \
  154. BIT_ASSEMBLE_4 ( _ptr, QWORD_OFFSET ( _ptr, _field1 ), \
  155. _field1, __VA_ARGS__ ) )
  156. #define BIT_FILL_5( _ptr, _field1, ... ) \
  157. BIT_FILL ( _ptr, QWORD_OFFSET ( _ptr, _field1 ), \
  158. BIT_ASSEMBLE_5 ( _ptr, QWORD_OFFSET ( _ptr, _field1 ), \
  159. _field1, __VA_ARGS__ ) )
  160. #define BIT_FILL_6( _ptr, _field1, ... ) \
  161. BIT_FILL ( _ptr, QWORD_OFFSET ( _ptr, _field1 ), \
  162. BIT_ASSEMBLE_6 ( _ptr, QWORD_OFFSET ( _ptr, _field1 ), \
  163. _field1, __VA_ARGS__ ) )
  164. /** Extract value of named field */
  165. #define BIT_GET64( _ptr, _field ) \
  166. ( { \
  167. unsigned int __index = QWORD_OFFSET ( _ptr, _field ); \
  168. uint64_t *__ptr = &(_ptr)->u.qwords[__index]; \
  169. uint64_t __value = BIT64_to_cpu ( *__ptr ); \
  170. __value >>= \
  171. QWORD_BIT_OFFSET ( _ptr, __index, _field ); \
  172. __value &= BIT_MASK ( _ptr, _field ); \
  173. __value; \
  174. } )
  175. /** Extract value of named field (for fields up to the size of a long) */
  176. #define BIT_GET( _ptr, _field ) \
  177. ( ( unsigned long ) BIT_GET64 ( _ptr, _field ) )
  178. #define BIT_SET( _ptr, _field, _value ) do { \
  179. unsigned int __index = QWORD_OFFSET ( _ptr, _field ); \
  180. uint64_t *__ptr = &(_ptr)->u.qwords[__index]; \
  181. unsigned int __shift = \
  182. QWORD_BIT_OFFSET ( _ptr, __index, _field ); \
  183. uint64_t __value = (_value); \
  184. *__ptr &= cpu_to_BIT64 ( ~( BIT_MASK ( _ptr, _field ) << \
  185. __shift ) ); \
  186. *__ptr |= cpu_to_BIT64 ( __value << __shift ); \
  187. } while ( 0 )
  188. #endif /* _GPXE_BITOPS_H */