iPXE
pseudobit.h
Go to the documentation of this file.
1#ifndef _IPXE_PSEUDOBIT_H
2#define _IPXE_PSEUDOBIT_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., 51 Franklin Street, Fifth Floor, Boston, MA
20 * 02110-1301, USA.
21 *
22 * You can also choose to distribute this program under the terms of
23 * the Unmodified Binary Distribution Licence (as given in the file
24 * COPYING.UBDL), provided that you have satisfied its requirements.
25 */
26
27FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
28
29/**
30 * @file
31 *
32 * Pseudo-bit structures
33 *
34 */
35
36#include <stdint.h>
37#include <byteswap.h>
38
39/* Endianness selection.
40 *
41 * This is a property of the device, not a property of the host CPU.
42 */
43#ifdef PSEUDOBIT_LITTLE_ENDIAN
44#define cpu_to_BIT64 cpu_to_le64
45#define cpu_to_BIT32 cpu_to_le32
46#define BIT64_to_cpu le64_to_cpu
47#define BIT32_to_cpu le32_to_cpu
48#define QWORD_SHIFT( offset, width ) (offset)
49#endif
50#ifdef PSEUDOBIT_BIG_ENDIAN
51#define cpu_to_BIT64 cpu_to_be64
52#define cpu_to_BIT32 cpu_to_be32
53#define BIT64_to_cpu be64_to_cpu
54#define BIT32_to_cpu be32_to_cpu
55#define QWORD_SHIFT( offset, width ) ( 64 - (offset) - (width) )
56#endif
57
58/** Datatype used to represent a bit in the pseudo-structures */
59typedef unsigned char pseudo_bit_t;
60
61/**
62 * Wrapper structure for pseudo_bit_t structures
63 *
64 * This structure provides a wrapper around pseudo_bit_t structures.
65 * It has the correct size, and also encapsulates type information
66 * about the underlying pseudo_bit_t-based structure, which allows the
67 * BIT_FILL() etc. macros to work without requiring explicit type
68 * information.
69 */
70#define PSEUDO_BIT_STRUCT( _structure ) \
71 union { \
72 uint8_t bytes[ sizeof ( _structure ) / 8 ]; \
73 uint32_t dwords[ sizeof ( _structure ) / 32 ]; \
74 uint64_t qwords[ sizeof ( _structure ) / 64 ]; \
75 _structure *dummy[0]; \
76 } __attribute__ (( packed )) u
77
78/** Get pseudo_bit_t structure type from wrapper structure pointer */
79#define PSEUDO_BIT_STRUCT_TYPE( _ptr ) \
80 typeof ( *((_ptr)->u.dummy[0]) )
81
82/** Bit offset of a field within a pseudo_bit_t structure */
83#define BIT_OFFSET( _ptr, _field ) \
84 offsetof ( PSEUDO_BIT_STRUCT_TYPE ( _ptr ), _field )
85
86/** Bit width of a field within a pseudo_bit_t structure */
87#define BIT_WIDTH( _ptr, _field ) \
88 sizeof ( ( ( PSEUDO_BIT_STRUCT_TYPE ( _ptr ) * ) NULL )->_field )
89
90/** Qword offset of a field within a pseudo_bit_t structure */
91#define QWORD_OFFSET( _ptr, _field ) \
92 ( BIT_OFFSET ( _ptr, _field ) / 64 )
93
94/** Qword bit offset of a field within a pseudo_bit_t structure */
95#define QWORD_BIT_OFFSET( _ptr, _index, _field ) \
96 ( BIT_OFFSET ( _ptr, _field ) - ( 64 * (_index) ) )
97
98/** Qword bit shift for a field within a pseudo_bit_t structure */
99#define QWORD_BIT_SHIFT( _ptr, _index, _field ) \
100 QWORD_SHIFT ( QWORD_BIT_OFFSET ( _ptr, _index, _field ), \
101 BIT_WIDTH ( _ptr, _field ) )
102
103/** Bit mask for a field within a pseudo_bit_t structure */
104#define BIT_MASK( _ptr, _field ) \
105 ( ( ~( ( uint64_t ) 0 ) ) >> \
106 ( 64 - BIT_WIDTH ( _ptr, _field ) ) )
107
108/*
109 * Assemble native-endian qword from named fields and values
110 *
111 */
112
113#define BIT_ASSEMBLE_1( _ptr, _index, _field, _value ) \
114 ( ( ( uint64_t) (_value) ) << \
115 QWORD_BIT_SHIFT ( _ptr, _index, _field ) )
116
117#define BIT_ASSEMBLE_2( _ptr, _index, _field, _value, ... ) \
118 ( BIT_ASSEMBLE_1 ( _ptr, _index, _field, _value ) | \
119 BIT_ASSEMBLE_1 ( _ptr, _index, __VA_ARGS__ ) )
120
121#define BIT_ASSEMBLE_3( _ptr, _index, _field, _value, ... ) \
122 ( BIT_ASSEMBLE_1 ( _ptr, _index, _field, _value ) | \
123 BIT_ASSEMBLE_2 ( _ptr, _index, __VA_ARGS__ ) )
124
125#define BIT_ASSEMBLE_4( _ptr, _index, _field, _value, ... ) \
126 ( BIT_ASSEMBLE_1 ( _ptr, _index, _field, _value ) | \
127 BIT_ASSEMBLE_3 ( _ptr, _index, __VA_ARGS__ ) )
128
129#define BIT_ASSEMBLE_5( _ptr, _index, _field, _value, ... ) \
130 ( BIT_ASSEMBLE_1 ( _ptr, _index, _field, _value ) | \
131 BIT_ASSEMBLE_4 ( _ptr, _index, __VA_ARGS__ ) )
132
133#define BIT_ASSEMBLE_6( _ptr, _index, _field, _value, ... ) \
134 ( BIT_ASSEMBLE_1 ( _ptr, _index, _field, _value ) | \
135 BIT_ASSEMBLE_5 ( _ptr, _index, __VA_ARGS__ ) )
136
137#define BIT_ASSEMBLE_7( _ptr, _index, _field, _value, ... ) \
138 ( BIT_ASSEMBLE_1 ( _ptr, _index, _field, _value ) | \
139 BIT_ASSEMBLE_6 ( _ptr, _index, __VA_ARGS__ ) )
140
141/*
142 * Build native-endian (positive) qword bitmasks from named fields
143 *
144 */
145
146#define BIT_MASK_1( _ptr, _index, _field ) \
147 ( BIT_MASK ( _ptr, _field ) << \
148 QWORD_BIT_SHIFT ( _ptr, _index, _field ) )
149
150#define BIT_MASK_2( _ptr, _index, _field, ... ) \
151 ( BIT_MASK_1 ( _ptr, _index, _field ) | \
152 BIT_MASK_1 ( _ptr, _index, __VA_ARGS__ ) )
153
154#define BIT_MASK_3( _ptr, _index, _field, ... ) \
155 ( BIT_MASK_1 ( _ptr, _index, _field ) | \
156 BIT_MASK_2 ( _ptr, _index, __VA_ARGS__ ) )
157
158#define BIT_MASK_4( _ptr, _index, _field, ... ) \
159 ( BIT_MASK_1 ( _ptr, _index, _field ) | \
160 BIT_MASK_3 ( _ptr, _index, __VA_ARGS__ ) )
161
162#define BIT_MASK_5( _ptr, _index, _field, ... ) \
163 ( BIT_MASK_1 ( _ptr, _index, _field ) | \
164 BIT_MASK_4 ( _ptr, _index, __VA_ARGS__ ) )
165
166#define BIT_MASK_6( _ptr, _index, _field, ... ) \
167 ( BIT_MASK_1 ( _ptr, _index, _field ) | \
168 BIT_MASK_5 ( _ptr, _index, __VA_ARGS__ ) )
169
170#define BIT_MASK_7( _ptr, _index, _field, ... ) \
171 ( BIT_MASK_1 ( _ptr, _index, _field ) | \
172 BIT_MASK_6 ( _ptr, _index, __VA_ARGS__ ) )
173
174/*
175 * Populate device-endian qwords from named fields and values
176 *
177 */
178
179#define BIT_FILL( _ptr, _index, _assembled ) do { \
180 uint64_t *__ptr = &(_ptr)->u.qwords[(_index)]; \
181 uint64_t __assembled = (_assembled); \
182 *__ptr = cpu_to_BIT64 ( __assembled ); \
183 } while ( 0 )
184
185#define BIT_FILL_1( _ptr, _field1, ... ) \
186 BIT_FILL ( _ptr, QWORD_OFFSET ( _ptr, _field1 ), \
187 BIT_ASSEMBLE_1 ( _ptr, QWORD_OFFSET ( _ptr, _field1 ), \
188 _field1, __VA_ARGS__ ) )
189
190#define BIT_FILL_2( _ptr, _field1, ... ) \
191 BIT_FILL ( _ptr, QWORD_OFFSET ( _ptr, _field1 ), \
192 BIT_ASSEMBLE_2 ( _ptr, QWORD_OFFSET ( _ptr, _field1 ), \
193 _field1, __VA_ARGS__ ) )
194
195#define BIT_FILL_3( _ptr, _field1, ... ) \
196 BIT_FILL ( _ptr, QWORD_OFFSET ( _ptr, _field1 ), \
197 BIT_ASSEMBLE_3 ( _ptr, QWORD_OFFSET ( _ptr, _field1 ), \
198 _field1, __VA_ARGS__ ) )
199
200#define BIT_FILL_4( _ptr, _field1, ... ) \
201 BIT_FILL ( _ptr, QWORD_OFFSET ( _ptr, _field1 ), \
202 BIT_ASSEMBLE_4 ( _ptr, QWORD_OFFSET ( _ptr, _field1 ), \
203 _field1, __VA_ARGS__ ) )
204
205#define BIT_FILL_5( _ptr, _field1, ... ) \
206 BIT_FILL ( _ptr, QWORD_OFFSET ( _ptr, _field1 ), \
207 BIT_ASSEMBLE_5 ( _ptr, QWORD_OFFSET ( _ptr, _field1 ), \
208 _field1, __VA_ARGS__ ) )
209
210#define BIT_FILL_6( _ptr, _field1, ... ) \
211 BIT_FILL ( _ptr, QWORD_OFFSET ( _ptr, _field1 ), \
212 BIT_ASSEMBLE_6 ( _ptr, QWORD_OFFSET ( _ptr, _field1 ), \
213 _field1, __VA_ARGS__ ) )
214
215#define BIT_QWORD_PTR( _ptr, _field ) \
216 ( { \
217 unsigned int __index = QWORD_OFFSET ( _ptr, _field ); \
218 uint64_t *__ptr = &(_ptr)->u.qwords[__index]; \
219 __ptr; \
220 } )
221
222/** Extract value of named field */
223#define BIT_GET64( _ptr, _field ) \
224 ( { \
225 unsigned int __index = QWORD_OFFSET ( _ptr, _field ); \
226 uint64_t *__ptr = &(_ptr)->u.qwords[__index]; \
227 uint64_t __value = BIT64_to_cpu ( *__ptr ); \
228 __value >>= \
229 QWORD_BIT_SHIFT ( _ptr, __index, _field ); \
230 __value &= BIT_MASK ( _ptr, _field ); \
231 __value; \
232 } )
233
234/** Extract value of named field (for fields up to the size of a long) */
235#define BIT_GET( _ptr, _field ) \
236 ( ( unsigned long ) BIT_GET64 ( _ptr, _field ) )
237
238#define BIT_SET( _ptr, _field, _value ) do { \
239 unsigned int __index = QWORD_OFFSET ( _ptr, _field ); \
240 uint64_t *__ptr = &(_ptr)->u.qwords[__index]; \
241 unsigned int __shift = \
242 QWORD_BIT_SHIFT ( _ptr, __index, _field ); \
243 uint64_t __value = (_value); \
244 *__ptr &= cpu_to_BIT64 ( ~( BIT_MASK ( _ptr, _field ) << \
245 __shift ) ); \
246 *__ptr |= cpu_to_BIT64 ( __value << __shift ); \
247 } while ( 0 )
248
249#endif /* _IPXE_PSEUDOBIT_H */
#define FILE_LICENCE(_licence)
Declare a particular licence as applying to a file.
Definition compiler.h:896
unsigned char pseudo_bit_t
Datatype used to represent a bit in the pseudo-structures.
Definition nx_bitops.h:37