summaryrefslogtreecommitdiffstats
path: root/bsp-howto/initilization_code.rst
blob: a69731e2ba846bbdae940efe84ed7820e1807e75 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
.. comment SPDX-License-Identifier: CC-BY-SA-4.0

.. COMMENT: COPYRIGHT (c) 1988-2008.
.. COMMENT: On-Line Applications Research Corporation (OAR).
.. COMMENT: All rights reserved.

Initialization Code
###################

Introduction
============

The initialization code is the first piece of code executed when there's a
reset/reboot. Its purpose is to initialize the board for the application.  This
chapter contains a narrative description of the initialization process followed
by a description of each of the files and routines commonly found in the BSP
related to initialization.  The remainder of this chapter covers special issues
which require attention such as interrupt vector table and chip select
initialization.

Most of the examples in this chapter will be based on the SPARC/ERC32 and
m68k/gen68340 BSP initialization code.  Like most BSPs, the initialization for
these BSP is divided into two subdirectories under the BSP source directory.
The BSP source code for these BSPs is in the following directories:

.. code-block:: shell

    c/src/lib/libbsp/m68k/gen68340
    c/src/lib/libbsp/sparc/erc32

Both BSPs contain startup code written in assembly language and C.  The
gen68340 BSP has its early initialization start code in the ``start340``
subdirectory and its C startup code in the ``startup`` directory.  In the
``start340`` directory are two source files.  The file ``startfor340only.s`` is
the simpler of these files as it only has initialization code for a MC68340
board.  The file ``start340.s`` contains initialization for a 68349 based board
as well.

Similarly, the ERC32 BSP has startup code written in assembly language and C.
However, this BSP shares this code with other SPARC BSPs.  Thus the
``Makefile.am`` explicitly references the following files for this
functionality.

.. code-block:: shell

    ../../sparc/shared/start.S

.. note::

   In most BSPs, the directory named ``start340`` in the gen68340 BSP would be
   simply named ``start`` or start followed by a BSP designation.

Required Global Variables
=========================

Although not strictly part of initialization, there are a few global variables
assumed to exist by reusable device drivers.  These global variables should
only defined by the BSP when using one of these device drivers.

The BSP author probably should be aware of the ``Configuration`` Table
structure generated by ``<rtems/confdefs.h>`` during debug but should not
explicitly reference it in the source code.  There are helper routines provided
by RTEMS to access individual fields.

In older RTEMS versions, the BSP included a number of required global
variables.  We have made every attempt to eliminate these in the interest of
simplicity.

Board Initialization
====================

This section describes the steps an application goes through from the time the
first BSP code is executed until the first application task executes.

The initialization flows from assembly language start code to the shared
``bootcard.c`` framework then through the C Library, RTEMS, device driver
initialization phases, and the context switch to the first application task.
After this, the application executes until it calls ``exit``,
``rtems_shutdown_executive``, or some other normal termination initiating
routine and a fatal system state is reached.  The optional
``bsp_fatal_extension`` initial extension can perform BSP specific system
termination.

The routines invoked during this will be discussed and their location in the
RTEMS source tree pointed out as we discuss each.

Start Code - Assembly Language Initialization
---------------------------------------------

The assembly language code in the directory ``start`` is the first part of the
application to execute.  It is responsible for initializing the processor and
board enough to execute the rest of the BSP.  This includes:

- initializing the stack

- zeroing out the uninitialized data section ``.bss``

- disabling external interrupts

- copy the initialized data from ROM to RAM

The general rule of thumb is that the start code in assembly should do the
minimum necessary to allow C code to execute to complete the initialization
sequence.

The initial assembly language start code completes its execution by invoking
the shared routine ``boot_card()``.

The label (symbolic name) associated with the starting address of the program
is typically called ``start``.  The start object file is the first object file
linked into the program image so it is ensured that the start code is at offset
0 in the ``.text`` section.  It is the responsibility of the linker script in
conjunction with the compiler specifications file to put the start code in the
correct location in the application image.

boot_card() - Boot the Card
---------------------------

The ``boot_card()`` is the first C code invoked.  This file is the core
component in the RTEMS BSP Initialization Framework and provides the proper
sequencing of initialization steps for the BSP, RTEMS and device drivers. All
BSPs use the same shared version of ``boot_card()`` which is located in the
following file:

.. code-block:: shell

    c/src/lib/libbsp/shared/bootcard.c

The ``boot_card()`` routine performs the following functions:

- It disables processor interrupts.

- It sets the command line argument variables
  for later use by the application.

- It invokes the BSP specific routine ``bsp_work_area_initialize()`` which is
  supposed to initialize the RTEMS Workspace and the C Program Heap.  Usually
  the default implementation in ``c/src/lib/libbsp/shared/bspgetworkarea.c``
  should be sufficient.  Custom implementations can use
  ``bsp_work_area_initialize_default()`` or
  ``bsp_work_area_initialize_with_table()`` available as inline functions
  from``#include <bsp/bootcard.h>``.

