| #ifndef _GPXE_TABLES_H |
| #define _GPXE_TABLES_H |
| |
| FILE_LICENCE ( GPL2_OR_LATER ); |
| |
| /** @page ifdef_harmful #ifdef considered harmful |
| * |
| * Overuse of @c #ifdef has long been a problem in Etherboot. |
| * Etherboot provides a rich array of features, but all these features |
| * take up valuable space in a ROM image. The traditional solution to |
| * this problem has been for each feature to have its own @c #ifdef |
| * option, allowing the feature to be compiled in only if desired. |
| * |
| * The problem with this is that it becomes impossible to compile, let |
| * alone test, all possible versions of Etherboot. Code that is not |
| * typically used tends to suffer from bit-rot over time. It becomes |
| * extremely difficult to predict which combinations of compile-time |
| * options will result in code that can even compile and link |
| * correctly. |
| * |
| * To solve this problem, we have adopted a new approach from |
| * Etherboot 5.5 onwards. @c #ifdef is now "considered harmful", and |
| * its use should be minimised. Separate features should be |
| * implemented in separate @c .c files, and should \b always be |
| * compiled (i.e. they should \b not be guarded with a @c #ifdef @c |
| * MY_PET_FEATURE statement). By making (almost) all code always |
| * compile, we avoid the problem of bit-rot in rarely-used code. |
| * |
| * The file config.h, in combination with the @c make command line, |
| * specifies the objects that will be included in any particular build |
| * of Etherboot. For example, suppose that config.h includes the line |
| * |
| * @code |
| * |
| * #define CONSOLE_SERIAL |
| * #define DOWNLOAD_PROTO_TFTP |
| * |
| * @endcode |
| * |
| * When a particular Etherboot image (e.g. @c bin/rtl8139.zdsk) is |
| * built, the options specified in config.h are used to drag in the |
| * relevant objects at link-time. For the above example, serial.o and |
| * tftp.o would be linked in. |
| * |
| * There remains one problem to solve: how do these objects get used? |
| * Traditionally, we had code such as |
| * |
| * @code |
| * |
| * #ifdef CONSOLE_SERIAL |
| * serial_init(); |
| * #endif |
| * |
| * @endcode |
| * |
| * in main.c, but this reintroduces @c #ifdef and so is a Bad Idea. |
| * We cannot simply remove the @c #ifdef and make it |
| * |
| * @code |
| * |
| * serial_init(); |
| * |
| * @endcode |
| * |
| * because then serial.o would end up always being linked in. |
| * |
| * The solution is to use @link tables.h linker tables @endlink. |
| * |
| */ |
| |
| /** @file |
| * |
| * Linker tables |
| * |
| * Read @ref ifdef_harmful first for some background on the motivation |
| * for using linker tables. |
| * |
| * This file provides macros for dealing with linker-generated tables |
| * of fixed-size symbols. We make fairly extensive use of these in |
| * order to avoid @c #ifdef spaghetti and/or linker symbol pollution. |
| * For example, instead of having code such as |
| * |
| * @code |
| * |
| * #ifdef CONSOLE_SERIAL |
| * serial_init(); |
| * #endif |
| * |
| * @endcode |
| * |
| * we make serial.c generate an entry in the initialisation function |
| * table, and then have a function call_init_fns() that simply calls |
| * all functions present in this table. If and only if serial.o gets |
| * linked in, then its initialisation function will be called. We |
| * avoid linker symbol pollution (i.e. always dragging in serial.o |
| * just because of a call to serial_init()) and we also avoid @c |
| * #ifdef spaghetti (having to conditionalise every reference to |
| * functions in serial.c). |
| * |
| * The linker script takes care of assembling the tables for us. All |
| * our table sections have names of the format @c .tbl.NAME.NN where |
| * @c NAME designates the data structure stored in the table (e.g. @c |
| * init_fns) and @c NN is a two-digit decimal number used to impose an |
| * ordering upon the tables if required. @c NN=00 is reserved for the |
| * symbol indicating "table start", and @c NN=99 is reserved for the |
| * symbol indicating "table end". |
| * |
| * As an example, suppose that we want to create a "frobnicator" |
| * feature framework, and allow for several independent modules to |
| * provide frobnicating services. Then we would create a frob.h |
| * header file containing e.g. |
| * |
| * @code |
| * |
| * struct frobnicator { |
| * const char *name; // Name of the frobnicator |
| * void ( *frob ) ( void ); // The frobnicating function itself |
| * }; |
| * |
| * #define FROBNICATORS __table ( struct frobnicator, "frobnicators" ) |
| * |
| * #define __frobnicator __table_entry ( FROBNICATORS, 01 ) |
| * |
| * @endcode |
| * |
| * Any module providing frobnicating services would look something |
| * like |
| * |
| * @code |
| * |
| * #include "frob.h" |
| * |
| * static void my_frob ( void ) { |
| * // Do my frobnicating |
| * ... |
| * } |
| * |
| * struct frob my_frobnicator __frobnicator = { |
| * .name = "my_frob", |
| * .frob = my_frob, |
| * }; |
| * |
| * @endcode |
| * |
| * The central frobnicator code (frob.c) would use the frobnicating |
| * modules as follows |
| * |
| * @code |
| * |
| * #include "frob.h" |
| * |
| * // Call all linked-in frobnicators |
| * void frob_all ( void ) { |
| * struct frob *frob; |
| * |
| * for_each_table ( frob, FROBNICATORS ) { |
| * printf ( "Calling frobnicator \"%s\"\n", frob->name ); |
| * frob->frob (); |
| * } |
| * } |
| * |
| * @endcode |
| * |
| * See init.h and init.c for a real-life example. |
| * |
| */ |
| |
| #ifdef DOXYGEN |
| #define __attribute__( x ) |
| #endif |
| |
| /** |
| * Declare a linker table |
| * |
| * @v type Data type |
| * @v name Table name |
| * @ret table Linker table |
| */ |
| #define __table( type, name ) ( type, name ) |
| |
| /** |
| * Get linker table data type |
| * |
| * @v table Linker table |
| * @ret type Data type |
| */ |
| #define __table_type( table ) __table_extract_type table |
| #define __table_extract_type( type, name ) type |
| |
| /** |
| * Get linker table name |
| * |
| * @v table Linker table |
| * @ret name Table name |
| */ |
| #define __table_name( table ) __table_extract_name table |
| #define __table_extract_name( type, name ) name |
| |
| /** |
| * Get linker table section name |
| * |
| * @v table Linker table |
| * @v idx Sub-table index |
| * @ret section Section name |
| */ |
| #define __table_section( table, idx ) \ |
| ".tbl." __table_name ( table ) "." __table_str ( idx ) |
| #define __table_str( x ) #x |
| |
| /** |
| * Get linker table alignment |
| * |
| * @v table Linker table |
| * @ret align Alignment |
| */ |
| #define __table_alignment( table ) __alignof__ ( __table_type ( table ) ) |
| |
| /** |
| * Declare a linker table entry |
| * |
| * @v table Linker table |
| * @v idx Sub-table index |
| * |
| * Example usage: |
| * |
| * @code |
| * |
| * #define FROBNICATORS __table ( struct frobnicator, "frobnicators" ) |
| * |
| * #define __frobnicator __table_entry ( FROBNICATORS, 01 ) |
| * |
| * struct frobnicator my_frob __frobnicator = { |
| * ... |
| * }; |
| * |
| * @endcode |
| */ |
| #define __table_entry( table, idx ) \ |
| __attribute__ (( __section__ ( __table_section ( table, idx ) ),\ |
| __aligned__ ( __table_alignment ( table ) ) )) |
| |
| /** |
| * Get start of linker table entries |
| * |
| * @v table Linker table |
| * @v idx Sub-table index |
| * @ret entries Start of entries |
| */ |
| #define __table_entries( table, idx ) ( { \ |
| static __table_type ( table ) __table_entries[0] \ |
| __table_entry ( table, idx ); \ |
| __table_entries; } ) |
| |
| /** |
| * Get start of linker table |
| * |
| * @v table Linker table |
| * @ret start Start of linker table |
| * |
| * Example usage: |
| * |
| * @code |
| * |
| * #define FROBNICATORS __table ( struct frobnicator, "frobnicators" ) |
| * |
| * struct frobnicator *frobs = table_start ( FROBNICATORS ); |
| * |
| * @endcode |
| */ |
| #define table_start( table ) __table_entries ( table, 00 ) |
| |
| /** |
| * Get end of linker table |
| * |
| * @v table Linker table |
| * @ret end End of linker table |
| * |
| * Example usage: |
| * |
| * @code |
| * |
| * #define FROBNICATORS __table ( struct frobnicator, "frobnicators" ) |
| * |
| * struct frobnicator *frobs_end = table_end ( FROBNICATORS ); |
| * |
| * @endcode |
| */ |
| #define table_end( table ) __table_entries ( table, 99 ) |
| |
| /** |
| * Get number of entries in linker table |
| * |
| * @v table Linker table |
| * @ret num_entries Number of entries in linker table |
| * |
| * Example usage: |
| * |
| * @code |
| * |
| * #define FROBNICATORS __table ( struct frobnicator, "frobnicators" ) |
| * |
| * unsigned int num_frobs = table_num_entries ( FROBNICATORS ); |
| * |
| * @endcode |
| * |
| */ |
| #define table_num_entries( table ) \ |
| ( ( unsigned int ) ( table_end ( table ) - \ |
| table_start ( table ) ) ) |
| |
| /** |
| * Iterate through all entries within a linker table |
| * |
| * @v pointer Entry pointer |
| * @v table Linker table |
| * |
| * Example usage: |
| * |
| * @code |
| * |
| * #define FROBNICATORS __table ( struct frobnicator, "frobnicators" ) |
| * |
| * struct frobnicator *frob; |
| * |
| * for_each_table_entry ( frob, FROBNICATORS ) { |
| * ... |
| * } |
| * |
| * @endcode |
| * |
| */ |
| #define for_each_table_entry( pointer, table ) \ |
| for ( pointer = table_start ( table ) ; \ |
| pointer < table_end ( table ) ; \ |
| pointer++ ) |
| |
| /** |
| * Iterate through all entries within a linker table in reverse order |
| * |
| * @v pointer Entry pointer |
| * @v table Linker table |
| * |
| * Example usage: |
| * |
| * @code |
| * |
| * #define FROBNICATORS __table ( struct frobnicator, "frobnicators" ) |
| * |
| * struct frobnicator *frob; |
| * |
| * for_each_table_entry_reverse ( frob, FROBNICATORS ) { |
| * ... |
| * } |
| * |
| * @endcode |
| * |
| */ |
| #define for_each_table_entry_reverse( pointer, table ) \ |
| for ( pointer = ( table_end ( table ) - 1 ) ; \ |
| pointer >= table_start ( table ) ; \ |
| pointer-- ) |
| |
| /****************************************************************************** |
| * |
| * Intel's C compiler chokes on several of the constructs used in this |
| * file. The workarounds are ugly, so we use them only for an icc |
| * build. |
| * |
| */ |
| #define ICC_ALIGN_HACK_FACTOR 128 |
| #ifdef __ICC |
| |
| /* |
| * icc miscompiles zero-length arrays by inserting padding to a length |
| * of two array elements. We therefore have to generate the |
| * __table_entries() symbols by hand in asm. |
| * |
| */ |
| #undef __table_entries |
| #define __table_entries( table, idx ) ( { \ |
| extern __table_type ( table ) \ |
| __table_temp_sym ( idx, __LINE__ ) [] \ |
| __table_entry ( table, idx ) \ |
| asm ( __table_entries_sym ( table, idx ) ); \ |
| __asm__ ( ".ifndef %c0\n\t" \ |
| ".section " __table_section ( table, idx ) "\n\t" \ |
| ".align %c1\n\t" \ |
| "\n%c0:\n\t" \ |
| ".previous\n\t" \ |
| ".endif\n\t" \ |
| : : "i" ( __table_temp_sym ( idx, __LINE__ ) ), \ |
| "i" ( __table_alignment ( table ) ) ); \ |
| __table_temp_sym ( idx, __LINE__ ); } ) |
| #define __table_entries_sym( table, idx ) \ |
| "__tbl_" __table_name ( table ) "_" #idx |
| #define __table_temp_sym( a, b ) \ |
| ___table_temp_sym( __table_, a, _, b ) |
| #define ___table_temp_sym( a, b, c, d ) a ## b ## c ## d |
| |
| /* |
| * icc ignores __attribute__ (( aligned (x) )) when it is used to |
| * decrease the compiler's default choice of alignment (which may be |
| * higher than the alignment actually required by the structure). We |
| * work around this by forcing the alignment to a large multiple of |
| * the required value (so that we are never attempting to decrease the |
| * default alignment) and then postprocessing the object file to |
| * reduce the alignment back down to the "real" value. |
| * |
| */ |
| #undef __table_alignment |
| #define __table_alignment( table ) \ |
| ( ICC_ALIGN_HACK_FACTOR * __alignof__ ( __table_type ( table ) ) ) |
| |
| /* |
| * Because of the alignment hack, we must ensure that the compiler |
| * never tries to place multiple objects within the same section, |
| * otherwise the assembler will insert padding to the (incorrect) |
| * alignment boundary. Do this by appending the line number to table |
| * section names. |
| * |
| * Note that we don't need to worry about padding between array |
| * elements, since the alignment is declared on the variable (i.e. the |
| * whole array) rather than on the type (i.e. on all individual array |
| * elements). |
| */ |
| #undef __table_section |
| #define __table_section( table, idx ) \ |
| ".tbl." __table_name ( table ) "." __table_str ( idx ) \ |
| "." __table_xstr ( __LINE__ ) |
| #define __table_xstr( x ) __table_str ( x ) |
| |
| #endif /* __ICC */ |
| |
| #endif /* _GPXE_TABLES_H */ |