[489740f] | 1 | .. comment SPDX-License-Identifier: CC-BY-SA-4.0 |
---|
| 2 | |
---|
[6d7a4d2] | 3 | .. COMMENT: COPYRIGHT (c) 1988-2008. |
---|
| 4 | .. COMMENT: On-Line Applications Research Corporation (OAR). |
---|
| 5 | .. COMMENT: All rights reserved. |
---|
| 6 | |
---|
[b350509] | 7 | Initialization Code |
---|
| 8 | ################### |
---|
| 9 | |
---|
| 10 | Introduction |
---|
| 11 | ============ |
---|
| 12 | |
---|
[d389819] | 13 | The initialization code is the first piece of code executed when there's a |
---|
[6d7a4d2] | 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. |
---|
[b350509] | 20 | |
---|
| 21 | Most of the examples in this chapter will be based on the SPARC/ERC32 and |
---|
[6d7a4d2] | 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 | |
---|
[f29b7c1c] | 26 | .. code-block:: shell |
---|
[b350509] | 27 | |
---|
| 28 | c/src/lib/libbsp/m68k/gen68340 |
---|
| 29 | c/src/lib/libbsp/sparc/erc32 |
---|
| 30 | |
---|
[6d7a4d2] | 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 | |
---|
[f29b7c1c] | 44 | .. code-block:: shell |
---|
[b350509] | 45 | |
---|
| 46 | ../../sparc/shared/start.S |
---|
| 47 | |
---|
[6d7a4d2] | 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. |
---|
[b350509] | 52 | |
---|
| 53 | Required Global Variables |
---|
| 54 | ========================= |
---|
| 55 | |
---|
[6d7a4d2] | 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. |
---|
[b350509] | 59 | |
---|
[6d7a4d2] | 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. |
---|
[b350509] | 64 | |
---|
| 65 | In older RTEMS versions, the BSP included a number of required global |
---|
[6d7a4d2] | 66 | variables. We have made every attempt to eliminate these in the interest of |
---|
| 67 | simplicity. |
---|
[b350509] | 68 | |
---|
| 69 | Board Initialization |
---|
| 70 | ==================== |
---|
| 71 | |
---|
[6d7a4d2] | 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. |
---|
[b350509] | 74 | |
---|
[6d7a4d2] | 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. |
---|
[b350509] | 83 | |
---|
[6d7a4d2] | 84 | The routines invoked during this will be discussed and their location in the |
---|
| 85 | RTEMS source tree pointed out as we discuss each. |
---|
[b350509] | 86 | |
---|
| 87 | Start Code - Assembly Language Initialization |
---|
| 88 | --------------------------------------------- |
---|
| 89 | |
---|
[6d7a4d2] | 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: |
---|
[b350509] | 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 | |
---|
[6d7a4d2] | 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. |
---|
[b350509] | 105 | |
---|
[6d7a4d2] | 106 | The initial assembly language start code completes its execution by invoking |
---|
| 107 | the shared routine ``boot_card()``. |
---|
[b350509] | 108 | |
---|
[6d7a4d2] | 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. |
---|
[b350509] | 115 | |
---|
| 116 | boot_card() - Boot the Card |
---|
| 117 | --------------------------- |
---|
| 118 | |
---|
[6d7a4d2] | 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 | |
---|
[f29b7c1c] | 125 | .. code-block:: shell |
---|
[b350509] | 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 | |
---|
[6d7a4d2] | 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>``. |
---|
[b350509] | 143 | |
---|
[6d7a4d2] | 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. |
---|
[b350509] | 149 | |
---|
[6d7a4d2] | 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. |
---|
[b350509] | 153 | |
---|
[6d7a4d2] | 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. |
---|
[b350509] | 157 | |
---|
[6d7a4d2] | 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. |
---|
[b350509] | 161 | |
---|
[6d7a4d2] | 162 | - It invokes the BSP specific routine ``bsp_predriver_hook``. For most BSPs, |
---|
| 163 | the implementation of this routine does nothing. |
---|
[b350509] | 164 | |
---|
[6d7a4d2] | 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. |
---|
[b350509] | 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 | |
---|
[6d7a4d2] | 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. |
---|
[b350509] | 189 | |
---|
[d389819] | 190 | That's it. We just went through the entire sequence. |
---|
[b350509] | 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 |
---|
[6d7a4d2] | 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>``. |
---|
[b350509] | 204 | |
---|
| 205 | bsp_start() - BSP Specific Initialization |
---|
| 206 | ----------------------------------------- |
---|
| 207 | |
---|
| 208 | This is the second BSP specific C routine to execute during system |
---|
[6d7a4d2] | 209 | initialization. It is called right after ``bsp_work_area_initialize()``. The |
---|
| 210 | ``bsp_start()`` routine often performs required fundamental hardware |
---|
[b350509] | 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()`` |
---|
[6d7a4d2] | 219 | routine. In case of errors, the initialization should be terminated via |
---|
| 220 | ``bsp_fatal()``. |
---|
[b350509] | 221 | |
---|
| 222 | bsp_predriver_hook() - BSP Specific Predriver Hook |
---|
| 223 | -------------------------------------------------- |
---|
| 224 | |
---|
[6d7a4d2] | 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. |
---|
[b350509] | 228 | |
---|
[6d7a4d2] | 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. |
---|
[b350509] | 231 | |
---|
| 232 | Device Driver Initialization |
---|
| 233 | ---------------------------- |
---|
| 234 | |
---|
[6d7a4d2] | 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. |
---|
[b350509] | 239 | |
---|
[6d7a4d2] | 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*. |
---|
[b350509] | 244 | |
---|
[6d7a4d2] | 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). |
---|
[b350509] | 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 | |
---|
[6d7a4d2] | 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). |
---|
[b350509] | 256 | |
---|
| 257 | RTEMS Postdriver Callback |
---|
| 258 | ------------------------- |
---|
| 259 | |
---|
[6d7a4d2] | 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: |
---|
[b350509] | 268 | |
---|
[f29b7c1c] | 269 | .. code-block:: shell |
---|
[b350509] | 270 | |
---|
| 271 | c/src/lib/libbsp/shared/bsppost.c |
---|
| 272 | |
---|
| 273 | The Interrupt Vector Table |
---|
| 274 | ========================== |
---|
| 275 | |
---|
[6d7a4d2] | 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. |
---|
[b350509] | 294 | |
---|
| 295 | Interrupt Vector Table on the gen68340 BSP |
---|
| 296 | ------------------------------------------ |
---|
| 297 | |
---|
[6d7a4d2] | 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. |
---|
[b350509] | 302 | |
---|
[6d7a4d2] | 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. |
---|
[b350509] | 308 | |
---|
| 309 | Chip Select Initialization |
---|
| 310 | ========================== |
---|
| 311 | |
---|
[6d7a4d2] | 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: |
---|
[b350509] | 315 | |
---|
[4e71fe2] | 316 | .. code-block:: c |
---|
| 317 | |
---|
| 318 | +-------------------+ |
---|
| 319 | ------------| | |
---|
| 320 | ------------| |------------ |
---|
| 321 | ------------| Address |------------ |
---|
| 322 | ------------| Decoder |------------ |
---|
| 323 | ------------| |------------ |
---|
| 324 | ------------| | |
---|
| 325 | +-------------------+ |
---|
| 326 | CPU Bus Chip Select |
---|
[b350509] | 327 | |
---|
[6d7a4d2] | 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. |
---|
[b350509] | 332 | |
---|
| 333 | Integrated Processor Registers Initialization |
---|
| 334 | ============================================= |
---|
| 335 | |
---|
[6d7a4d2] | 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. |
---|
[b350509] | 341 | |
---|
| 342 | Data Section Recopy |
---|
| 343 | =================== |
---|
| 344 | |
---|
[6d7a4d2] | 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``). |
---|
[b350509] | 349 | |
---|
| 350 | This code performs the following actions: |
---|
| 351 | |
---|
[6d7a4d2] | 352 | - copies the .data section from ROM to its location reserved in RAM (see |
---|
| 353 | `Initialized Data`_ for more details about this copy), |
---|
[b350509] | 354 | |
---|
[6d7a4d2] | 355 | - clear ``.bss`` section (all the non-initialized data will take value 0). |
---|
[b350509] | 356 | |
---|
| 357 | The RTEMS Configuration Table |
---|
| 358 | ============================= |
---|
| 359 | |
---|
[6d7a4d2] | 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*. |
---|