- It invokes the BSP specific routine ``bsp_start()`` which is written in C and
  thus able to perform more advanced initialization.  Often MMU, bus and
  interrupt controller initialization occurs here.  Since the RTEMS Workspace
  and the C Program Heap was already initialized by
  ``bsp_work_area_initialize()``, this routine may use ``malloc()``, etc.

- It invokes the RTEMS directive ``rtems_initialize_data_structures()`` to
  initialize the RTEMS executive to a state where objects can be created but
  tasking is not enabled.

- It invokes the BSP specific routine ``bsp_libc_init()`` to initialize the C
  Library.  Usually the default implementation in
  ``c/src/lib/libbsp/shared/bsplibc.c`` should be sufficient.

- It invokes the RTEMS directive ``rtems_initialize_before_drivers()`` to
  initialize the MPCI Server thread in a multiprocessor configuration and
  execute API specific extensions.

- It invokes the BSP specific routine ``bsp_predriver_hook``. For most BSPs,
  the implementation of this routine does nothing.

- It invokes the RTEMS directive ``rtems_initialize_device_drivers()`` to
  initialize the statically configured set of device drivers in the order they
  were specified in the Configuration Table.

- It invokes the BSP specific routine ``bsp_postdriver_hook``. For
  most BSPs, the implementation of this routine does nothing.  However, some
  BSPs use this hook and perform some initialization which must be done at
  this point in the initialization sequence.  This is the last opportunity
  for the BSP to insert BSP specific code into the initialization sequence.

- It invokes the RTEMS directive ``rtems_initialize_start_multitasking()``
  which initiates multitasking and performs a context switch to the first user
  application task and may enable interrupts as a side-effect of that context
  switch.  The context switch saves the executing context.  The application
  runs now.  The directive ``rtems_shutdown_executive()`` will return to the
  saved context.  The ``exit()`` function will use this directive.  After a
  return to the saved context a fatal system state is reached.  The fatal
  source is ``RTEMS_FATAL_SOURCE_EXIT`` with a fatal code set to the value
  passed to rtems_shutdown_executive().  The enabling of interrupts during the
  first context switch is often the source for fatal errors during BSP
  development because the BSP did not clear and/or disable all interrupt
  sources and a spurious interrupt will occur.  When in the context of the
  first task but before its body has been entered, any C++ Global Constructors
  will be invoked.

That's it.  We just went through the entire sequence.

bsp_work_area_initialize() - BSP Specific Work Area Initialization
------------------------------------------------------------------

This is the first BSP specific C routine to execute during system
initialization.  It must initialize the support for allocating memory from the
C Program Heap and RTEMS Workspace commonly referred to as the work areas.
Many BSPs place the work areas at the end of RAM although this is certainly not
a requirement.  Usually the default implementation
in:file:`c/src/lib/libbsp/shared/bspgetworkarea.c` should be sufficient.
Custom implementations can use ``bsp_work_area_initialize_default()``
or``bsp_work_area_initialize_with_table()`` available as inline functions from
``#include <bsp/bootcard.h>``.

bsp_start() - BSP Specific Initialization
-----------------------------------------

This is the second BSP specific C routine to execute during system
initialization.  It is called right after ``bsp_work_area_initialize()``.  The
``bsp_start()`` routine often performs required fundamental hardware
initialization such as setting bus controller registers that do not have a
direct impact on whether or not C code can execute.  The interrupt controllers
are usually initialized here.  The source code for this routine is usually
found in the file :file:`c/src/lib/libbsp/${CPU}/${BSP}/startup/bspstart.c`.
It is not allowed to create any operating system objects, e.g. RTEMS
semaphores.

After completing execution, this routine returns to the ``boot_card()``
routine.  In case of errors, the initialization should be terminated via
``bsp_fatal()``.

bsp_predriver_hook() - BSP Specific Predriver Hook
--------------------------------------------------

The ``bsp_predriver_hook()`` method is the BSP specific routine that is invoked
immediately before the the device drivers are initialized. RTEMS initialization
is complete but interrupts and tasking are disabled.

The BSP may use the shared version of this routine which is empty.  Most BSPs
do not provide a specific implementation of this callback.

Device Driver Initialization
----------------------------

At this point in the initialization sequence, the initialization routines for
all of the device drivers specified in the Device Driver Table are invoked.
The initialization routines are invoked in the order they appear in the Device
Driver Table.

The Driver Address Table is part of the RTEMS Configuration Table. It defines
device drivers entry points (initialization, open, close, read, write, and
control). For more information about this table, please refer to the
*Configuring a System* chapter in the *RTEMS Application C User's Guide*.

The RTEMS initialization procedure calls the initialization function for every
driver defined in the RTEMS Configuration Table (this allows one to include
only the drivers needed by the application).

All these primitives have a major and a minor number as arguments:

- the major number refers to the driver type,

