of ``bl31_params``. The ``bl_params`` structure is based on the convention
described in AArch64 BL31 cold boot interface section.
Required CPU state for warm boot initialization
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
When requesting a CPU power-on, or suspending a running CPU, AArch32 EL3
Runtime Software must ensure execution of a warm boot initialization entrypoint.
If ARM Trusted Firmware BL1 is used and the PROGRAMMABLE\_RESET\_ADDRESS build
flag is false, then AArch32 EL3 Runtime Software must ensure that BL1 branches
to the warm boot entrypoint by arranging for the BL1 platform function,
plat\_get\_my\_entrypoint(), to return a non-zero value.
In this case, the warm boot entrypoint must be in AArch32 EL3, little-endian
data access and all interrupt sources masked:
::
PSTATE.AIF = 0x7
SCTLR.EE = 0
The warm boot entrypoint may be implemented by using the ARM Trusted Firmware
``psci_warmboot_entrypoint()`` function. In that case, the platform must fulfil
the pre-requisites mentioned in the `PSCI Library integration guide`_.
EL3 runtime services framework
------------------------------
Software executing in the non-secure state and in the secure state at exception
levels lower than EL3 will request runtime services using the Secure Monitor
Call (SMC) instruction. These requests will follow the convention described in
the SMC Calling Convention PDD (`SMCCC`_). The `SMCCC`_ assigns function
identifiers to each SMC request and describes how arguments are passed and
returned.
The EL3 runtime services framework enables the development of services by
different providers that can be easily integrated into final product firmware.
The following sections describe the framework which facilitates the
registration, initialization and use of runtime services in EL3 Runtime
Software (BL31).
The design of the runtime services depends heavily on the concepts and
definitions described in the `SMCCC`_, in particular SMC Function IDs, Owning
Entity Numbers (OEN), Fast and Yielding calls, and the SMC32 and SMC64 calling
conventions. Please refer to that document for more detailed explanation of
these terms.
The following runtime services are expected to be implemented first. They have
not all been instantiated in the current implementation.
#. Standard service calls
This service is for management of the entire system. The Power State
Coordination Interface (`PSCI`_) is the first set of standard service calls
defined by ARM (see PSCI section later).
#. Secure-EL1 Payload Dispatcher service
If a system runs a Trusted OS or other Secure-EL1 Payload (SP) then
it also requires a *Secure Monitor* at EL3 to switch the EL1 processor
context between the normal world (EL1/EL2) and trusted world (Secure-EL1).
The Secure Monitor will make these world switches in response to SMCs. The
`SMCCC`_ provides for such SMCs with the Trusted OS Call and Trusted
Application Call OEN ranges.
The interface between the EL3 Runtime Software and the Secure-EL1 Payload is
not defined by the `SMCCC`_ or any other standard. As a result, each
Secure-EL1 Payload requires a specific Secure Monitor that runs as a runtime
service - within ARM Trusted Firmware this service is referred to as the
Secure-EL1 Payload Dispatcher (SPD).
ARM Trusted Firmware provides a Test Secure-EL1 Payload (TSP) and its
associated Dispatcher (TSPD). Details of SPD design and TSP/TSPD operation
are described in the "Secure-EL1 Payloads and Dispatchers" section below.
#. CPU implementation service
This service will provide an interface to CPU implementation specific
services for a given platform e.g. access to processor errata workarounds.
This service is currently unimplemented.
Additional services for ARM Architecture, SiP and OEM calls can be implemented.
Each implemented service handles a range of SMC function identifiers as
described in the `SMCCC`_.
Registration
~~~~~~~~~~~~
A runtime service is registered using the ``DECLARE_RT_SVC()`` macro, specifying
the name of the service, the range of OENs covered, the type of service and
initialization and call handler functions. This macro instantiates a ``const struct rt_svc_desc`` for the service with these details (see ``runtime_svc.h``).
This structure is allocated in a special ELF section ``rt_svc_descs``, enabling
the framework to find all service descriptors included into BL31.
The specific service for a SMC Function is selected based on the OEN and call
type of the Function ID, and the framework uses that information in the service
descriptor to identify the handler for the SMC Call.
The service descriptors do not include information to identify the precise set
of SMC function identifiers supported by this service implementation, the
security state from which such calls are valid nor the capability to support
64-bit and/or 32-bit callers (using SMC32 or SMC64). Responding appropriately
to these aspects of a SMC call is the responsibility of the service
implementation, the framework is focused on integration of services from
different providers and minimizing the time taken by the framework before the
service handler is invoked.
Details of the parameters, requirements and behavior of the initialization and
call handling functions are provided in the following sections.
Initialization
~~~~~~~~~~~~~~
``runtime_svc_init()`` in ``runtime_svc.c`` initializes the runtime services
framework running on the primary CPU during cold boot as part of the BL31
initialization. This happens prior to initializing a Trusted OS and running
Normal world boot firmware that might in turn use these services.
Initialization involves validating each of the declared runtime service
descriptors, calling the service initialization function and populating the
index used for runtime lookup of the service.
The BL31 linker script collects all of the declared service descriptors into a
single array and defines symbols that allow the framework to locate and traverse
the array, and determine its size.
The framework does basic validation of each descriptor to halt firmware
initialization if service declaration errors are detected. The framework does
not check descriptors for the following error conditions, and may behave in an
unpredictable manner under such scenarios:
#. Overlapping OEN ranges
#. Multiple descriptors for the same range of OENs and ``call_type``
#. Incorrect range of owning entity numbers for a given ``call_type``
Once validated, the service ``init()`` callback is invoked. This function carries
out any essential EL3 initialization before servicing requests. The ``init()``
function is only invoked on the primary CPU during cold boot. If the service
uses per-CPU data this must either be initialized for all CPUs during this call,
or be done lazily when a CPU first issues an SMC call to that service. If
``init()`` returns anything other than ``0``, this is treated as an initialization
error and the service is ignored: this does not cause the firmware to halt.
The OEN and call type fields present in the SMC Function ID cover a total of
128 distinct services, but in practice a single descriptor can cover a range of
OENs, e.g. SMCs to call a Trusted OS function. To optimize the lookup of a
service handler, the framework uses an array of 128 indices that map every
distinct OEN/call-type combination either to one of the declared services or to
indicate the service is not handled. This ``rt_svc_descs_indices[]`` array is
populated for all of the OENs covered by a service after the service ``init()``
function has reported success. So a service that fails to initialize will never
have it's ``handle()`` function invoked.
The following figure shows how the ``rt_svc_descs_indices[]`` index maps the SMC
Function ID call type and OEN onto a specific service handler in the
``rt_svc_descs[]`` array.
|Image 1|
Handling an SMC
~~~~~~~~~~~~~~~
When the EL3 runtime services framework receives a Secure Monitor Call, the SMC
Function ID is passed in W0 from the lower exception level (as per the
`SMCCC`_). If the calling register width is AArch32, it is invalid to invoke an
SMC Function which indicates the SMC64 calling convention: such calls are
ignored and return the Unknown SMC Function Identifier result code ``0xFFFFFFFF``
in R0/X0.
Bit[31] (fast/yielding call) and bits[29:24] (owning entity number) of the SMC
Function ID are combined to index into the ``rt_svc_descs_indices[]`` array. The
resulting value might indicate a service that has no handler, in this case the
framework will also report an Unknown SMC Function ID. Otherwise, the value is
used as a further index into the ``rt_svc_descs[]`` array to locate the required
service and handler.
The service's ``handle()`` callback is provided with five of the SMC parameters
directly, the others are saved into memory for retrieval (if needed) by the
handler. The handler is also provided with an opaque ``handle`` for use with the
supporting library for parameter retrieval, setting return values and context
manipulation; and with ``flags`` indicating the security state of the caller. The
framework finally sets up the execution stack for the handler, and invokes the
services ``handle()`` function.
On return from the handler the result registers are populated in X0-X3 before
restoring the stack and CPU state and returning from the original SMC.
Power State Coordination Interface
----------------------------------
TODO: Provide design walkthrough of PSCI implementation.
The PSCI v1.0 specification categorizes APIs as optional and mandatory. All the
mandatory APIs in PSCI v1.0 and all the APIs in PSCI v0.2 draft specification
`Power State Coordination Interface PDD`_ are implemented. The table lists
the PSCI v1.0 APIs and their support in generic code.
An API implementation might have a dependency on platform code e.g. CPU\_SUSPEND
requires the platform to export a part of the implementation. Hence the level
of support of the mandatory APIs depends upon the support exported by the
platform port as well. The Juno and FVP (all variants) platforms export all the
which returns a reference to the ``entry_point_info`` structure corresponding to
the image which will be run in the specified security state. The SPD uses this
API to get entry point information for the SECURE image, BL32.
In the absence of a BL32 image, BL31 passes control to the normal world
bootloader image (BL33). When the BL32 image is present, it is typical
that the SPD wants control to be passed to BL32 first and then later to BL33.
To do this the SPD has to register a BL32 initialization function during
initialization of the SPD service. The BL32 initialization function has this
prototype:
..code:: c
int32_t init(void);
and is registered using the ``bl31_register_bl32_init()`` function.
Trusted Firmware supports two approaches for the SPD to pass control to BL32
before returning through EL3 and running the non-trusted firmware (BL33):
#. In the BL32 setup function, use ``bl31_set_next_image_type()`` to
request that the exit from ``bl31_main()`` is to the BL32 entrypoint in
Secure-EL1. BL31 will exit to BL32 using the asynchronous method by
calling ``bl31_prepare_next_image_entry()`` and ``el3_exit()``.
When the BL32 has completed initialization at Secure-EL1, it returns to
BL31 by issuing an SMC, using a Function ID allocated to the SPD. On
receipt of this SMC, the SPD service handler should switch the CPU context
from trusted to normal world and use the ``bl31_set_next_image_type()`` and
``bl31_prepare_next_image_entry()`` functions to set up the initial return to
the normal world firmware BL33. On return from the handler the framework
will exit to EL2 and run BL33.
#. The BL32 setup function registers an initialization function using
``bl31_register_bl32_init()`` which provides a SPD-defined mechanism to
invoke a 'world-switch synchronous call' to Secure-EL1 to run the BL32
entrypoint.
NOTE: The Test SPD service included with the Trusted Firmware provides one
implementation of such a mechanism.
On completion BL32 returns control to BL31 via a SMC, and on receipt the
SPD service handler invokes the synchronous call return mechanism to return
to the BL32 initialization function. On return from this function,
``bl31_main()`` will set up the return to the normal world firmware BL33 and
continue the boot process in the normal world.
#. .. rubric:: Crash Reporting in BL31
:name:crash-reporting-in-bl31
BL31 implements a scheme for reporting the processor state when an unhandled
exception is encountered. The reporting mechanism attempts to preserve all the
register contents and report it via a dedicated UART (PL011 console). BL31
reports the general purpose, EL3, Secure EL1 and some EL2 state registers.
A dedicated per-CPU crash stack is maintained by BL31 and this is retrieved via
the per-CPU pointer cache. The implementation attempts to minimise the memory
required for this feature. The file ``crash_reporting.S`` contains the
implementation for crash reporting.
The sample crash output is shown below.
::
x0 :0x000000004F00007C
x1 :0x0000000007FFFFFF
x2 :0x0000000004014D50
x3 :0x0000000000000000
x4 :0x0000000088007998
x5 :0x00000000001343AC
x6 :0x0000000000000016
x7 :0x00000000000B8A38
x8 :0x00000000001343AC
x9 :0x00000000000101A8
x10 :0x0000000000000002
x11 :0x000000000000011C
x12 :0x00000000FEFDC644
x13 :0x00000000FED93FFC
x14 :0x0000000000247950
x15 :0x00000000000007A2
x16 :0x00000000000007A4
x17 :0x0000000000247950
x18 :0x0000000000000000
x19 :0x00000000FFFFFFFF
x20 :0x0000000004014D50
x21 :0x000000000400A38C
x22 :0x0000000000247950
x23 :0x0000000000000010
x24 :0x0000000000000024
x25 :0x00000000FEFDC868
x26 :0x00000000FEFDC86A
x27 :0x00000000019EDEDC
x28 :0x000000000A7CFDAA
x29 :0x0000000004010780
x30 :0x000000000400F004
scr_el3 :0x0000000000000D3D
sctlr_el3 :0x0000000000C8181F
cptr_el3 :0x0000000000000000
tcr_el3 :0x0000000080803520
daif :0x00000000000003C0
mair_el3 :0x00000000000004FF
spsr_el3 :0x00000000800003CC
elr_el3 :0x000000000400C0CC
ttbr0_el3 :0x00000000040172A0
esr_el3 :0x0000000096000210
sp_el3 :0x0000000004014D50
far_el3 :0x000000004F00007C
spsr_el1 :0x0000000000000000
elr_el1 :0x0000000000000000
spsr_abt :0x0000000000000000
spsr_und :0x0000000000000000
spsr_irq :0x0000000000000000
spsr_fiq :0x0000000000000000
sctlr_el1 :0x0000000030C81807
actlr_el1 :0x0000000000000000
cpacr_el1 :0x0000000000300000
csselr_el1 :0x0000000000000002
sp_el1 :0x0000000004028800
esr_el1 :0x0000000000000000
ttbr0_el1 :0x000000000402C200
ttbr1_el1 :0x0000000000000000
mair_el1 :0x00000000000004FF
amair_el1 :0x0000000000000000
tcr_el1 :0x0000000000003520
tpidr_el1 :0x0000000000000000
tpidr_el0 :0x0000000000000000
tpidrro_el0 :0x0000000000000000
dacr32_el2 :0x0000000000000000
ifsr32_el2 :0x0000000000000000
par_el1 :0x0000000000000000
far_el1 :0x0000000000000000
afsr0_el1 :0x0000000000000000
afsr1_el1 :0x0000000000000000
contextidr_el1 :0x0000000000000000
vbar_el1 :0x0000000004027000
cntp_ctl_el0 :0x0000000000000000
cntp_cval_el0 :0x0000000000000000
cntv_ctl_el0 :0x0000000000000000
cntv_cval_el0 :0x0000000000000000
cntkctl_el1 :0x0000000000000000
fpexc32_el2 :0x0000000004000700
sp_el0 :0x0000000004010780
Guidelines for Reset Handlers
-----------------------------
Trusted Firmware implements a framework that allows CPU and platform ports to
perform actions very early after a CPU is released from reset in both the cold
and warm boot paths. This is done by calling the ``reset_handler()`` function in
both the BL1 and BL31 images. It in turn calls the platform and CPU specific
reset handling functions.
Details for implementing a CPU specific reset handler can be found in
Section 8. Details for implementing a platform specific reset handler can be
found in the `Porting Guide`_ (see the ``plat_reset_handler()`` function).
When adding functionality to a reset handler, keep in mind that if a different
reset handling behavior is required between the first and the subsequent
invocations of the reset handling code, this should be detected at runtime.
In other words, the reset handler should be able to detect whether an action has
already been performed and act as appropriate. Possible courses of actions are,
e.g. skip the action the second time, or undo/redo it.
CPU specific operations framework
---------------------------------
Certain aspects of the ARMv8 architecture are implementation defined,
that is, certain behaviours are not architecturally defined, but must be defined
and documented by individual processor implementations. The ARM Trusted
Firmware implements a framework which categorises the common implementation
defined behaviours and allows a processor to export its implementation of that
behaviour. The categories are:
#. Processor specific reset sequence.
#. Processor specific power down sequences.
#. Processor specific register dumping as a part of crash reporting.
#. Errata status reporting.
Each of the above categories fulfils a different requirement.
#. allows any processor specific initialization before the caches and MMU
are turned on, like implementation of errata workarounds, entry into
the intra-cluster coherency domain etc.
#. allows each processor to implement the power down sequence mandated in
its Technical Reference Manual (TRM).
#. allows a processor to provide additional information to the developer
in the event of a crash, for example Cortex-A53 has registers which
can expose the data cache contents.
#. allows a processor to define a function that inspects and reports the status
of all errata workarounds on that processor.
Please note that only 2. is mandated by the TRM.
The CPU specific operations framework scales to accommodate a large number of
different CPUs during power down and reset handling. The platform can specify
any CPU optimization it wants to enable for each CPU. It can also specify
the CPU errata workarounds to be applied for each CPU type during reset
handling by defining CPU errata compile time macros. Details on these macros
can be found in the `cpu-specific-build-macros.rst`_ file.
The CPU specific operations framework depends on the ``cpu_ops`` structure which
needs to be exported for each type of CPU in the platform. It is defined in
``include/lib/cpus/aarch64/cpu_macros.S`` and has the following fields : ``midr``,
``reset_func()``, ``cpu_pwr_down_ops`` (array of power down functions) and
``cpu_reg_dump()``.
The CPU specific files in ``lib/cpus`` export a ``cpu_ops`` data structure with
suitable handlers for that CPU. For example, ``lib/cpus/aarch64/cortex_a53.S``
exports the ``cpu_ops`` for Cortex-A53 CPU. According to the platform
configuration, these CPU specific files must be included in the build by
the platform makefile. The generic CPU specific operations framework code exists
in ``lib/cpus/aarch64/cpu_helpers.S``.
CPU specific Reset Handling
~~~~~~~~~~~~~~~~~~~~~~~~~~~
After a reset, the state of the CPU when it calls generic reset handler is:
MMU turned off, both instruction and data caches turned off and not part
of any coherency domain.
The BL entrypoint code first invokes the ``plat_reset_handler()`` to allow
the platform to perform any system initialization required and any system
errata workarounds that needs to be applied. The ``get_cpu_ops_ptr()`` reads
the current CPU midr, finds the matching ``cpu_ops`` entry in the ``cpu_ops``
array and returns it. Note that only the part number and implementer fields
in midr are used to find the matching ``cpu_ops`` entry. The ``reset_func()`` in
the returned ``cpu_ops`` is then invoked which executes the required reset
handling for that CPU and also any errata workarounds enabled by the platform.
This function must preserve the values of general purpose registers x20 to x29.
Refer to Section "Guidelines for Reset Handlers" for general guidelines
regarding placement of code in a reset handler.
CPU specific power down sequence
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
During the BL31 initialization sequence, the pointer to the matching ``cpu_ops``
entry is stored in per-CPU data by ``init_cpu_ops()`` so that it can be quickly
retrieved during power down sequences.
Various CPU drivers register handlers to perform power down at certain power
levels for that specific CPU. The PSCI service, upon receiving a power down
request, determines the highest power level at which to execute power down
sequence for a particular CPU. It uses the ``prepare_cpu_pwr_dwn()`` function to
pick the right power down handler for the requested level. The function
retrieves ``cpu_ops`` pointer member of per-CPU data, and from that, further
retrieves ``cpu_pwr_down_ops`` array, and indexes into the required level. If the
requested power level is higher than what a CPU driver supports, the handler
registered for highest level is invoked.
At runtime the platform hooks for power down are invoked by the PSCI service to
perform platform specific operations during a power down sequence, for example
turning off CCI coherency during a cluster power down.
CPU specific register reporting during crash
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If the crash reporting is enabled in BL31, when a crash occurs, the crash
reporting framework calls ``do_cpu_reg_dump`` which retrieves the matching
``cpu_ops`` using ``get_cpu_ops_ptr()`` function. The ``cpu_reg_dump()`` in
``cpu_ops`` is invoked, which then returns the CPU specific register values to
be reported and a pointer to the ASCII list of register names in a format
expected by the crash reporting framework.
CPU errata status reporting
~~~~~~~~~~~~~~~~~~~~~~~~~~~
Errata workarounds for CPUs supported in ARM Trusted Firmware are applied during
both cold and warm boots, shortly after reset. Individual Errata workarounds are
enabled as build options. Some errata workarounds have potential run-time
implications; therefore some are enabled by default, others not. Platform ports
shall override build options to enable or disable errata as appropriate. The CPU
drivers take care of applying errata workarounds that are enabled and applicable
to a given CPU. Refer to the section titled *CPU Errata Workarounds* in `CPUBM`_
for more information.
Functions in CPU drivers that apply errata workaround must follow the
conventions listed below.
The errata workaround must be authored as two separate functions:
- One that checks for errata. This function must determine whether that errata
applies to the current CPU. Typically this involves matching the current
CPUs revision and variant against a value that's known to be affected by the
errata. If the function determines that the errata applies to this CPU, it
must return ``ERRATA_APPLIES``; otherwise, it must return
``ERRATA_NOT_APPLIES``. The utility functions ``cpu_get_rev_var`` and
``cpu_rev_var_ls`` functions may come in handy for this purpose.
For an errata identified as ``E``, the check function must be named
``check_errata_E``.
This function will be invoked at different times, both from assembly and from
C run time. Therefore it must follow AAPCS, and must not use stack.
- Another one that applies the errata workaround. This function would call the
check function described above, and applies errata workaround if required.
CPU drivers that apply errata workaround can optionally implement an assembly
function that report the status of errata workarounds pertaining to that CPU.
For a driver that registers the CPU, for example, ``cpux`` via. ``declare_cpu_ops``
macro, the errata reporting function, if it exists, must be named
``cpux_errata_report``. This function will always be called with MMU enabled; it
must follow AAPCS and may use stack.
In a debug build of ARM Trusted Firmware, on a CPU that comes out of reset, both
BL1 and the run time firmware (BL31 in AArch64, and BL32 in AArch32) will invoke
errata status reporting function, if one exists, for that type of CPU.
To report the status of each errata workaround, the function shall use the
assembler macro ``report_errata``, passing it:
- The build option that enables the errata;
- The name of the CPU: this must be the same identifier that CPU driver
registered itself with, using ``declare_cpu_ops``;
- And the errata identifier: the identifier must match what's used in the
errata's check function described above.
The errata status reporting function will be called once per CPU type/errata
combination during the software's active life time.
It's expected that whenever an errata workaround is submitted to ARM Trusted
Firmware, the errata reporting function is appropriately extended to report its
status as well.
Reporting the status of errata workaround is for informational purpose only; it
has no functional significance.
Memory layout of BL images
--------------------------
Each bootloader image can be divided in 2 parts:
- the static contents of the image. These are data actually stored in the
binary on the disk. In the ELF terminology, they are called ``PROGBITS``
sections;
- the run-time contents of the image. These are data that don't occupy any
space in the binary on the disk. The ELF binary just contains some
metadata indicating where these data will be stored at run-time and the
corresponding sections need to be allocated and initialized at run-time.
In the ELF terminology, they are called ``NOBITS`` sections.
All PROGBITS sections are grouped together at the beginning of the image,
followed by all NOBITS sections. This is true for all Trusted Firmware images
and it is governed by the linker scripts. This ensures that the raw binary
images are as small as possible. If a NOBITS section was inserted in between
PROGBITS sections then the resulting binary file would contain zero bytes in
place of this NOBITS section, making the image unnecessarily bigger. Smaller
images allow faster loading from the FIP to the main memory.
Linker scripts and symbols
~~~~~~~~~~~~~~~~~~~~~~~~~~
Each bootloader stage image layout is described by its own linker script. The
linker scripts export some symbols into the program symbol table. Their values
correspond to particular addresses. The trusted firmware code can refer to these
symbols to figure out the image memory layout.
Linker symbols follow the following naming convention in the trusted firmware.
-``__<SECTION>_START__``
Start address of a given section named ``<SECTION>``.
-``__<SECTION>_END__``
End address of a given section named ``<SECTION>``. If there is an alignment
constraint on the section's end address then ``__<SECTION>_END__`` corresponds
to the end address of the section's actual contents, rounded up to the right
boundary. Refer to the value of ``__<SECTION>_UNALIGNED_END__`` to know the
actual end address of the section's contents.
-``__<SECTION>_UNALIGNED_END__``
End address of a given section named ``<SECTION>`` without any padding or
rounding up due to some alignment constraint.
-``__<SECTION>_SIZE__``
Size (in bytes) of a given section named ``<SECTION>``. If there is an
alignment constraint on the section's end address then ``__<SECTION>_SIZE__``
corresponds to the size of the section's actual contents, rounded up to the
right boundary. In other words, ``__<SECTION>_SIZE__ = __<SECTION>_END__ - _<SECTION>_START__``. Refer to the value of ``__<SECTION>_UNALIGNED_SIZE__``
to know the actual size of the section's contents.
-``__<SECTION>_UNALIGNED_SIZE__``
Size (in bytes) of a given section named ``<SECTION>`` without any padding or
rounding up due to some alignment constraint. In other words,