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