mirror of
https://github.com/ARM-software/arm-trusted-firmware.git
synced 2025-04-18 02:24:18 +00:00
Add EL3 runtime services and SPD documentation
1. Add design information on EL3 runtime services and Secure-EL1 Payload Dispatchers (SPD) to firmware-design.md. 2. Create new EL3 runtime service writer's guide (rt-svc-writers-guide.md) to ease creation of new runtime services. Change-Id: I670aeb5fc246e25c6e599a15139aac886a0074fd
This commit is contained in:
parent
247f60bcbc
commit
5e1e920075
3 changed files with 634 additions and 49 deletions
BIN
docs/diagrams/rt-svc-descs-layout.png
Normal file
BIN
docs/diagrams/rt-svc-descs-layout.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 76 KiB |
|
@ -4,11 +4,14 @@ ARM Trusted Firmware Design
|
||||||
Contents :
|
Contents :
|
||||||
|
|
||||||
1. Introduction
|
1. Introduction
|
||||||
2. Cold Boot
|
2. Cold boot
|
||||||
3. Memory layout on FVP platforms
|
3. EL3 runtime services framework
|
||||||
4. Firmware Image Package (FIP)
|
4. Power State Coordination Interface
|
||||||
5. Code Structure
|
5. Secure-EL1 Payloads and Dispatchers
|
||||||
6. References
|
6. Memory layout on FVP platforms
|
||||||
|
7. Firmware Image Package (FIP)
|
||||||
|
8. Code Structure
|
||||||
|
9. References
|
||||||
|
|
||||||
|
|
||||||
1. Introduction
|
1. Introduction
|
||||||
|
@ -29,7 +32,7 @@ instruction. The SMC instruction must be used as mandated by the [SMC Calling
|
||||||
Convention PDD][SMCCC] [3].
|
Convention PDD][SMCCC] [3].
|
||||||
|
|
||||||
|
|
||||||
2. Cold Boot
|
2. Cold boot
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
The cold boot path starts when the platform is physically turned on. One of
|
The cold boot path starts when the platform is physically turned on. One of
|
||||||
|
@ -334,59 +337,330 @@ memory address populated by BL2.
|
||||||
|
|
||||||
* Runtime services initialization:
|
* Runtime services initialization:
|
||||||
|
|
||||||
The only runtime service implemented by BL3-1 is PSCI. The complete PSCI API
|
The runtime service framework and its initialization is described in the
|
||||||
is not yet implemented. The following functions are currently implemented:
|
"EL3 runtime services framework" section below.
|
||||||
|
|
||||||
- `PSCI_VERSION`
|
Details about the PSCI service are provided in the "Power State Coordination
|
||||||
- `CPU_OFF`
|
Interface" section below.
|
||||||
- `CPU_ON`
|
|
||||||
- `CPU_SUSPEND`
|
|
||||||
- `AFFINITY_INFO`
|
|
||||||
|
|
||||||
The `CPU_ON`, `CPU_OFF` and `CPU_SUSPEND` functions implement the warm boot
|
* BL3-2 (Secure-EL1 Payload) image initialization
|
||||||
path in ARM Trusted Firmware. `CPU_ON` and `CPU_OFF` have undergone testing
|
|
||||||
on all the supported FVPs. `CPU_SUSPEND` & `AFFINITY_INFO` have undergone
|
|
||||||
testing only on the AEM v8 Base FVP. Support for `AFFINITY_INFO` is still
|
|
||||||
experimental. Support for `CPU_SUSPEND` is stable for entry into power down
|
|
||||||
states. Standby states are currently not supported. `PSCI_VERSION` is
|
|
||||||
present but completely untested in this version of the software.
|
|
||||||
|
|
||||||
Unsupported PSCI functions can be divided into ones that can return
|
If a BL3-2 image is present then there must be a matching Secure-EL1 Payload
|
||||||
execution to the caller and ones that cannot. The following functions
|
Dispatcher (SPD) service (see later for details). During initialization
|
||||||
return with a error code as documented in the [Power State Coordination
|
that service must register a function to carry out initialization of BL3-2
|
||||||
Interface PDD] [PSCI].
|
once the runtime services are fully initialized. BL3-1 invokes such a
|
||||||
|
registered function to initialize BL3-2 before running BL3-3.
|
||||||
|
|
||||||
- `MIGRATE` : -1 (NOT_SUPPORTED)
|
Details on BL3-2 initialization and the SPD's role are described in the
|
||||||
- `MIGRATE_INFO_TYPE` : 2 (Trusted OS is either not present or does not
|
"Secure-EL1 Payloads and Dispatchers" section below.
|
||||||
require migration)
|
|
||||||
- `MIGRATE_INFO_UP_CPU` : 0 (Return value is UNDEFINED)
|
|
||||||
|
|
||||||
The following unsupported functions do not return and signal an assertion
|
* BL3-3 (Non-trusted Firmware) execution
|
||||||
failure if invoked.
|
|
||||||
|
|
||||||
- `SYSTEM_OFF`
|
BL3-1 initializes the EL2 or EL1 processor context for normal-world cold
|
||||||
- `SYSTEM_RESET`
|
boot, ensuring that no secure state information finds its way into the
|
||||||
|
non-secure execution state. BL3-1 uses the entrypoint information provided
|
||||||
BL3-1 returns the error code `-1` if an SMC is raised for any other runtime
|
by BL2 to jump to the Non-trusted firmware image (BL3-3) at the highest
|
||||||
service. This behavior is mandated by the [SMC calling convention PDD]
|
available Exception Level (EL2 if available, otherwise EL1).
|
||||||
[SMCCC].
|
|
||||||
|
|
||||||
|
|
||||||
### BL3-2 (Secure Payload) image initialization
|
3. EL3 runtime services framework
|
||||||
|
----------------------------------
|
||||||
|
|
||||||
BL2 is responsible for loading a BL3-2 image in memory specified by the platform.
|
Software executing in the non-secure state and in the secure state at exception
|
||||||
BL3-1 provides an api that uses the entrypoint and memory layout information for
|
levels lower than EL3 will request runtime services using the Secure Monitor
|
||||||
the BL3-2 image provided by BL2 to initialise BL3-2 in S-EL1.
|
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
|
||||||
|
Firmware (BL3-1).
|
||||||
|
|
||||||
|
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 Standard 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.
|
||||||
|
|
||||||
|
1. 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).
|
||||||
|
|
||||||
|
NOTE: Currently this service is called PSCI since there are no other
|
||||||
|
defined standard service calls.
|
||||||
|
|
||||||
|
2. 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 Firmware 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.
|
||||||
|
|
||||||
|
3. 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].
|
||||||
|
|
||||||
|
|
||||||
### Normal world software execution
|
### Registration
|
||||||
|
|
||||||
BL3-1 uses the entrypoint information provided by BL2 to jump to the normal
|
A runtime service is registered using the `DECLARE_RT_SVC()` macro, specifying
|
||||||
world software image (BL3-3) at the highest available Exception Level (EL2 if
|
the name of the service, the range of OENs covered, the type of service and
|
||||||
available, otherwise EL1).
|
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 BL3-1.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
|
||||||
3. Memory layout on FVP platforms
|
### 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 BL3-1
|
||||||
|
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 BL3-1 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:
|
||||||
|
|
||||||
|
1. Overlapping OEN ranges
|
||||||
|
2. Multiple descriptors for the same range of OENs and `call_type`
|
||||||
|
3. 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.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
|
||||||
|
### 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/standard 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.
|
||||||
|
|
||||||
|
|
||||||
|
4. Power State Coordination Interface
|
||||||
|
--------------------------------------
|
||||||
|
|
||||||
|
TODO: Provide design walkthrough of PSCI implementation.
|
||||||
|
|
||||||
|
The complete PSCI API is not yet implemented. The following functions are
|
||||||
|
currently implemented:
|
||||||
|
|
||||||
|
- `PSCI_VERSION`
|
||||||
|
- `CPU_OFF`
|
||||||
|
- `CPU_ON`
|
||||||
|
- `CPU_SUSPEND`
|
||||||
|
- `AFFINITY_INFO`
|
||||||
|
|
||||||
|
The `CPU_ON`, `CPU_OFF` and `CPU_SUSPEND` functions implement the warm boot
|
||||||
|
path in ARM Trusted Firmware. `CPU_ON` and `CPU_OFF` have undergone testing
|
||||||
|
on all the supported FVPs. `CPU_SUSPEND` & `AFFINITY_INFO` have undergone
|
||||||
|
testing only on the AEM v8 Base FVP. Support for `AFFINITY_INFO` is still
|
||||||
|
experimental. Support for `CPU_SUSPEND` is stable for entry into power down
|
||||||
|
states. Standby states are currently not supported. `PSCI_VERSION` is
|
||||||
|
present but completely untested in this version of the software.
|
||||||
|
|
||||||
|
Unsupported PSCI functions can be divided into ones that can return
|
||||||
|
execution to the caller and ones that cannot. The following functions
|
||||||
|
return with a error code as documented in the [Power State Coordination
|
||||||
|
Interface PDD] [PSCI].
|
||||||
|
|
||||||
|
- `MIGRATE` : -1 (NOT_SUPPORTED)
|
||||||
|
- `MIGRATE_INFO_TYPE` : 2 (Trusted OS is either not present or does not
|
||||||
|
require migration)
|
||||||
|
- `MIGRATE_INFO_UP_CPU` : 0 (Return value is UNDEFINED)
|
||||||
|
|
||||||
|
The following unsupported functions do not return and signal an assertion
|
||||||
|
failure if invoked.
|
||||||
|
|
||||||
|
- `SYSTEM_OFF`
|
||||||
|
- `SYSTEM_RESET`
|
||||||
|
|
||||||
|
|
||||||
|
5. Secure-EL1 Payloads and Dispatchers
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
On a production system that includes a Trusted OS running in Secure-EL1/EL0,
|
||||||
|
the Trusted OS is coupled with a companion runtime service in the BL3-1
|
||||||
|
firmware. This service is responsible for the initialisation of the Trusted
|
||||||
|
OS and all communications with it. The Trusted OS is the BL3-2 stage of the
|
||||||
|
boot flow in ARM Trusted Firmware. The firmware will attempt to locate, load
|
||||||
|
and execute a BL3-2 image.
|
||||||
|
|
||||||
|
ARM Trusted Firmware uses a more general term for the BL3-2 software that runs
|
||||||
|
at Secure-EL1 - the _Secure-EL1 Payload_ - as it is not always a Trusted OS.
|
||||||
|
|
||||||
|
The ARM Trusted Firmware provides a Test Secure-EL1 Payload (TSP) and a Test
|
||||||
|
Secure-EL1 Payload Dispatcher (TSPD) service as an example of how a Trusted OS
|
||||||
|
is supported on a production system using the Runtime Services Framework. On
|
||||||
|
such a system, the Test BL3-2 image and service are replaced by the Trusted OS
|
||||||
|
and its dispatcher service.
|
||||||
|
|
||||||
|
The TSP runs in Secure-EL1. It is designed to demonstrate synchronous
|
||||||
|
communication with the normal-world software running in EL1/EL2. Communication
|
||||||
|
is initiated by the normal-world software
|
||||||
|
|
||||||
|
* either directly through a Fast SMC (as defined in the [SMCCC])
|
||||||
|
|
||||||
|
* or indirectly through a [PSCI] SMC. The [PSCI] implementation in turn
|
||||||
|
informs the TSPD about the requested power management operation. This allows
|
||||||
|
the TSP to prepare for or respond to the power state change
|
||||||
|
|
||||||
|
The TSPD service is responsible for.
|
||||||
|
|
||||||
|
* Initializing the TSP
|
||||||
|
|
||||||
|
* Routing requests and responses between the secure and the non-secure
|
||||||
|
states during the two types of communications just described
|
||||||
|
|
||||||
|
### Initializing a BL3-2 Image
|
||||||
|
|
||||||
|
The Secure-EL1 Payload Dispatcher (SPD) service is responsible for initializing
|
||||||
|
the BL3-2 image. It needs access to the information passed by BL2 to BL3-1 to do
|
||||||
|
so. Hence BL3-1 implements:
|
||||||
|
|
||||||
|
1. `bl31_plat_get_bl32_mem_layout()` to return the extents of memory
|
||||||
|
available for BL3-2's use as communicated by BL2.
|
||||||
|
|
||||||
|
2. `bl31_get_next_image_info(uint32_t security_state)` to return a reference
|
||||||
|
to the `el_change_info` structure corresponding to the next image which will
|
||||||
|
be run in the specified security state. The SPD uses this api with the
|
||||||
|
secure security state as the parameter to get entry related information about
|
||||||
|
BL3-2.
|
||||||
|
|
||||||
|
In the absence of a BL3-2 image, BL3-1 passes control to the normal world
|
||||||
|
bootloader image (BL3-3). When the BL3-2 image is present, it is typical
|
||||||
|
that the SPD wants control to be passed to BL3-2 first and then later to BL3-3.
|
||||||
|
|
||||||
|
To do this the SPD has to register a BL3-2 initialization function during
|
||||||
|
initialization of the SPD service. The BL3-2 initialization function has this
|
||||||
|
prototype:
|
||||||
|
|
||||||
|
int32_t init(meminfo *bl32_meminfo);
|
||||||
|
|
||||||
|
and is registered using the `bl31_register_bl32_init()` function.
|
||||||
|
|
||||||
|
Trusted Firmware supports two approaches for the SPD to pass control to BL3-2
|
||||||
|
before returning through EL3 and running the non-trusted firmware (BL3-3):
|
||||||
|
|
||||||
|
1. In the BL3-2 initialization function, set up a secure context (see below
|
||||||
|
for more details of CPU context support) for this CPU and use
|
||||||
|
`bl31_set_next_image_type()` to request that the exit from `bl31_main()` is
|
||||||
|
to the BL3-2 entrypoint in Secure-EL1.
|
||||||
|
|
||||||
|
When the BL3-2 has completed initialization at Secure-EL1, it returns to
|
||||||
|
BL3-1 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 BL3-3. On return from the handler the framework
|
||||||
|
will exit to EL2 and run BL3-3.
|
||||||
|
|
||||||
|
2. In the BL3-2 initialization function, use an SPD-defined mechanism to
|
||||||
|
invoke a 'world-switch synchronous call' to Secure-EL1 to run the BL3-2
|
||||||
|
entrypoint.
|
||||||
|
NOTE: The Test SPD service included with the Trusted Firmware provides one
|
||||||
|
implementation of such a mechanism.
|
||||||
|
|
||||||
|
On completion BL3-2 returns control to BL3-1 via a SMC, and on receipt the
|
||||||
|
SPD service handler invokes the synchronous call return mechanism to return
|
||||||
|
to the BL3-2 initialization function. On return from this function,
|
||||||
|
`bl31_main()` will set up the return to the normal world firmware BL3-3 and
|
||||||
|
continue the boot process in the normal world.
|
||||||
|
|
||||||
|
|
||||||
|
6. Memory layout on FVP platforms
|
||||||
----------------------------------
|
----------------------------------
|
||||||
|
|
||||||
On FVP platforms, we use the Trusted ROM and Trusted SRAM to store the trusted
|
On FVP platforms, we use the Trusted ROM and Trusted SRAM to store the trusted
|
||||||
|
@ -659,7 +933,7 @@ following view:
|
||||||
------------ 0x04000000
|
------------ 0x04000000
|
||||||
|
|
||||||
|
|
||||||
4. Firmware Image Package (FIP)
|
7. Firmware Image Package (FIP)
|
||||||
--------------------------------
|
--------------------------------
|
||||||
|
|
||||||
Using a Firmware Image Package (FIP) allows for packing bootloader images (and
|
Using a Firmware Image Package (FIP) allows for packing bootloader images (and
|
||||||
|
@ -739,7 +1013,7 @@ Currently the FVPs policy only allows for loading of known images. The platform
|
||||||
policy can be modified to add additional images.
|
policy can be modified to add additional images.
|
||||||
|
|
||||||
|
|
||||||
5. Code Structure
|
8. Code Structure
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
Trusted Firmware code is logically divided between the three boot loader
|
Trusted Firmware code is logically divided between the three boot loader
|
||||||
|
@ -754,11 +1028,13 @@ following categories (present as directories in the source code):
|
||||||
other code.
|
other code.
|
||||||
* **Stage specific.** Code specific to a boot stage.
|
* **Stage specific.** Code specific to a boot stage.
|
||||||
* **Drivers.**
|
* **Drivers.**
|
||||||
|
* **Services.** EL3 runtime services, e.g. PSCI or SPD. Specific SPD services
|
||||||
|
reside in the `services/spd` directory (e.g. `services/spd/tspd`).
|
||||||
|
|
||||||
Each boot loader stage uses code from one or more of the above mentioned
|
Each boot loader stage uses code from one or more of the above mentioned
|
||||||
categories. Based upon the above, the code layout looks like this:
|
categories. Based upon the above, the code layout looks like this:
|
||||||
|
|
||||||
Directory Used by BL1? Used by BL2? Used by BL3?
|
Directory Used by BL1? Used by BL2? Used by BL3-1?
|
||||||
bl1 Yes No No
|
bl1 Yes No No
|
||||||
bl2 No Yes No
|
bl2 No Yes No
|
||||||
bl31 No No Yes
|
bl31 No No Yes
|
||||||
|
@ -767,6 +1043,7 @@ categories. Based upon the above, the code layout looks like this:
|
||||||
drivers Yes No Yes
|
drivers Yes No Yes
|
||||||
common Yes Yes Yes
|
common Yes Yes Yes
|
||||||
lib Yes Yes Yes
|
lib Yes Yes Yes
|
||||||
|
services No No Yes
|
||||||
|
|
||||||
All assembler files have the `.S` extension. The linker source files for each
|
All assembler files have the `.S` extension. The linker source files for each
|
||||||
boot stage have the extension `.ld.S`. These are processed by GCC to create the
|
boot stage have the extension `.ld.S`. These are processed by GCC to create the
|
||||||
|
@ -776,7 +1053,7 @@ FDTs provide a description of the hardware platform and are used by the Linux
|
||||||
kernel at boot time. These can be found in the `fdts` directory.
|
kernel at boot time. These can be found in the `fdts` directory.
|
||||||
|
|
||||||
|
|
||||||
6. References
|
9. References
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
1. Trusted Board Boot Requirements CLIENT PDD (ARM DEN 0006B-5). Available
|
1. Trusted Board Boot Requirements CLIENT PDD (ARM DEN 0006B-5). Available
|
||||||
|
|
308
docs/rt-svc-writers-guide.md
Normal file
308
docs/rt-svc-writers-guide.md
Normal file
|
@ -0,0 +1,308 @@
|
||||||
|
EL3 Runtime Service Writers Guide for ARM Trusted Firmware
|
||||||
|
==========================================================
|
||||||
|
|
||||||
|
Contents
|
||||||
|
--------
|
||||||
|
|
||||||
|
1. Introduction
|
||||||
|
2. Owning Entities, Call Types and Function IDs
|
||||||
|
3. Getting started
|
||||||
|
4. Registering a runtime service
|
||||||
|
5. Initializing a runtime service
|
||||||
|
6. Handling runtime service requests
|
||||||
|
7. Services that contain multiple sub-services
|
||||||
|
8. Secure-EL1 Payload Dispatcher service (SPD)
|
||||||
|
|
||||||
|
- - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
|
1. Introduction
|
||||||
|
----------------
|
||||||
|
|
||||||
|
This document describes how to add a runtime service to the EL3 Runtime
|
||||||
|
Firmware component of ARM Trusted Firmware (BL3-1).
|
||||||
|
|
||||||
|
Software executing in the normal world and in the trusted world 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
|
||||||
|
results are returned.
|
||||||
|
|
||||||
|
SMC Functions are grouped together based on the implementor of the service, for
|
||||||
|
example a subset of the Function IDs are designated as "OEM Calls" (see [SMCCC]
|
||||||
|
for full details). The EL3 runtime services framework in BL3-1 enables the
|
||||||
|
independent implementation of services for each group, which are then compiled
|
||||||
|
into the BL3-1 image. This simplifies the integration of common software from
|
||||||
|
ARM to support [PSCI], Secure Monitor for a Trusted OS and SoC specific
|
||||||
|
software. The common runtime services framework ensures that SMC Functions are
|
||||||
|
dispatched to their respective service implementation - the [Firmware Design]
|
||||||
|
provides details of how this is achieved.
|
||||||
|
|
||||||
|
The interface and operation 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 Standard calls, and the SMC32 and
|
||||||
|
SMC64 calling conventions. Please refer to that document for a full explanation
|
||||||
|
of these terms.
|
||||||
|
|
||||||
|
|
||||||
|
2. Owning Entities, Call Types and Function IDs
|
||||||
|
------------------------------------------------
|
||||||
|
|
||||||
|
The SMC Function Identifier includes a OEN field. These values and their
|
||||||
|
meaning are described in [SMCCC] and summarized in table 1 below. Some entities
|
||||||
|
are allocated a range of of OENs. The OEN must be interpreted in conjunction
|
||||||
|
with the SMC call type, which is either _Fast_ or _Standard_. Fast calls are
|
||||||
|
uninterruptible whereas Standard calls can be pre-empted. The majority of
|
||||||
|
Owning Entities only have allocated ranges for Fast calls: Standard calls are
|
||||||
|
reserved exclusively for Trusted OS providers or for interoperability with
|
||||||
|
legacy 32-bit software that predates the [SMCCC].
|
||||||
|
|
||||||
|
Type OEN Service
|
||||||
|
Fast 0 ARM Architecture calls
|
||||||
|
Fast 1 CPU Service calls
|
||||||
|
Fast 2 SiP Service calls
|
||||||
|
Fast 3 OEM Service calls
|
||||||
|
Fast 4 Standard Service calls
|
||||||
|
Fast 5-47 Reserved for future use
|
||||||
|
Fast 48-49 Trusted Application calls
|
||||||
|
Fast 50-63 Trusted OS calls
|
||||||
|
|
||||||
|
Std 0- 1 Reserved for existing ARMv7 calls
|
||||||
|
Std 2-63 Trusted OS Standard Calls
|
||||||
|
|
||||||
|
_Table 1: Service types and their corresponding Owning Entity Numbers_
|
||||||
|
|
||||||
|
Each individual entity can allocate the valid identifiers within the entity
|
||||||
|
range as they need - it is not necessary to coordinate with other entities of
|
||||||
|
the same type. For example, two SoC providers can use the same Function ID
|
||||||
|
within the SiP Service calls OEN range to mean different things - as these
|
||||||
|
calls should be specific to the SoC. The Standard Runtime Calls OEN is used for
|
||||||
|
services defined by ARM standards, such as [PSCI].
|
||||||
|
|
||||||
|
The SMC Function ID also indicates whether the call has followed the SMC32
|
||||||
|
calling convention, where all parameters are 32-bit, or the SMC64 calling
|
||||||
|
convention, where the parameters are 64-bit. The framework identifies and
|
||||||
|
rejects invalid calls that use the SMC64 calling convention but that originate
|
||||||
|
from an AArch32 caller.
|
||||||
|
|
||||||
|
The EL3 runtime services framework uses the call type and OEN to identify a
|
||||||
|
specific handler for each SMC call, but it is expected that an individual
|
||||||
|
handler will be responsible for all SMC Functions within a given service type.
|
||||||
|
|
||||||
|
|
||||||
|
3. Getting started
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
ARM Trusted Firmware has a [`services`] directory in the source tree under
|
||||||
|
which each owning entity can place the implementation of its runtime service.
|
||||||
|
The [PSCI] implementation is located here in the [`services/psci`] directory.
|
||||||
|
|
||||||
|
Runtime service sources will need to include the [`runtime_svc.h`] header file.
|
||||||
|
|
||||||
|
|
||||||
|
4. Registering a runtime service
|
||||||
|
---------------------------------
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
#define DECLARE_RT_SVC(_name, _start, _end, _type, _setup, _smch)
|
||||||
|
|
||||||
|
* `_name` is used to identify the data structure declared by this macro, and
|
||||||
|
is also used for diagnostic purposes
|
||||||
|
|
||||||
|
* `_start` and `_end` values must be based on the `OEN_*` values defined in
|
||||||
|
[`runtime_svc.h`]
|
||||||
|
|
||||||
|
* `_type` must be one of `SMC_TYPE_FAST` or `SMC_TYPE_STD`
|
||||||
|
|
||||||
|
* `_setup` is the initialization function with the `rt_svc_init` signature:
|
||||||
|
|
||||||
|
typedef int32_t (*rt_svc_init)(void);
|
||||||
|
|
||||||
|
* `_smch` is the SMC handler function with the `rt_svc_handle` signature:
|
||||||
|
|
||||||
|
typedef uint64_t (*rt_svc_handle)(uint32_t smc_fid,
|
||||||
|
uint64_t x1, uint64_t x2,
|
||||||
|
uint64_t x3, uint64_t x4,
|
||||||
|
void *reserved,
|
||||||
|
void *handle,
|
||||||
|
uint64_t flags);
|
||||||
|
|
||||||
|
Details of the requirements and behavior of the two callbacks is provided in
|
||||||
|
the following sections.
|
||||||
|
|
||||||
|
During initialization the services framework validates each declared service
|
||||||
|
to ensure that the following conditions are met:
|
||||||
|
|
||||||
|
1. The `_start` OEN is not greater than the `_end` OEN
|
||||||
|
2. The `_end` OEN does not exceed the maximum OEN value (63)
|
||||||
|
3. The `_type` is one of `SMC_TYPE_FAST` or `SMC_TYPE_STD`
|
||||||
|
4. `_setup` and `_smch` routines have been specified
|
||||||
|
|
||||||
|
[`psci_steup.c`] provides an example of registering a runtime service:
|
||||||
|
|
||||||
|
/* Register PSCI as a run time service */
|
||||||
|
DECLARE_RT_SVC(
|
||||||
|
psci,
|
||||||
|
OEN_STD_START,
|
||||||
|
OEN_STD_END,
|
||||||
|
SMC_TYPE_FAST,
|
||||||
|
psci_setup,
|
||||||
|
psci_smc_handler
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
5. Initializing a runtime service
|
||||||
|
---------------------------------
|
||||||
|
|
||||||
|
Runtime services are initialized once, during cold boot, by the primary CPU
|
||||||
|
after platform and architectural initialization is complete. The framework
|
||||||
|
performs basic validation of the declared service before calling
|
||||||
|
the service initialization function (`_setup` in the declaration). This
|
||||||
|
function must carry out any essential EL3 initialization prior to receiving a
|
||||||
|
SMC Function call via the handler function.
|
||||||
|
|
||||||
|
On success, the initialization function must return `0`. Any other return value
|
||||||
|
will cause the framework to issue a diagnostic:
|
||||||
|
|
||||||
|
Error initializing runtime service <name of the service>
|
||||||
|
|
||||||
|
and then ignore the service - the system will continue to boot but SMC calls
|
||||||
|
will not be passed to the service handler and instead return the _Unknown SMC
|
||||||
|
Function ID_ result `0xFFFFFFFF`.
|
||||||
|
|
||||||
|
If the system must not be allowed to proceed without the service, the
|
||||||
|
initialization function must itself cause the firmware boot to be halted.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
|
||||||
|
6. Handling runtime service requests
|
||||||
|
-------------------------------------
|
||||||
|
|
||||||
|
SMC calls for a service are forwarded by the framework to the service's SMC
|
||||||
|
handler function (`_smch` in the service declaration). This function must have
|
||||||
|
the following signature:
|
||||||
|
|
||||||
|
typedef uint64_t (*rt_svc_handle)(uint32_t smc_fid,
|
||||||
|
uint64_t x1, uint64_t x2,
|
||||||
|
uint64_t x3, uint64_t x4,
|
||||||
|
void *reserved,
|
||||||
|
void *handle,
|
||||||
|
uint64_t flags);
|
||||||
|
|
||||||
|
The handler is responsible for:
|
||||||
|
|
||||||
|
1. Determining that `smc_fid` is a valid and supported SMC Function ID,
|
||||||
|
otherwise completing the request with the _Unknown SMC Function ID_:
|
||||||
|
|
||||||
|
SMC_RET1(handle, SMC_UNK);
|
||||||
|
|
||||||
|
2. Determining if the requested function is valid for the calling security
|
||||||
|
state. SMC Calls can be made from both the normal and trusted worlds and
|
||||||
|
the framework will forward all calls to the service handler.
|
||||||
|
|
||||||
|
The `flags` parameter to this function indicates the caller security state
|
||||||
|
in bit[0], where a value of `1` indicates a non-secure caller. The
|
||||||
|
`is_caller_secure(flags)` and `is_caller_non_secure(flags)` can be used to
|
||||||
|
test this condition.
|
||||||
|
|
||||||
|
If invalid, the request should be completed with:
|
||||||
|
|
||||||
|
SMC_RET1(handle, SMC_UNK);
|
||||||
|
|
||||||
|
3. Truncating parameters for calls made using the SMC32 calling convention.
|
||||||
|
Such calls can be determined by checking the CC field in bit[30] of the
|
||||||
|
`smc_fid` parameter, for example by using:
|
||||||
|
|
||||||
|
if (GET_SMC_CC(smc_fid) == SMC_32) ...
|
||||||
|
|
||||||
|
For such calls, the upper bits of the parameters x1-x4 and the saved
|
||||||
|
parameters X5-X7 are UNDEFINED and must be explicitly ignored by the
|
||||||
|
handler. This can be done by truncating the values to a suitable 32-bit
|
||||||
|
integer type before use, for example by ensuring that functions defined
|
||||||
|
to handle individual SMC Functions use appropriate 32-bit parameters.
|
||||||
|
|
||||||
|
4. Providing the service requested by the SMC Function, utilizing the
|
||||||
|
immediate parameters x1-x4 and/or the additional saved parameters X5-X7.
|
||||||
|
The latter can be retrieved using the `SMC_GET_GP(handle, ref)` function,
|
||||||
|
supplying the appropriate `CTX_GPREG_Xn` reference, e.g.
|
||||||
|
|
||||||
|
uint64_t x6 = SMC_GET_GP(handle, CTX_GPREG_X6);
|
||||||
|
|
||||||
|
5. Implementing the standard SMC32 Functions that provide information about
|
||||||
|
the implementation of the service. These are the Call Count, Implementor
|
||||||
|
UID and Revision Details for each service documented in section 6 of the
|
||||||
|
[SMCCC].
|
||||||
|
|
||||||
|
The ARM Trusted Firmware expects owning entities to follow this
|
||||||
|
recommendation.
|
||||||
|
|
||||||
|
5. Returning the result to the caller. The [SMCCC] allows for up to 256 bits
|
||||||
|
of return value in SMC64 using X0-X3 and 128 bits in SMC32 using W0-W3. The
|
||||||
|
framework provides a family of macros to set the multi-register return
|
||||||
|
value and complete the handler:
|
||||||
|
|
||||||
|
SMC_RET1(handle, x0);
|
||||||
|
SMC_RET2(handle, x0, x1);
|
||||||
|
SMC_RET3(handle, x0, x1, x2);
|
||||||
|
SMC_RET4(handle, x0, x1, x2, x3);
|
||||||
|
|
||||||
|
The `reserved` parameter to the handler is reserved for future use and can be
|
||||||
|
ignored. The value returned by a SMC handler is also reserved for future use -
|
||||||
|
completion of the handler function must always be via one of the `SMC_RETn()`
|
||||||
|
macros.
|
||||||
|
|
||||||
|
NOTE: The PSCI and Test Secure-EL1 Payload Dispatcher services do not follow
|
||||||
|
all of the above requirements yet.
|
||||||
|
|
||||||
|
|
||||||
|
7. Services that contain multiple sub-services
|
||||||
|
-----------------------------------------------
|
||||||
|
|
||||||
|
It is possible that a single owning entity implements multiple sub-services. For
|
||||||
|
example, the Standard calls service handles `0x84000000`-`0x8400FFFF` and
|
||||||
|
`0xC4000000`-`0xC400FFFF` functions. Within that range, the [PSCI] service
|
||||||
|
handles the `0x84000000`-`0x8400001F` and `0xC4000000`-`0xC400001F` functions.
|
||||||
|
In that respect, [PSCI] is a 'sub-service' of the Standard calls service. In
|
||||||
|
future, there could be additional such sub-services in the Standard calls
|
||||||
|
service which perform independent functions.
|
||||||
|
|
||||||
|
In this situation it may be valuable to introduce a second level framework to
|
||||||
|
enable independent implementation of sub-services. Such a framework might look
|
||||||
|
very similar to the current runtime services framework, but using a different
|
||||||
|
part of the SMC Function ID to identify the sub-service. Trusted Firmware does
|
||||||
|
not provide such a framework at present.
|
||||||
|
|
||||||
|
|
||||||
|
8. Secure-EL1 Payload Dispatcher service (SPD)
|
||||||
|
-----------------------------------------------
|
||||||
|
|
||||||
|
Services that handle SMC Functions targeting a Trusted OS, Trusted Application,
|
||||||
|
or other Secure-EL1 Payload are special. These services need to manage the
|
||||||
|
Secure-EL1 context, provide the _Secure Monitor_ functionality of switching
|
||||||
|
between the normal and secure worlds, deliver SMC Calls through to Secure-EL1
|
||||||
|
and generally manage the Secure-EL1 Payload through CPU power-state transitions.
|
||||||
|
|
||||||
|
TODO: Provide details of the additional work required to implement a SPD and
|
||||||
|
the BL3-1 support for these services. Or a reference to the document that will
|
||||||
|
provide this information....
|
||||||
|
|
||||||
|
|
||||||
|
- - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
|
_Copyright (c) 2014, ARM Limited and Contributors. All rights reserved._
|
||||||
|
|
||||||
|
|
||||||
|
[Firmware Design]: ./firmware-design.md
|
||||||
|
|
||||||
|
[`services`]: ../services
|
||||||
|
[`services/psci`]: ../services/psci
|
||||||
|
[`psci_steup.c`]: ../services/psci/psci_setup.c
|
||||||
|
[`runtime_svc.h`]: ../include/runtime_svc.h
|
||||||
|
[PSCI]: http://infocenter.arm.com/help/topic/com.arm.doc.den0022b/index.html "Power State Coordination Interface PDD (ARM DEN 0022B.b)"
|
||||||
|
[SMCCC]: http://infocenter.arm.com/help/topic/com.arm.doc.den0028a/index.html "SMC Calling Convention PDD (ARM DEN 0028A)"
|
Loading…
Add table
Reference in a new issue