You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

tables.h 8.8KB

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