- the minor number is used to control two peripherals with the same driver (for
  instance, we define only one major number for the serial driver, but two
  minor numbers for channel A and B if there are two channels in the UART).

RTEMS Postdriver Callback
-------------------------

The ``bsp_postdriver_hook()`` BSP specific routine is invoked immediately after
the the device drivers and MPCI are initialized.  Interrupts and tasking are
disabled.

Most BSPs use the shared implementation of this routine which is responsible
for opening the device ``/dev/console`` for standard input, output and error if
the application has configured the Console Device Driver.  This file is located
at:

.. code-block:: shell

    c/src/lib/libbsp/shared/bsppost.c

The Interrupt Vector Table
==========================

The Interrupt Vector Table is called different things on different processor
families but the basic functionality is the same.  Each entry in the Table
corresponds to the handler routine for a particular interrupt source.  When an
interrupt from that source occurs, the specified handler routine is invoked.
Some context information is saved by the processor automatically when this
happens.  RTEMS saves enough context information so that an interrupt service
routine can be implemented in a high level language.

On some processors, the Interrupt Vector Table is at a fixed address.  If this
address is in RAM, then usually the BSP only has to initialize it to contain
pointers to default handlers.  If the table is in ROM, then the application
developer will have to take special steps to fill in the table.

If the base address of the Interrupt Vector Table can be dynamically changed to
an arbitrary address, then the RTEMS port to that processor family will usually
allocate its own table and install it.  For example, on some members of the
Motorola MC68xxx family, the Vector Base Register (``vbr``) contains this base
address.

Interrupt Vector Table on the gen68340 BSP
------------------------------------------

The gen68340 BSP provides a default Interrupt Vector Table in the file
``$BSP_ROOT/start340/start340.s``.  After the ``entry`` label is the definition
of space reserved for the table of interrupts vectors.  This space is assigned
the symbolic name of ``__uhoh`` in the ``gen68340`` BSP.

At ``__uhoh`` label is the default interrupt handler routine. This routine is
only called when an unexpected interrupts is raised.  One can add their own
routine there (in that case there's a call to a routine -
$BSP_ROOT/startup/dumpanic.c - that prints which address caused the interrupt
and the contents of the registers, stack, etc.), but this should not return.

Chip Select Initialization
==========================

When the microprocessor accesses a memory area, address decoding is handled by
an address decoder, so that the microprocessor knows which memory chip(s) to
access.  The following figure illustrates this:

.. code-block:: c

                +-------------------+
    ------------|                   |
    ------------|                   |------------
    ------------|      Address      |------------
    ------------|      Decoder      |------------
    ------------|                   |------------
    ------------|                   |
                +-------------------+
    CPU Bus                            Chip Select

The Chip Select registers must be programmed such that they match the
``linkcmds`` settings. In the gen68340 BSP, ROM and RAM addresses can be found
in both the ``linkcmds`` and initialization code, but this is not a great way
to do this.  It is better to define addresses in the linker script.

Integrated Processor Registers Initialization
=============================================

The CPUs used in many embedded systems are highly complex devices with multiple
peripherals on the CPU itself.  For these devices, there are always some
specific integrated processor registers that must be initialized.  Refer to the
processors' manuals for details on these registers and be VERY careful
programming them.

Data Section Recopy
===================

The next initialization part can be found in
``$BSP340_ROOT/start340/init68340.c``. First the Interrupt Vector Table is
copied into RAM, then the data section recopy is initiated
(``_CopyDataClearBSSAndStart`` in ``$BSP340_ROOT/start340/startfor340only.s``).

This code performs the following actions:

- copies the .data section from ROM to its location reserved in RAM (see
  :ref:`Initialized Data` for more details about this copy),

- clear ``.bss`` section (all the non-initialized data will take value 0).

The RTEMS Configuration Table
=============================

The RTEMS configuration table contains the maximum number of objects RTEMS can
handle during the application (e.g. maximum number of tasks, semaphores,
etc.). It's used to allocate the size for the RTEMS inner data structures.

The RTEMS configuration table is application dependent, which means that one
has to provide one per application. It is usually defined by defining macros
and including the header file ``<rtems/confdefs.h>``.  In simple applications
such as the tests provided with RTEMS, it is commonly found in the main module
of the application.  For more complex applications, it may be in a file by
itself.

The header file ``<rtems/confdefs.h>`` defines a constant table named
``Configuration``.  With RTEMS 4.8 and older, it was accepted practice for the
BSP to copy this table into a modifiable copy named ``BSP_Configuration``.
This copy of the table was modified to define the base address of the RTEMS
Executive Workspace as well as to reflect any BSP and device driver
requirements not automatically handled by the application.  In 4.9 and newer,
we have eliminated the BSP copies of the configuration tables and are making
efforts to make the configuration information generated by
``<rtems/confdefs.h>`` constant and read only.

For more information on the RTEMS Configuration Table, refer to the *RTEMS
Application C User's Guide*.