mirror of
https://github.com/ARM-software/arm-trusted-firmware.git
synced 2025-04-16 01:24:27 +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 :
|
||||
|
||||
1. Introduction
|
||||
2. Cold Boot
|
||||
3. Memory layout on FVP platforms
|
||||
4. Firmware Image Package (FIP)
|
||||
5. Code Structure
|
||||
6. References
|
||||
2. Cold boot
|
||||
3. EL3 runtime services framework
|
||||
4. Power State Coordination Interface
|
||||
5. Secure-EL1 Payloads and Dispatchers
|
||||
6. Memory layout on FVP platforms
|
||||
7. Firmware Image Package (FIP)
|
||||
8. Code Structure
|
||||
9. References
|
||||
|
||||
|
||||
1. Introduction
|
||||
|
@ -29,7 +32,7 @@ instruction. The SMC instruction must be used as mandated by the [SMC Calling
|
|||
Convention PDD][SMCCC] [3].
|
||||
|
||||
|
||||
2. Cold Boot
|
||||
2. Cold boot
|
||||
-------------
|
||||
|
||||
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:
|
||||
|
||||
The only runtime service implemented by BL3-1 is PSCI. The complete PSCI API
|
||||
is not yet implemented. The following functions are currently implemented:
|
||||
The runtime service framework and its initialization is described in the
|
||||
"EL3 runtime services framework" section below.
|
||||
|
||||
- `PSCI_VERSION`
|
||||
- `CPU_OFF`
|
||||
- `CPU_ON`
|
||||
- `CPU_SUSPEND`
|
||||
- `AFFINITY_INFO`
|
||||
Details about the PSCI service are provided in the "Power State Coordination
|
||||
Interface" section below.
|
||||
|
||||
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.
|
||||
* BL3-2 (Secure-EL1 Payload) image initialization
|
||||
|
||||
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].
|
||||
If a BL3-2 image is present then there must be a matching Secure-EL1 Payload
|
||||
Dispatcher (SPD) service (see later for details). During initialization
|
||||
that service must register a function to carry out initialization of BL3-2
|
||||
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)
|
||||
- `MIGRATE_INFO_TYPE` : 2 (Trusted OS is either not present or does not
|
||||
require migration)
|
||||
- `MIGRATE_INFO_UP_CPU` : 0 (Return value is UNDEFINED)
|
||||
Details on BL3-2 initialization and the SPD's role are described in the
|
||||
"Secure-EL1 Payloads and Dispatchers" section below.
|
||||
|
||||
The following unsupported functions do not return and signal an assertion
|
||||
failure if invoked.
|
||||
* BL3-3 (Non-trusted Firmware) execution
|
||||
|
||||
- `SYSTEM_OFF`
|
||||
- `SYSTEM_RESET`
|
||||
|
||||
BL3-1 returns the error code `-1` if an SMC is raised for any other runtime
|
||||
service. This behavior is mandated by the [SMC calling convention PDD]
|
||||
[SMCCC].
|
||||
BL3-1 initializes the EL2 or EL1 processor context for normal-world cold
|
||||
boot, ensuring that no secure state information finds its way into the
|
||||
non-secure execution state. BL3-1 uses the entrypoint information provided
|
||||
by BL2 to jump to the Non-trusted firmware image (BL3-3) at the highest
|
||||
available Exception Level (EL2 if available, otherwise EL1).
|
||||
|
||||
|
||||
### 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.
|
||||
BL3-1 provides an api that uses the entrypoint and memory layout information for
|
||||
the BL3-2 image provided by BL2 to initialise BL3-2 in S-EL1.
|
||||
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
|
||||
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
|
||||
world software image (BL3-3) at the highest available Exception Level (EL2 if
|
||||
available, otherwise EL1).
|
||||
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 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
|
||||
|
@ -659,7 +933,7 @@ following view:
|
|||
------------ 0x04000000
|
||||
|
||||
|
||||
4. Firmware Image Package (FIP)
|
||||
7. Firmware Image Package (FIP)
|
||||
--------------------------------
|
||||
|
||||
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.
|
||||
|
||||
|
||||
5. Code Structure
|
||||
8. Code Structure
|
||||
------------------
|
||||
|
||||
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.
|
||||
* **Stage specific.** Code specific to a boot stage.
|
||||
* **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
|
||||
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
|
||||
bl2 No Yes No
|
||||
bl31 No No Yes
|
||||
|
@ -767,6 +1043,7 @@ categories. Based upon the above, the code layout looks like this:
|
|||
drivers Yes No Yes
|
||||
common Yes Yes Yes
|
||||
lib Yes Yes Yes
|
||||
services No No Yes
|
||||
|
||||
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
|
||||
|
@ -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.
|
||||
|
||||
|
||||
6. References
|
||||
9. References
|
||||
--------------
|
||||
|
||||
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