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