Browse Source

Doxygenated

tags/v0.9.3
Michael Brown 19 years ago
parent
commit
c18ea5282c
1 changed files with 189 additions and 23 deletions
  1. 189
    23
      src/include/tables.h

+ 189
- 23
src/include/tables.h View File

1
 #ifndef TABLES_H
1
 #ifndef TABLES_H
2
 #define TABLES_H
2
 #define TABLES_H
3
 
3
 
4
-/*
5
- * Macros for dealing with linker-generated tables of fixed-size
6
- * symbols.  We make fairly extensive use of these in order to avoid
7
- * ifdef spaghetti and/or linker symbol pollution.  For example,
8
- * instead of having code such as
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
9
  *
58
  *
10
- * #ifdef CONSOLE_SERIAL
11
  *   serial_init();
59
  *   serial_init();
12
- * #endif
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
13
  *
88
  *
14
  * we make serial.c generate an entry in the initialisation function
89
  * we make serial.c generate an entry in the initialisation function
15
  * table, and then have a function call_init_fns() that simply calls
90
  * table, and then have a function call_init_fns() that simply calls
16
  * all functions present in this table.  If and only if serial.o gets
91
  * all functions present in this table.  If and only if serial.o gets
17
  * linked in, then its initialisation function will be called.  We
92
  * linked in, then its initialisation function will be called.  We
18
  * avoid linker symbol pollution (i.e. always dragging in serial.o
93
  * avoid linker symbol pollution (i.e. always dragging in serial.o
19
- * just because of a call to serial_init()) and we also avoid ifdef
20
- * spaghetti (having to conditionalise every reference to functions in
21
- * serial.c).
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).
22
  *
97
  *
23
  * The linker script takes care of assembling the tables for us.  All
98
  * The linker script takes care of assembling the tables for us.  All
24
- * our table sections have names of the format ".tbl.NAME.NN" where
25
- * NAME designates the data structure stored in the table
26
- * (e.g. "init_fn") and NN is a two-digit decimal number used to
27
- * impose an ordering upon the tables if required.  NN=00 is reserved
28
- * for the symbol indicating "table start", and NN=99 is reserved for
29
- * the symbol indicating "table end".
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_fn) 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 __frobnicator __table ( frobnicators, 01 )
119
+ *
120
+ * @endcode
30
  *
121
  *
31
- * To define an entry in the "xxx" table:
122
+ * Any module providing frobnicating services would look something
123
+ * like
32
  *
124
  *
33
- *  static struct xxx my_xxx __table(xxx,01) = { ... };
125
+ * @code
34
  *
126
  *
35
- * To access start and end markers for the "xxx" table:
127
+ *   #include "frob.h"
36
  *
128
  *
37
- *  static struct xxx xxx_start[0] __table_start(xxx);
38
- *  static struct xxx xxx_end[0] __table_end(xxx);
129
+ *   static void my_frob ( void ) {
130
+ *	// Do my frobnicating
131
+ *	...
132
+ *   }
39
  *
133
  *
40
- * See init.h and init.c for an example of how these macros are used
41
- * in practice.
134
+ *   static 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
+ *   static struct frob frob_start[0] __table_start ( frobnicators );
149
+ *   static struct frob frob_end[0] __table_end ( frobnicators );
150
+ *
151
+ *   // Call all linked-in frobnicators
152
+ *   void frob_all ( void ) {
153
+ *	struct frob *frob;
154
+ *
155
+ *      for ( frob = frob_start ; frob < frob_end ; frob++ ) {
156
+ *         printf ( "Calling frobnicator \"%s\"\n", frob->name );
157
+ *	   frob->frob ();
158
+ *	}
159
+ *   }
160
+ *
161
+ * @endcode
162
+ *
163
+ * See init.h and init.c for a real-life example.
42
  *
164
  *
43
  */
165
  */
44
 
166
 
49
 #define __table_section_start(table) __table_section(table,00)
171
 #define __table_section_start(table) __table_section(table,00)
50
 #define __table_section_end(table) __table_section(table,99)
172
 #define __table_section_end(table) __table_section(table,99)
51
 
173
 
174
+
175
+/**
176
+ * Linker table entry.
177
+ *
178
+ * Declares a data structure to be part of a linker table.  Use as
179
+ * e.g.
180
+ *
181
+ * @code
182
+ *
183
+ *   static struct my_foo __table ( foo, 01 ) = {
184
+ *      ...
185
+ *   };
186
+ *
187
+ * @endcode
188
+ *
189
+ */
52
 #define __table(table,idx) \
190
 #define __table(table,idx) \
53
 	__attribute__ (( unused, __table_section(table,idx) ))
191
 	__attribute__ (( unused, __table_section(table,idx) ))
192
+
193
+/**
194
+ * Linker table start marker.
195
+ *
196
+ * Declares a data structure (usually an empty data structure) to be
197
+ * the start of a linker table.  Use as e.g.
198
+ *
199
+ * @code
200
+ *
201
+ *   static struct foo_start[0] __table_start ( foo );
202
+ *
203
+ * @endcode
204
+ *
205
+ */
54
 #define __table_start(table) \
206
 #define __table_start(table) \
55
 	__attribute__ (( unused, __table_section_start(table) ))
207
 	__attribute__ (( unused, __table_section_start(table) ))
208
+
209
+/**
210
+ * Linker table end marker.
211
+ *
212
+ * Declares a data structure (usually an empty data structure) to be
213
+ * the end of a linker table.  Use as e.g.
214
+ *
215
+ * @code
216
+ *
217
+ *   static struct foo_end[0] __table_end ( foo );
218
+ *
219
+ * @endcode
220
+ *
221
+ */
56
 #define __table_end(table) \
222
 #define __table_end(table) \
57
 	__attribute__ (( unused, __table_section_end(table) ))
223
 	__attribute__ (( unused, __table_section_end(table) ))
58
 
224
 

Loading…
Cancel
Save