1 | .. comment SPDX-License-Identifier: CC-BY-SA-4.0 |
---|
2 | |
---|
3 | .. COMMENT: COPYRIGHT (c) 1988-2008. |
---|
4 | .. COMMENT: On-Line Applications Research Corporation (OAR). |
---|
5 | .. COMMENT: All rights reserved. |
---|
6 | |
---|
7 | Initialization Code |
---|
8 | ################### |
---|
9 | |
---|
10 | Introduction |
---|
11 | ============ |
---|
12 | |
---|
13 | The initialization code is the first piece of code executed when there's a |
---|
14 | reset/reboot. Its purpose is to initialize the board for the application. This |
---|
15 | chapter contains a narrative description of the initialization process followed |
---|
16 | by a description of each of the files and routines commonly found in the BSP |
---|
17 | related to initialization. The remainder of this chapter covers special issues |
---|
18 | which require attention such as interrupt vector table and chip select |
---|
19 | initialization. |
---|
20 | |
---|
21 | Most of the examples in this chapter will be based on the SPARC/ERC32 and |
---|
22 | m68k/gen68340 BSP initialization code. Like most BSPs, the initialization for |
---|
23 | these BSP is divided into two subdirectories under the BSP source directory. |
---|
24 | The BSP source code for these BSPs is in the following directories: |
---|
25 | |
---|
26 | .. code:: c |
---|
27 | |
---|
28 | c/src/lib/libbsp/m68k/gen68340 |
---|
29 | c/src/lib/libbsp/sparc/erc32 |
---|
30 | |
---|
31 | Both BSPs contain startup code written in assembly language and C. The |
---|
32 | gen68340 BSP has its early initialization start code in the ``start340`` |
---|
33 | subdirectory and its C startup code in the ``startup`` directory. In the |
---|
34 | ``start340`` directory are two source files. The file ``startfor340only.s`` is |
---|
35 | the simpler of these files as it only has initialization code for a MC68340 |
---|
36 | board. The file ``start340.s`` contains initialization for a 68349 based board |
---|
37 | as well. |
---|
38 | |
---|
39 | Similarly, the ERC32 BSP has startup code written in assembly language and C. |
---|
40 | However, this BSP shares this code with other SPARC BSPs. Thus the |
---|
41 | ``Makefile.am`` explicitly references the following files for this |
---|
42 | functionality. |
---|
43 | |
---|
44 | .. code:: c |
---|
45 | |
---|
46 | ../../sparc/shared/start.S |
---|
47 | |
---|
48 | .. note:: |
---|
49 | |
---|
50 | In most BSPs, the directory named ``start340`` in the gen68340 BSP would be |
---|
51 | simply named ``start`` or start followed by a BSP designation. |
---|
52 | |
---|
53 | Required Global Variables |
---|
54 | ========================= |
---|
55 | |
---|
56 | Although not strictly part of initialization, there are a few global variables |
---|
57 | assumed to exist by reusable device drivers. These global variables should |
---|
58 | only defined by the BSP when using one of these device drivers. |
---|
59 | |
---|
60 | The BSP author probably should be aware of the ``Configuration`` Table |
---|
61 | structure generated by ``<rtems/confdefs.h>`` during debug but should not |
---|
62 | explicitly reference it in the source code. There are helper routines provided |
---|
63 | by RTEMS to access individual fields. |
---|
64 | |
---|
65 | In older RTEMS versions, the BSP included a number of required global |
---|
66 | variables. We have made every attempt to eliminate these in the interest of |
---|
67 | simplicity. |
---|
68 | |
---|
69 | Board Initialization |
---|
70 | ==================== |
---|
71 | |
---|
72 | This section describes the steps an application goes through from the time the |
---|
73 | first BSP code is executed until the first application task executes. |
---|
74 | |
---|
75 | The initialization flows from assembly language start code to the shared |
---|
76 | ``bootcard.c`` framework then through the C Library, RTEMS, device driver |
---|
77 | initialization phases, and the context switch to the first application task. |
---|
78 | After this, the application executes until it calls ``exit``, |
---|
79 | ``rtems_shutdown_executive``, or some other normal termination initiating |
---|
80 | routine and a fatal system state is reached. The optional |
---|
81 | ``bsp_fatal_extension`` initial extension can perform BSP specific system |
---|
82 | termination. |
---|
83 | |
---|
84 | The routines invoked during this will be discussed and their location in the |
---|
85 | RTEMS source tree pointed out as we discuss each. |
---|
86 | |
---|
87 | Start Code - Assembly Language Initialization |
---|
88 | --------------------------------------------- |
---|
89 | |
---|
90 | The assembly language code in the directory ``start`` is the first part of the |
---|
91 | application to execute. It is responsible for initializing the processor and |
---|
92 | board enough to execute the rest of the BSP. This includes: |
---|
93 | |
---|
94 | - initializing the stack |
---|
95 | |
---|
96 | - zeroing out the uninitialized data section ``.bss`` |
---|
97 | |
---|
98 | - disabling external interrupts |
---|
99 | |
---|
100 | - copy the initialized data from ROM to RAM |
---|
101 | |
---|
102 | The general rule of thumb is that the start code in assembly should do the |
---|
103 | minimum necessary to allow C code to execute to complete the initialization |
---|
104 | sequence. |
---|
105 | |
---|
106 | The initial assembly language start code completes its execution by invoking |
---|
107 | the shared routine ``boot_card()``. |
---|
108 | |
---|
109 | The label (symbolic name) associated with the starting address of the program |
---|
110 | is typically called ``start``. The start object file is the first object file |
---|
111 | linked into the program image so it is ensured that the start code is at offset |
---|
112 | 0 in the ``.text`` section. It is the responsibility of the linker script in |
---|
113 | conjunction with the compiler specifications file to put the start code in the |
---|
114 | correct location in the application image. |
---|
115 | |
---|
116 | boot_card() - Boot the Card |
---|
117 | --------------------------- |
---|
118 | |
---|
119 | The ``boot_card()`` is the first C code invoked. This file is the core |
---|
120 | component in the RTEMS BSP Initialization Framework and provides the proper |
---|
121 | sequencing of initialization steps for the BSP, RTEMS and device drivers. All |
---|
122 | BSPs use the same shared version of ``boot_card()`` which is located in the |
---|
123 | following file: |
---|
124 | |
---|
125 | .. code:: c |
---|
126 | |
---|
127 | c/src/lib/libbsp/shared/bootcard.c |
---|
128 | |
---|
129 | The ``boot_card()`` routine performs the following functions: |
---|
130 | |
---|
131 | - It disables processor interrupts. |
---|
132 | |
---|
133 | - It sets the command line argument variables |
---|
134 | for later use by the application. |
---|
135 | |
---|
136 | - It invokes the BSP specific routine ``bsp_work_area_initialize()`` which is |
---|
137 | supposed to initialize the RTEMS Workspace and the C Program Heap. Usually |
---|
138 | the default implementation in ``c/src/lib/libbsp/shared/bspgetworkarea.c`` |
---|
139 | should be sufficient. Custom implementations can use |
---|
140 | ``bsp_work_area_initialize_default()`` or |
---|
141 | ``bsp_work_area_initialize_with_table()`` available as inline functions |
---|
142 | from``#include <bsp/bootcard.h>``. |
---|
143 | |
---|
144 | - It invokes the BSP specific routine ``bsp_start()`` which is written in C and |
---|
145 | thus able to perform more advanced initialization. Often MMU, bus and |
---|
146 | interrupt controller initialization occurs here. Since the RTEMS Workspace |
---|
147 | and the C Program Heap was already initialized by |
---|
148 | ``bsp_work_area_initialize()``, this routine may use ``malloc()``, etc. |
---|
149 | |
---|
150 | - It invokes the RTEMS directive ``rtems_initialize_data_structures()`` to |
---|
151 | initialize the RTEMS executive to a state where objects can be created but |
---|
152 | tasking is not enabled. |
---|
153 | |
---|
154 | - It invokes the BSP specific routine ``bsp_libc_init()`` to initialize the C |
---|
155 | Library. Usually the default implementation in |
---|
156 | ``c/src/lib/libbsp/shared/bsplibc.c`` should be sufficient. |
---|
157 | |
---|
158 | - It invokes the RTEMS directive ``rtems_initialize_before_drivers()`` to |
---|
159 | initialize the MPCI Server thread in a multiprocessor configuration and |
---|
160 | execute API specific extensions. |
---|
161 | |
---|
162 | - It invokes the BSP specific routine ``bsp_predriver_hook``. For most BSPs, |
---|
163 | the implementation of this routine does nothing. |
---|
164 | |
---|
165 | - It invokes the RTEMS directive ``rtems_initialize_device_drivers()`` to |
---|
166 | initialize the statically configured set of device drivers in the order they |
---|
167 | were specified in the Configuration Table. |
---|
168 | |
---|
169 | - It invokes the BSP specific routine ``bsp_postdriver_hook``. For |
---|
170 | most BSPs, the implementation of this routine does nothing. However, some |
---|
171 | BSPs use this hook and perform some initialization which must be done at |
---|
172 | this point in the initialization sequence. This is the last opportunity |
---|
173 | for the BSP to insert BSP specific code into the initialization sequence. |
---|
174 | |
---|
175 | - It invokes the RTEMS directive ``rtems_initialize_start_multitasking()`` |
---|
176 | which initiates multitasking and performs a context switch to the first user |
---|
177 | application task and may enable interrupts as a side-effect of that context |
---|
178 | switch. The context switch saves the executing context. The application |
---|
179 | runs now. The directive ``rtems_shutdown_executive()`` will return to the |
---|
180 | saved context. The ``exit()`` function will use this directive. After a |
---|
181 | return to the saved context a fatal system state is reached. The fatal |
---|
182 | source is ``RTEMS_FATAL_SOURCE_EXIT`` with a fatal code set to the value |
---|
183 | passed to rtems_shutdown_executive(). The enabling of interrupts during the |
---|
184 | first context switch is often the source for fatal errors during BSP |
---|
185 | development because the BSP did not clear and/or disable all interrupt |
---|
186 | sources and a spurious interrupt will occur. When in the context of the |
---|
187 | first task but before its body has been entered, any C++ Global Constructors |
---|
188 | will be invoked. |
---|
189 | |
---|
190 | That's it. We just went through the entire sequence. |
---|
191 | |
---|
192 | bsp_work_area_initialize() - BSP Specific Work Area Initialization |
---|
193 | ------------------------------------------------------------------ |
---|
194 | |
---|
195 | This is the first BSP specific C routine to execute during system |
---|
196 | initialization. It must initialize the support for allocating memory from the |
---|
197 | C Program Heap and RTEMS Workspace commonly referred to as the work areas. |
---|
198 | Many BSPs place the work areas at the end of RAM although this is certainly not |
---|
199 | a requirement. Usually the default implementation |
---|
200 | in:file:`c/src/lib/libbsp/shared/bspgetworkarea.c` should be sufficient. |
---|
201 | Custom implementations can use ``bsp_work_area_initialize_default()`` |
---|
202 | or``bsp_work_area_initialize_with_table()`` available as inline functions from |
---|
203 | ``#include <bsp/bootcard.h>``. |
---|
204 | |
---|
205 | bsp_start() - BSP Specific Initialization |
---|
206 | ----------------------------------------- |
---|
207 | |
---|
208 | This is the second BSP specific C routine to execute during system |
---|
209 | initialization. It is called right after ``bsp_work_area_initialize()``. The |
---|
210 | ``bsp_start()`` routine often performs required fundamental hardware |
---|
211 | initialization such as setting bus controller registers that do not have a |
---|
212 | direct impact on whether or not C code can execute. The interrupt controllers |
---|
213 | are usually initialized here. The source code for this routine is usually |
---|
214 | found in the file :file:`c/src/lib/libbsp/${CPU}/${BSP}/startup/bspstart.c`. |
---|
215 | It is not allowed to create any operating system objects, e.g. RTEMS |
---|
216 | semaphores. |
---|
217 | |
---|
218 | After completing execution, this routine returns to the ``boot_card()`` |
---|
219 | routine. In case of errors, the initialization should be terminated via |
---|
220 | ``bsp_fatal()``. |
---|
221 | |
---|
222 | bsp_predriver_hook() - BSP Specific Predriver Hook |
---|
223 | -------------------------------------------------- |
---|
224 | |
---|
225 | The ``bsp_predriver_hook()`` method is the BSP specific routine that is invoked |
---|
226 | immediately before the the device drivers are initialized. RTEMS initialization |
---|
227 | is complete but interrupts and tasking are disabled. |
---|
228 | |
---|
229 | The BSP may use the shared version of this routine which is empty. Most BSPs |
---|
230 | do not provide a specific implementation of this callback. |
---|
231 | |
---|
232 | Device Driver Initialization |
---|
233 | ---------------------------- |
---|
234 | |
---|
235 | At this point in the initialization sequence, the initialization routines for |
---|
236 | all of the device drivers specified in the Device Driver Table are invoked. |
---|
237 | The initialization routines are invoked in the order they appear in the Device |
---|
238 | Driver Table. |
---|
239 | |
---|
240 | The Driver Address Table is part of the RTEMS Configuration Table. It defines |
---|
241 | device drivers entry points (initialization, open, close, read, write, and |
---|
242 | control). For more information about this table, please refer to the |
---|
243 | *Configuring a System* chapter in the *RTEMS Application C User's Guide*. |
---|
244 | |
---|
245 | The RTEMS initialization procedure calls the initialization function for every |
---|
246 | driver defined in the RTEMS Configuration Table (this allows one to include |
---|
247 | only the drivers needed by the application). |
---|
248 | |
---|
249 | All these primitives have a major and a minor number as arguments: |
---|
250 | |
---|
251 | - the major number refers to the driver type, |
---|
252 | |
---|
253 | - the minor number is used to control two peripherals with the same driver (for |
---|
254 | instance, we define only one major number for the serial driver, but two |
---|
255 | minor numbers for channel A and B if there are two channels in the UART). |
---|
256 | |
---|
257 | RTEMS Postdriver Callback |
---|
258 | ------------------------- |
---|
259 | |
---|
260 | The ``bsp_postdriver_hook()`` BSP specific routine is invoked immediately after |
---|
261 | the the device drivers and MPCI are initialized. Interrupts and tasking are |
---|
262 | disabled. |
---|
263 | |
---|
264 | Most BSPs use the shared implementation of this routine which is responsible |
---|
265 | for opening the device ``/dev/console`` for standard input, output and error if |
---|
266 | the application has configured the Console Device Driver. This file is located |
---|
267 | at: |
---|
268 | |
---|
269 | .. code:: c |
---|
270 | |
---|
271 | c/src/lib/libbsp/shared/bsppost.c |
---|
272 | |
---|
273 | The Interrupt Vector Table |
---|
274 | ========================== |
---|
275 | |
---|
276 | The Interrupt Vector Table is called different things on different processor |
---|
277 | families but the basic functionality is the same. Each entry in the Table |
---|
278 | corresponds to the handler routine for a particular interrupt source. When an |
---|
279 | interrupt from that source occurs, the specified handler routine is invoked. |
---|
280 | Some context information is saved by the processor automatically when this |
---|
281 | happens. RTEMS saves enough context information so that an interrupt service |
---|
282 | routine can be implemented in a high level language. |
---|
283 | |
---|
284 | On some processors, the Interrupt Vector Table is at a fixed address. If this |
---|
285 | address is in RAM, then usually the BSP only has to initialize it to contain |
---|
286 | pointers to default handlers. If the table is in ROM, then the application |
---|
287 | developer will have to take special steps to fill in the table. |
---|
288 | |
---|
289 | If the base address of the Interrupt Vector Table can be dynamically changed to |
---|
290 | an arbitrary address, then the RTEMS port to that processor family will usually |
---|
291 | allocate its own table and install it. For example, on some members of the |
---|
292 | Motorola MC68xxx family, the Vector Base Register (``vbr``) contains this base |
---|
293 | address. |
---|
294 | |
---|
295 | Interrupt Vector Table on the gen68340 BSP |
---|
296 | ------------------------------------------ |
---|
297 | |
---|
298 | The gen68340 BSP provides a default Interrupt Vector Table in the file |
---|
299 | ``$BSP_ROOT/start340/start340.s``. After the ``entry`` label is the definition |
---|
300 | of space reserved for the table of interrupts vectors. This space is assigned |
---|
301 | the symbolic name of ``__uhoh`` in the ``gen68340`` BSP. |
---|
302 | |
---|
303 | At ``__uhoh`` label is the default interrupt handler routine. This routine is |
---|
304 | only called when an unexpected interrupts is raised. One can add their own |
---|
305 | routine there (in that case there's a call to a routine - |
---|
306 | $BSP_ROOT/startup/dumpanic.c - that prints which address caused the interrupt |
---|
307 | and the contents of the registers, stack, etc.), but this should not return. |
---|
308 | |
---|
309 | Chip Select Initialization |
---|
310 | ========================== |
---|
311 | |
---|
312 | When the microprocessor accesses a memory area, address decoding is handled by |
---|
313 | an address decoder, so that the microprocessor knows which memory chip(s) to |
---|
314 | access. The following figure illustrates this: |
---|
315 | |
---|
316 | .. code:: |
---|
317 | |
---|
318 | +-------------------+ |
---|
319 | ------------| | |
---|
320 | ------------| |------------ |
---|
321 | ------------| Address |------------ |
---|
322 | ------------| Decoder |------------ |
---|
323 | ------------| |------------ |
---|
324 | ------------| | |
---|
325 | +-------------------+ |
---|
326 | CPU Bus Chip Select |
---|
327 | |
---|
328 | The Chip Select registers must be programmed such that they match the |
---|
329 | ``linkcmds`` settings. In the gen68340 BSP, ROM and RAM addresses can be found |
---|
330 | in both the ``linkcmds`` and initialization code, but this is not a great way |
---|
331 | to do this. It is better to define addresses in the linker script. |
---|
332 | |
---|
333 | Integrated Processor Registers Initialization |
---|
334 | ============================================= |
---|
335 | |
---|
336 | The CPUs used in many embedded systems are highly complex devices with multiple |
---|
337 | peripherals on the CPU itself. For these devices, there are always some |
---|
338 | specific integrated processor registers that must be initialized. Refer to the |
---|
339 | processors' manuals for details on these registers and be VERY careful |
---|
340 | programming them. |
---|
341 | |
---|
342 | Data Section Recopy |
---|
343 | =================== |
---|
344 | |
---|
345 | The next initialization part can be found in |
---|
346 | ``$BSP340_ROOT/start340/init68340.c``. First the Interrupt Vector Table is |
---|
347 | copied into RAM, then the data section recopy is initiated |
---|
348 | (``_CopyDataClearBSSAndStart`` in ``$BSP340_ROOT/start340/startfor340only.s``). |
---|
349 | |
---|
350 | This code performs the following actions: |
---|
351 | |
---|
352 | - copies the .data section from ROM to its location reserved in RAM (see |
---|
353 | `Initialized Data`_ for more details about this copy), |
---|
354 | |
---|
355 | - clear ``.bss`` section (all the non-initialized data will take value 0). |
---|
356 | |
---|
357 | The RTEMS Configuration Table |
---|
358 | ============================= |
---|
359 | |
---|
360 | The RTEMS configuration table contains the maximum number of objects RTEMS can |
---|
361 | handle during the application (e.g. maximum number of tasks, semaphores, |
---|
362 | etc.). It's used to allocate the size for the RTEMS inner data structures. |
---|
363 | |
---|
364 | The RTEMS configuration table is application dependent, which means that one |
---|
365 | has to provide one per application. It is usually defined by defining macros |
---|
366 | and including the header file ``<rtems/confdefs.h>``. In simple applications |
---|
367 | such as the tests provided with RTEMS, it is commonly found in the main module |
---|
368 | of the application. For more complex applications, it may be in a file by |
---|
369 | itself. |
---|
370 | |
---|
371 | The header file ``<rtems/confdefs.h>`` defines a constant table named |
---|
372 | ``Configuration``. With RTEMS 4.8 and older, it was accepted practice for the |
---|
373 | BSP to copy this table into a modifiable copy named ``BSP_Configuration``. |
---|
374 | This copy of the table was modified to define the base address of the RTEMS |
---|
375 | Executive Workspace as well as to reflect any BSP and device driver |
---|
376 | requirements not automatically handled by the application. In 4.9 and newer, |
---|
377 | we have eliminated the BSP copies of the configuration tables and are making |
---|
378 | efforts to make the configuration information generated by |
---|
379 | ``<rtems/confdefs.h>`` constant and read only. |
---|
380 | |
---|
381 | For more information on the RTEMS Configuration Table, refer to the *RTEMS |
---|
382 | Application C User's Guide*. |
---|