iPXE
tables.h
Go to the documentation of this file.
1 #ifndef _IPXE_TABLES_H
2 #define _IPXE_TABLES_H
3 
4 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
5 
6 /** @page ifdef_harmful #ifdef considered harmful
7  *
8  * Overuse of @c #ifdef has long been a problem in Etherboot.
9  * Etherboot provides a rich array of features, but all these features
10  * take up valuable space in a ROM image. The traditional solution to
11  * this problem has been for each feature to have its own @c #ifdef
12  * option, allowing the feature to be compiled in only if desired.
13  *
14  * The problem with this is that it becomes impossible to compile, let
15  * alone test, all possible versions of Etherboot. Code that is not
16  * typically used tends to suffer from bit-rot over time. It becomes
17  * extremely difficult to predict which combinations of compile-time
18  * options will result in code that can even compile and link
19  * correctly.
20  *
21  * To solve this problem, we have adopted a new approach from
22  * Etherboot 5.5 onwards. @c #ifdef is now "considered harmful", and
23  * its use should be minimised. Separate features should be
24  * implemented in separate @c .c files, and should \b always be
25  * compiled (i.e. they should \b not be guarded with a @c #ifdef @c
26  * MY_PET_FEATURE statement). By making (almost) all code always
27  * compile, we avoid the problem of bit-rot in rarely-used code.
28  *
29  * The file config.h, in combination with the @c make command line,
30  * specifies the objects that will be included in any particular build
31  * of Etherboot. For example, suppose that config.h includes the line
32  *
33  * @code
34  *
35  * #define CONSOLE_SERIAL
36  * #define DOWNLOAD_PROTO_TFTP
37  *
38  * @endcode
39  *
40  * When a particular Etherboot image (e.g. @c bin/rtl8139.zdsk) is
41  * built, the options specified in config.h are used to drag in the
42  * relevant objects at link-time. For the above example, serial.o and
43  * tftp.o would be linked in.
44  *
45  * There remains one problem to solve: how do these objects get used?
46  * Traditionally, we had code such as
47  *
48  * @code
49  *
50  * #ifdef CONSOLE_SERIAL
51  * serial_init();
52  * #endif
53  *
54  * @endcode
55  *
56  * in main.c, but this reintroduces @c #ifdef and so is a Bad Idea.
57  * We cannot simply remove the @c #ifdef and make it
58  *
59  * @code
60  *
61  * serial_init();
62  *
63  * @endcode
64  *
65  * because then serial.o would end up always being linked in.
66  *
67  * The solution is to use @link tables.h linker tables @endlink.
68  *
69  */
70 
71 /** @file
72  *
73  * Linker tables
74  *
75  * Read @ref ifdef_harmful first for some background on the motivation
76  * for using linker tables.
77  *
78  * This file provides macros for dealing with linker-generated tables
79  * of fixed-size symbols. We make fairly extensive use of these in
80  * order to avoid @c #ifdef spaghetti and/or linker symbol pollution.
81  * For example, instead of having code such as
82  *
83  * @code
84  *
85  * #ifdef CONSOLE_SERIAL
86  * serial_init();
87  * #endif
88  *
89  * @endcode
90  *
91  * we make serial.c generate an entry in the initialisation function
92  * table, and then have a function call_init_fns() that simply calls
93  * all functions present in this table. If and only if serial.o gets
94  * linked in, then its initialisation function will be called. We
95  * avoid linker symbol pollution (i.e. always dragging in serial.o
96  * just because of a call to serial_init()) and we also avoid @c
97  * #ifdef spaghetti (having to conditionalise every reference to
98  * functions in serial.c).
99  *
100  * The linker script takes care of assembling the tables for us. All
101  * our table sections have names of the format @c .tbl.NAME.NN where
102  * @c NAME designates the data structure stored in the table (e.g. @c
103  * init_fns) and @c NN is a two-digit decimal number used to impose an
104  * ordering upon the tables if required. @c NN=00 is reserved for the
105  * symbol indicating "table start", and @c NN=99 is reserved for the
106  * symbol indicating "table end".
107  *
108  * As an example, suppose that we want to create a "frobnicator"
109  * feature framework, and allow for several independent modules to
110  * provide frobnicating services. Then we would create a frob.h
111  * header file containing e.g.
112  *
113  * @code
114  *
115  * struct frobnicator {
116  * const char *name; // Name of the frobnicator
117  * void ( *frob ) ( void ); // The frobnicating function itself
118  * };
119  *
120  * #define FROBNICATORS __table ( struct frobnicator, "frobnicators" )
121  *
122  * #define __frobnicator __table_entry ( FROBNICATORS, 01 )
123  *
124  * @endcode
125  *
126  * Any module providing frobnicating services would look something
127  * like
128  *
129  * @code
130  *
131  * #include "frob.h"
132  *
133  * static void my_frob ( void ) {
134  * // Do my frobnicating
135  * ...
136  * }
137  *
138  * struct frob my_frobnicator __frobnicator = {
139  * .name = "my_frob",
140  * .frob = my_frob,
141  * };
142  *
143  * @endcode
144  *
145  * The central frobnicator code (frob.c) would use the frobnicating
146  * modules as follows
147  *
148  * @code
149  *
150  * #include "frob.h"
151  *
152  * // Call all linked-in frobnicators
153  * void frob_all ( void ) {
154  * struct frob *frob;
155  *
156  * for_each_table ( frob, FROBNICATORS ) {
157  * printf ( "Calling frobnicator \"%s\"\n", frob->name );
158  * frob->frob ();
159  * }
160  * }
161  *
162  * @endcode
163  *
164  * See init.h and init.c for a real-life example.
165  *
166  */
167 
168 #ifdef DOXYGEN
169 #define __attribute__( x )
170 #endif
171 
172 /**
173  * Declare a linker table
174  *
175  * @v type Data type
176  * @v name Table name
177  * @ret table Linker table
178  */
179 #define __table( type, name ) ( type, name )
180 
181 /**
182  * Get linker table data type
183  *
184  * @v table Linker table
185  * @ret type Data type
186  */
187 #define __table_type( table ) __table_extract_type table
188 #define __table_extract_type( type, name ) type
189 
190 /**
191  * Get linker table name
192  *
193  * @v table Linker table
194  * @ret name Table name
195  */
196 #define __table_name( table ) __table_extract_name table
197 #define __table_extract_name( type, name ) name
198 
199 /**
200  * Get linker table section name
201  *
202  * @v table Linker table
203  * @v idx Sub-table index
204  * @ret section Section name
205  */
206 #define __table_section( table, idx ) \
207  ".tbl." __table_name ( table ) "." __table_str ( idx )
208 #define __table_str( x ) #x
209 
210 /**
211  * Get linker table alignment
212  *
213  * @v table Linker table
214  * @ret align Alignment
215  */
216 #define __table_alignment( table ) __alignof__ ( __table_type ( table ) )
217 
218 /**
219  * Declare a linker table entry
220  *
221  * @v table Linker table
222  * @v idx Sub-table index
223  *
224  * Example usage:
225  *
226  * @code
227  *
228  * #define FROBNICATORS __table ( struct frobnicator, "frobnicators" )
229  *
230  * #define __frobnicator __table_entry ( FROBNICATORS, 01 )
231  *
232  * struct frobnicator my_frob __frobnicator = {
233  * ...
234  * };
235  *
236  * @endcode
237  */
238 #define __table_entry( table, idx ) \
239  __attribute__ (( __section__ ( __table_section ( table, idx ) ),\
240  __aligned__ ( __table_alignment ( table ) ) ))
241 
242 /**
243  * Get start of linker table entries
244  *
245  * @v table Linker table
246  * @v idx Sub-table index
247  * @ret entries Start of entries
248  */
249 #define __table_entries( table, idx ) ( { \
250  static __table_type ( table ) __table_entries[0] \
251  __table_entry ( table, idx ) \
252  __attribute__ (( unused )); \
253  __table_entries; } )
254 
255 /**
256  * Declare start of linker table entries
257  *
258  * @v entries Start of entries
259  * @v table Linker table
260  * @v idx Sub-table index
261  */
262 #define __TABLE_ENTRIES( entries, table, idx ) \
263  __table_type ( table ) entries[0] \
264  __table_entry ( table, idx )
265 
266 /**
267  * Get start of linker table
268  *
269  * @v table Linker table
270  * @ret start Start of linker table
271  *
272  * Example usage:
273  *
274  * @code
275  *
276  * #define FROBNICATORS __table ( struct frobnicator, "frobnicators" )
277  *
278  * struct frobnicator *frobs = table_start ( FROBNICATORS );
279  *
280  * @endcode
281  */
282 #define table_start( table ) __table_entries ( table, 00 )
283 
284 /**
285  * Declare start of linker table
286  *
287  * @v start Start of linker table
288  * @v table Linker table
289  */
290 #define TABLE_START( start, table ) __TABLE_ENTRIES ( start, table, 00 )
291 
292 /**
293  * Get end of linker table
294  *
295  * @v table Linker table
296  * @ret end End of linker table
297  *
298  * Example usage:
299  *
300  * @code
301  *
302  * #define FROBNICATORS __table ( struct frobnicator, "frobnicators" )
303  *
304  * struct frobnicator *frobs_end = table_end ( FROBNICATORS );
305  *
306  * @endcode
307  */
308 #define table_end( table ) __table_entries ( table, 99 )
309 
310 /**
311  * Declare end of linker table
312  *
313  * @v end End of linker table
314  * @v table Linker table
315  */
316 #define TABLE_END( end, table ) __TABLE_ENTRIES ( end, table, 99 )
317 
318 /**
319  * Get number of entries in linker table
320  *
321  * @v table Linker table
322  * @ret num_entries Number of entries in linker table
323  *
324  * Example usage:
325  *
326  * @code
327  *
328  * #define FROBNICATORS __table ( struct frobnicator, "frobnicators" )
329  *
330  * unsigned int num_frobs = table_num_entries ( FROBNICATORS );
331  *
332  * @endcode
333  *
334  */
335 #define table_num_entries( table ) \
336  ( ( unsigned int ) ( table_end ( table ) - \
337  table_start ( table ) ) )
338 
339 /**
340  * Get index of entry within linker table
341  *
342  * @v table Linker table
343  * @v entry Table entry
344  *
345  * Example usage:
346  *
347  * @code
348  *
349  * #define FROBNICATORS __table ( struct frobnicator, "frobnicators" )
350  *
351  * #define __frobnicator __table_entry ( FROBNICATORS, 01 )
352  *
353  * struct frobnicator my_frob __frobnicator = {
354  * ...
355  * };
356  *
357  * unsigned int my_frob_idx = table_index ( FROBNICATORS, &my_frob );
358  *
359  * @endcode
360  */
361 #define table_index( table, entry ) \
362  ( ( unsigned int ) ( (entry) - table_start ( table ) ) )
363 
364 /**
365  * Iterate through all entries within a linker table
366  *
367  * @v pointer Entry pointer
368  * @v table Linker table
369  *
370  * Example usage:
371  *
372  * @code
373  *
374  * #define FROBNICATORS __table ( struct frobnicator, "frobnicators" )
375  *
376  * struct frobnicator *frob;
377  *
378  * for_each_table_entry ( frob, FROBNICATORS ) {
379  * ...
380  * }
381  *
382  * @endcode
383  *
384  */
385 #define for_each_table_entry( pointer, table ) \
386  for ( pointer = table_start ( table ) ; \
387  pointer < table_end ( table ) ; \
388  pointer++ )
389 
390 /**
391  * Iterate through all remaining entries within a linker table
392  *
393  * @v pointer Entry pointer, preset to most recent entry
394  * @v table Linker table
395  *
396  * Example usage:
397  *
398  * @code
399  *
400  * #define FROBNICATORS __table ( struct frobnicator, "frobnicators" )
401  * #define __frobnicator __table_entry ( FROBNICATORS, 01 )
402  *
403  * struct frob my_frobnicator __frobnicator;
404  * struct frobnicator *frob;
405  *
406  * frob = &my_frobnicator;
407  * for_each_table_entry_continue ( frob, FROBNICATORS ) {
408  * ...
409  * }
410  *
411  * @endcode
412  *
413  */
414 #define for_each_table_entry_continue( pointer, table ) \
415  for ( pointer++ ; \
416  pointer < table_end ( table ) ; \
417  pointer++ )
418 
419 /**
420  * Iterate through all entries within a linker table in reverse order
421  *
422  * @v pointer Entry pointer
423  * @v table Linker table
424  *
425  * Example usage:
426  *
427  * @code
428  *
429  * #define FROBNICATORS __table ( struct frobnicator, "frobnicators" )
430  *
431  * struct frobnicator *frob;
432  *
433  * for_each_table_entry_reverse ( frob, FROBNICATORS ) {
434  * ...
435  * }
436  *
437  * @endcode
438  *
439  */
440 #define for_each_table_entry_reverse( pointer, table ) \
441  for ( pointer = ( table_end ( table ) - 1 ) ; \
442  pointer >= table_start ( table ) ; \
443  pointer-- )
444 
445 /**
446  * Iterate through all remaining entries within a linker table in reverse order
447  *
448  * @v pointer Entry pointer, preset to most recent entry
449  * @v table Linker table
450  *
451  * Example usage:
452  *
453  * @code
454  *
455  * #define FROBNICATORS __table ( struct frobnicator, "frobnicators" )
456  * #define __frobnicator __table_entry ( FROBNICATORS, 01 )
457  *
458  * struct frob my_frobnicator __frobnicator;
459  * struct frobnicator *frob;
460  *
461  * frob = &my_frobnicator;
462  * for_each_table_entry_continue_reverse ( frob, FROBNICATORS ) {
463  * ...
464  * }
465  *
466  * @endcode
467  *
468  */
469 #define for_each_table_entry_continue_reverse( pointer, table ) \
470  for ( pointer-- ; \
471  pointer >= table_start ( table ) ; \
472  pointer-- )
473 
474 #endif /* _IPXE_TABLES_H */
FILE_LICENCE(GPL2_OR_LATER_OR_UBDL)