1#ifndef _GPXE_BITOPS_H
2#define _GPXE_BITOPS_H
3
4/*
5 * Copyright (C) 2008 Michael Brown <mbrown@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
22FILE_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 */
52typedef 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