mirror of
https://github.com/ARM-software/arm-trusted-firmware.git
synced 2025-04-16 17:44:19 +00:00
Remove Markdown documentation
Removed Markdown documents as they have been converted to reStructuredText. Change-Id: I3148222eb31258f158f64de4ddcdda4b232ce483 Signed-off-by: Douglas Raillard <douglas.raillard@arm.com>
This commit is contained in:
parent
668c5022e5
commit
06fb4278e6
29 changed files with 0 additions and 13307 deletions
|
@ -1,15 +0,0 @@
|
|||
Contributor Acknowledgements
|
||||
============================
|
||||
|
||||
Companies
|
||||
---------
|
||||
Linaro Limited
|
||||
|
||||
NVIDIA Corporation
|
||||
|
||||
Socionext Inc.
|
||||
|
||||
Xilinx, Inc.
|
||||
|
||||
Individuals
|
||||
-----------
|
122
contributing.md
122
contributing.md
|
@ -1,122 +0,0 @@
|
|||
Contributing to ARM Trusted Firmware
|
||||
====================================
|
||||
|
||||
Getting Started
|
||||
---------------
|
||||
|
||||
* Make sure you have a [GitHub account].
|
||||
* Create an [issue] for your work if one does not already exist. This gives
|
||||
everyone visibility of whether others are working on something similar. ARM
|
||||
licensees may contact ARM directly via their partner managers instead if
|
||||
they prefer.
|
||||
* Note that the [issue] tracker for this project is in a separate
|
||||
[issue tracking repository]. Please follow the guidelines in that
|
||||
repository.
|
||||
* If you intend to include Third Party IP in your contribution, please
|
||||
raise a separate [issue] for this and ensure that the changes that
|
||||
include Third Party IP are made on a separate topic branch.
|
||||
* [Fork][] [arm-trusted-firmware][] on GitHub.
|
||||
* Clone the fork to your own machine.
|
||||
* Create a local topic branch based on the [arm-trusted-firmware][] `master`
|
||||
branch.
|
||||
|
||||
|
||||
Making Changes
|
||||
--------------
|
||||
|
||||
* Make commits of logical units. See these general [Git guidelines] for
|
||||
contributing to a project.
|
||||
* Follow the [Linux coding style]; this style is enforced for the ARM Trusted
|
||||
Firmware project (style errors only, not warnings).
|
||||
* Use the checkpatch.pl script provided with the Linux source tree. A
|
||||
Makefile target is provided for convenience (see section 2 in the
|
||||
[User Guide]).
|
||||
* Keep the commits on topic. If you need to fix another bug or make another
|
||||
enhancement, please create a separate [issue] and address it on a separate
|
||||
topic branch.
|
||||
* Avoid long commit series. If you do have a long series, consider whether
|
||||
some commits should be squashed together or addressed in a separate topic.
|
||||
* Make sure your commit messages are in the proper format. If a commit fixes
|
||||
a GitHub [issue], include a reference (e.g.
|
||||
"fixes arm-software/tf-issues#45"); this ensures the [issue] is
|
||||
[automatically closed] when merged into the [arm-trusted-firmware] `master`
|
||||
branch.
|
||||
* Where appropriate, please update the documentation.
|
||||
* Consider whether the [User Guide], [Porting Guide], [Firmware Design] or
|
||||
other in-source documentation needs updating.
|
||||
* Ensure that each changed file has the correct copyright and license
|
||||
information. Files that entirely consist of contributions to this
|
||||
project should have the copyright notice and BSD-3-Clause SPDX license
|
||||
identifier as shown in [license.md](./license.md). Files that contain
|
||||
changes to imported Third Party IP should contain a notice as follows,
|
||||
with the original copyright and license text retained:
|
||||
```
|
||||
Portions copyright (c) [XXXX-]YYYY, ARM Limited and Contributors. All rights reserved.
|
||||
```
|
||||
where XXXX is the year of first contribution (if different to YYYY) and
|
||||
YYYY is the year of most recent contribution.
|
||||
* If not done previously, you may add your name or your company name to
|
||||
the [Acknowledgements] file.
|
||||
* If you are submitting new files that you intend to be the technical
|
||||
sub-maintainer for (for example, a new platform port), then also update
|
||||
the [Maintainers] file.
|
||||
* For topics with multiple commits, you should make all documentation
|
||||
changes (and nothing else) in the last commit of the series. Otherwise,
|
||||
include the documentation changes within the single commit.
|
||||
* Please test your changes. As a minimum, ensure UEFI boots to the shell on
|
||||
the Foundation FVP. See [Running the software on FVP] for more information.
|
||||
|
||||
|
||||
Submitting Changes
|
||||
------------------
|
||||
|
||||
* Ensure that each commit in the series has at least one `Signed-off-by:`
|
||||
line, using your real name and email address. The names in the
|
||||
`Signed-off-by:` and `Author:` lines must match. If anyone else contributes
|
||||
to the commit, they must also add their own `Signed-off-by:` line.
|
||||
By adding this line the contributor certifies the contribution is made under
|
||||
the terms of the [Developer Certificate of Origin (DCO)][DCO].
|
||||
* Push your local changes to your fork of the repository.
|
||||
* Submit a [pull request] to the [arm-trusted-firmware] `integration` branch.
|
||||
* The changes in the [pull request] will then undergo further review and
|
||||
testing by the [Maintainers]. Any review comments will be made as
|
||||
comments on the [pull request]. This may require you to do some rework.
|
||||
* When the changes are accepted, the [Maintainers] will integrate them.
|
||||
* Typically, the [Maintainers] will merge the [pull request] into the
|
||||
`integration` branch within the GitHub UI, creating a merge commit.
|
||||
* Please avoid creating merge commits in the [pull request] itself.
|
||||
* If the [pull request] is not based on a recent commit, the [Maintainers]
|
||||
may rebase it onto the `master` branch first, or ask you to do this.
|
||||
* If the [pull request] cannot be automatically merged, the [Maintainers]
|
||||
will ask you to rebase it onto the `master` branch.
|
||||
* After final integration testing, the [Maintainers] will push your merge
|
||||
commit to the `master` branch. If a problem is found during integration,
|
||||
the merge commit will be removed from the `integration` branch and the
|
||||
[Maintainers] will ask you to create a new pull request to resolve the
|
||||
problem.
|
||||
* Please do not delete your topic branch until it is safely merged into
|
||||
the `master` branch.
|
||||
|
||||
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
_Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved._
|
||||
|
||||
|
||||
[User Guide]: ./docs/user-guide.md
|
||||
[Running the software on FVP]: ./docs/user-guide.md#8--running-the-software-on-fvp
|
||||
[Porting Guide]: ./docs/porting-guide.md
|
||||
[Firmware Design]: ./docs/firmware-design.md
|
||||
[Acknowledgements]: ./acknowledgements.md "Contributor acknowledgements"
|
||||
[DCO]: ./dco.txt
|
||||
[Maintainers]: ./maintainers.md
|
||||
|
||||
[GitHub account]: https://github.com/signup/free
|
||||
[Fork]: https://help.github.com/articles/fork-a-repo
|
||||
[issue tracking repository]: https://github.com/ARM-software/tf-issues
|
||||
[issue]: https://github.com/ARM-software/tf-issues/issues
|
||||
[pull request]: https://help.github.com/articles/using-pull-requests
|
||||
[automatically closed]: https://help.github.com/articles/closing-issues-via-commit-messages
|
||||
[Git guidelines]: http://git-scm.com/book/ch5-2.html
|
||||
[Linux coding style]: https://www.kernel.org/doc/Documentation/CodingStyle
|
||||
[arm-trusted-firmware]: https://github.com/ARM-software/arm-trusted-firmware
|
|
@ -1,93 +0,0 @@
|
|||
|
||||
ARM SiP Service
|
||||
===============
|
||||
|
||||
This document enumerates and describes the ARM SiP (Silicon Provider) services.
|
||||
|
||||
SiP services are non-standard, platform-specific services offered by the silicon
|
||||
implementer or platform provider. They are accessed via. `SMC` ("SMC calls")
|
||||
instruction executed from Exception Levels below EL3. SMC calls for SiP
|
||||
services:
|
||||
|
||||
* Follow [SMC Calling Convention][SMCCC];
|
||||
* Use SMC function IDs that fall in the SiP range, which are `0xc2000000` -
|
||||
`0xc200ffff` for 64-bit calls, and `0x82000000` - `0x8200ffff` for 32-bit
|
||||
calls.
|
||||
|
||||
The ARM SiP implementation offers the following services:
|
||||
|
||||
* Performance Measurement Framework (PMF)
|
||||
* Execution State Switching service
|
||||
|
||||
Source definitions for ARM SiP service are located in the `arm_sip_svc.h` header
|
||||
file.
|
||||
|
||||
Performance Measurement Framework (PMF)
|
||||
---------------------------------------
|
||||
|
||||
The [Performance Measurement Framework](./firmware-design.md#13--performance-measurement-framework)
|
||||
allows callers to retrieve timestamps captured at various paths in ARM Trusted
|
||||
Firmware execution. It's described in detail in [Firmware Design document][Firmware Design].
|
||||
|
||||
Execution State Switching service
|
||||
---------------------------------
|
||||
|
||||
Execution State Switching service provides a mechanism for a non-secure lower
|
||||
Exception Level (either EL2, or NS EL1 if EL2 isn't implemented) to request to
|
||||
switch its execution state (a.k.a. Register Width), either from AArch64 to
|
||||
AArch32, or from AArch32 to AArch64, for the calling CPU. This service is only
|
||||
available when ARM Trusted Firmware is built for AArch64 (i.e. when build option
|
||||
`ARCH` is set to `aarch64`).
|
||||
|
||||
### `ARM_SIP_SVC_EXE_STATE_SWITCH`
|
||||
|
||||
Arguments:
|
||||
uint32_t Function ID
|
||||
uint32_t PC hi
|
||||
uint32_t PC lo
|
||||
uint32_t Cookie hi
|
||||
uint32_t Cookie lo
|
||||
|
||||
Return:
|
||||
uint32_t
|
||||
|
||||
The function ID parameter must be `0x82000020`. It uniquely identifies the
|
||||
Execution State Switching service being requested.
|
||||
|
||||
The parameters _PC hi_ and _PC lo_ defines upper and lower words, respectively,
|
||||
of the entry point (physical address) at which execution should start, after
|
||||
Execution State has been switched. When calling from AArch64, _PC hi_ must be 0.
|
||||
|
||||
When execution starts at the supplied entry point after Execution State has been
|
||||
switched, the parameters _Cookie hi_ and _Cookie lo_ are passed in CPU registers
|
||||
0 and 1, respectively. When calling from AArch64, _Cookie hi_ must be 0.
|
||||
|
||||
This call can only be made on the primary CPU, before any secondaries were
|
||||
brought up with `CPU_ON` PSCI call. Otherwise, the call will always fail.
|
||||
|
||||
The effect of switching execution state is as if the Exception Level were
|
||||
entered for the first time, following power on. This means CPU registers that
|
||||
have a defined reset value by the Architecture will assume that value. Other
|
||||
registers should not be expected to hold their values before the call was made.
|
||||
CPU endianness, however, is preserved from the previous execution state. Note
|
||||
that this switches the execution state of the calling CPU only. This is not a
|
||||
substitute for PSCI `SYSTEM_RESET`.
|
||||
|
||||
The service may return the following error codes:
|
||||
|
||||
- `STATE_SW_E_PARAM`: If any of the parameters were deemed invalid for
|
||||
a specific request.
|
||||
- `STATE_SW_E_DENIED`: If the call is not successful, or when ARM Trusted
|
||||
Firmware is built for AArch32.
|
||||
|
||||
If the call is successful, the caller wouldn't observe the SMC returning.
|
||||
Instead, execution starts at the supplied entry point, with the CPU registers 0
|
||||
and 1 populated with the supplied _Cookie hi_ and _Cookie lo_ values,
|
||||
respectively.
|
||||
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
_Copyright (c) 2017, ARM Limited and Contributors. All rights reserved._
|
||||
|
||||
[Firmware Design]: ./firmware-design.md
|
||||
[SMCCC]: http://infocenter.arm.com/help/topic/com.arm.doc.den0028a/index.html "SMC Calling Convention PDD (ARM DEN 0028A)"
|
|
@ -1,925 +0,0 @@
|
|||
Abstracting a Chain of Trust
|
||||
============================
|
||||
|
||||
Contents :
|
||||
|
||||
1. [Introduction](#1--introduction)
|
||||
2. [Framework design](#2--framework-design)
|
||||
3. [Specifying a Chain of Trust](#3--specifying-a-chain-of-trust)
|
||||
4. [Implementation example](#4--implementation-example)
|
||||
|
||||
|
||||
1. Introduction
|
||||
----------------
|
||||
|
||||
The aim of this document is to describe the authentication framework implemented
|
||||
in the Trusted Firmware. This framework fulfills the following requirements:
|
||||
|
||||
1. It should be possible for a platform port to specify the Chain of Trust in
|
||||
terms of certificate hierarchy and the mechanisms used to verify a
|
||||
particular image/certificate.
|
||||
|
||||
2. The framework should distinguish between:
|
||||
|
||||
- The mechanism used to encode and transport information, e.g. DER encoded
|
||||
X.509v3 certificates to ferry Subject Public Keys, hashes and non-volatile
|
||||
counters.
|
||||
|
||||
- The mechanism used to verify the transported information i.e. the
|
||||
cryptographic libraries.
|
||||
|
||||
The framework has been designed following a modular approach illustrated in the
|
||||
next diagram:
|
||||
|
||||
```
|
||||
+---------------+---------------+------------+
|
||||
| Trusted | Trusted | Trusted |
|
||||
| Firmware | Firmware | Firmware |
|
||||
| Generic | IO Framework | Platform |
|
||||
| Code i.e. | (IO) | Port |
|
||||
| BL1/BL2 (GEN) | | (PP) |
|
||||
+---------------+---------------+------------+
|
||||
^ ^ ^
|
||||
| | |
|
||||
v v v
|
||||
+-----------+ +-----------+ +-----------+
|
||||
| | | | | Image |
|
||||
| Crypto | | Auth | | Parser |
|
||||
| Module |<->| Module |<->| Module |
|
||||
| (CM) | | (AM) | | (IPM) |
|
||||
| | | | | |
|
||||
+-----------+ +-----------+ +-----------+
|
||||
^ ^
|
||||
| |
|
||||
v v
|
||||
+----------------+ +-----------------+
|
||||
| Cryptographic | | Image Parser |
|
||||
| Libraries (CL) | | Libraries (IPL) |
|
||||
+----------------+ +-----------------+
|
||||
| |
|
||||
| |
|
||||
| |
|
||||
v v
|
||||
+-----------------+
|
||||
| Misc. Libs e.g. |
|
||||
| ASN.1 decoder |
|
||||
| |
|
||||
+-----------------+
|
||||
|
||||
DIAGRAM 1.
|
||||
```
|
||||
|
||||
This document describes the inner details of the authentication framework and
|
||||
the abstraction mechanisms available to specify a Chain of Trust.
|
||||
|
||||
|
||||
2. Framework design
|
||||
--------------------
|
||||
|
||||
This section describes some aspects of the framework design and the rationale
|
||||
behind them. These aspects are key to verify a Chain of Trust.
|
||||
|
||||
### 2.1 Chain of Trust
|
||||
|
||||
A CoT is basically a sequence of authentication images which usually starts with
|
||||
a root of trust and culminates in a single data image. The following diagram
|
||||
illustrates how this maps to a CoT for the BL31 image described in the
|
||||
TBBR-Client specification.
|
||||
|
||||
```
|
||||
+------------------+ +-------------------+
|
||||
| ROTPK/ROTPK Hash |------>| Trusted Key |
|
||||
+------------------+ | Certificate |
|
||||
| (Auth Image) |
|
||||
/+-------------------+
|
||||
/ |
|
||||
/ |
|
||||
/ |
|
||||
/ |
|
||||
L v
|
||||
+------------------+ +-------------------+
|
||||
| Trusted World |------>| BL31 Key |
|
||||
| Public Key | | Certificate |
|
||||
+------------------+ | (Auth Image) |
|
||||
+-------------------+
|
||||
/ |
|
||||
/ |
|
||||
/ |
|
||||
/ |
|
||||
/ v
|
||||
+------------------+ L +-------------------+
|
||||
| BL31 Content |------>| BL31 Content |
|
||||
| Certificate PK | | Certificate |
|
||||
+------------------+ | (Auth Image) |
|
||||
+-------------------+
|
||||
/ |
|
||||
/ |
|
||||
/ |
|
||||
/ |
|
||||
/ v
|
||||
+------------------+ L +-------------------+
|
||||
| BL31 Hash |------>| BL31 Image |
|
||||
| | | (Data Image) |
|
||||
+------------------+ | |
|
||||
+-------------------+
|
||||
|
||||
DIAGRAM 2.
|
||||
```
|
||||
|
||||
The root of trust is usually a public key (ROTPK) that has been burnt in the
|
||||
platform and cannot be modified.
|
||||
|
||||
### 2.2 Image types
|
||||
|
||||
Images in a CoT are categorised as authentication and data images. An
|
||||
authentication image contains information to authenticate a data image or
|
||||
another authentication image. A data image is usually a boot loader binary, but
|
||||
it could be any other data that requires authentication.
|
||||
|
||||
### 2.3 Component responsibilities
|
||||
|
||||
For every image in a Chain of Trust, the following high level operations are
|
||||
performed to verify it:
|
||||
|
||||
1. Allocate memory for the image either statically or at runtime.
|
||||
|
||||
2. Identify the image and load it in the allocated memory.
|
||||
|
||||
3. Check the integrity of the image as per its type.
|
||||
|
||||
4. Authenticate the image as per the cryptographic algorithms used.
|
||||
|
||||
5. If the image is an authentication image, extract the information that will
|
||||
be used to authenticate the next image in the CoT.
|
||||
|
||||
In Diagram 1, each component is responsible for one or more of these operations.
|
||||
The responsibilities are briefly described below.
|
||||
|
||||
|
||||
#### 2.2.1 TF Generic code and IO framework (GEN/IO)
|
||||
|
||||
These components are responsible for initiating the authentication process for a
|
||||
particular image in BL1 or BL2. For each BL image that requires authentication,
|
||||
the Generic code asks recursively the Authentication module what is the parent
|
||||
image until either an authenticated image or the ROT is reached. Then the
|
||||
Generic code calls the IO framewotk to load the image and calls the
|
||||
Authentication module to authenticate it, following the CoT from ROT to Image.
|
||||
|
||||
|
||||
#### 2.2.2 TF Platform Port (PP)
|
||||
|
||||
The platform is responsible for:
|
||||
|
||||
1. Specifying the CoT for each image that needs to be authenticated. Details of
|
||||
how a CoT can be specified by the platform are explained later. The platform
|
||||
also specifies the authentication methods and the parsing method used for
|
||||
each image.
|
||||
|
||||
2. Statically allocating memory for each parameter in each image which is
|
||||
used for verifying the CoT, e.g. memory for public keys, hashes etc.
|
||||
|
||||
3. Providing the ROTPK or a hash of it.
|
||||
|
||||
4. Providing additional information to the IPM to enable it to identify and
|
||||
extract authentication parameters contained in an image, e.g. if the
|
||||
parameters are stored as X509v3 extensions, the corresponding OID must be
|
||||
provided.
|
||||
|
||||
5. Fulfill any other memory requirements of the IPM and the CM (not currently
|
||||
described in this document).
|
||||
|
||||
6. Export functions to verify an image which uses an authentication method that
|
||||
cannot be interpreted by the CM, e.g. if an image has to be verified using a
|
||||
NV counter, then the value of the counter to compare with can only be
|
||||
provided by the platform.
|
||||
|
||||
7. Export a custom IPM if a proprietary image format is being used (described
|
||||
later).
|
||||
|
||||
|
||||
#### 2.2.3 Authentication Module (AM)
|
||||
|
||||
It is responsible for:
|
||||
|
||||
1. Providing the necessary abstraction mechanisms to describe a CoT. Amongst
|
||||
other things, the authentication and image parsing methods must be specified
|
||||
by the PP in the CoT.
|
||||
|
||||
2. Verifying the CoT passed by GEN by utilising functionality exported by the
|
||||
PP, IPM and CM.
|
||||
|
||||
3. Tracking which images have been verified. In case an image is a part of
|
||||
multiple CoTs then it should be verified only once e.g. the Trusted World
|
||||
Key Certificate in the TBBR-Client spec. contains information to verify
|
||||
SCP_BL2, BL31, BL32 each of which have a separate CoT. (This
|
||||
responsibility has not been described in this document but should be
|
||||
trivial to implement).
|
||||
|
||||
4. Reusing memory meant for a data image to verify authentication images e.g.
|
||||
in the CoT described in Diagram 2, each certificate can be loaded and
|
||||
verified in the memory reserved by the platform for the BL31 image. By the
|
||||
time BL31 (the data image) is loaded, all information to authenticate it
|
||||
will have been extracted from the parent image i.e. BL31 content
|
||||
certificate. It is assumed that the size of an authentication image will
|
||||
never exceed the size of a data image. It should be possible to verify this
|
||||
at build time using asserts.
|
||||
|
||||
|
||||
#### 2.2.4 Cryptographic Module (CM)
|
||||
|
||||
The CM is responsible for providing an API to:
|
||||
|
||||
1. Verify a digital signature.
|
||||
2. Verify a hash.
|
||||
|
||||
The CM does not include any cryptography related code, but it relies on an
|
||||
external library to perform the cryptographic operations. A Crypto-Library (CL)
|
||||
linking the CM and the external library must be implemented. The following
|
||||
functions must be provided by the CL:
|
||||
|
||||
```
|
||||
void (*init)(void);
|
||||
int (*verify_signature)(void *data_ptr, unsigned int data_len,
|
||||
void *sig_ptr, unsigned int sig_len,
|
||||
void *sig_alg, unsigned int sig_alg_len,
|
||||
void *pk_ptr, unsigned int pk_len);
|
||||
int (*verify_hash)(void *data_ptr, unsigned int data_len,
|
||||
void *digest_info_ptr, unsigned int digest_info_len);
|
||||
```
|
||||
|
||||
These functions are registered in the CM using the macro:
|
||||
```
|
||||
REGISTER_CRYPTO_LIB(_name, _init, _verify_signature, _verify_hash);
|
||||
```
|
||||
|
||||
`_name` must be a string containing the name of the CL. This name is used for
|
||||
debugging purposes.
|
||||
|
||||
#### 2.2.5 Image Parser Module (IPM)
|
||||
|
||||
The IPM is responsible for:
|
||||
|
||||
1. Checking the integrity of each image loaded by the IO framework.
|
||||
2. Extracting parameters used for authenticating an image based upon a
|
||||
description provided by the platform in the CoT descriptor.
|
||||
|
||||
Images may have different formats (for example, authentication images could be
|
||||
x509v3 certificates, signed ELF files or any other platform specific format).
|
||||
The IPM allows to register an Image Parser Library (IPL) for every image format
|
||||
used in the CoT. This library must implement the specific methods to parse the
|
||||
image. The IPM obtains the image format from the CoT and calls the right IPL to
|
||||
check the image integrity and extract the authentication parameters.
|
||||
|
||||
See Section "Describing the image parsing methods" for more details about the
|
||||
mechanism the IPM provides to define and register IPLs.
|
||||
|
||||
|
||||
### 2.3 Authentication methods
|
||||
|
||||
The AM supports the following authentication methods:
|
||||
|
||||
1. Hash
|
||||
2. Digital signature
|
||||
|
||||
The platform may specify these methods in the CoT in case it decides to define
|
||||
a custom CoT instead of reusing a predefined one.
|
||||
|
||||
If a data image uses multiple methods, then all the methods must be a part of
|
||||
the same CoT. The number and type of parameters are method specific. These
|
||||
parameters should be obtained from the parent image using the IPM.
|
||||
|
||||
1. Hash
|
||||
|
||||
Parameters:
|
||||
|
||||
1. A pointer to data to hash
|
||||
2. Length of the data
|
||||
4. A pointer to the hash
|
||||
5. Length of the hash
|
||||
|
||||
The hash will be represented by the DER encoding of the following ASN.1
|
||||
type:
|
||||
|
||||
```
|
||||
DigestInfo ::= SEQUENCE {
|
||||
digestAlgorithm DigestAlgorithmIdentifier,
|
||||
digest Digest
|
||||
}
|
||||
```
|
||||
|
||||
This ASN.1 structure makes it possible to remove any assumption about the
|
||||
type of hash algorithm used as this information accompanies the hash. This
|
||||
should allow the Cryptography Library (CL) to support multiple hash
|
||||
algorithm implementations.
|
||||
|
||||
2. Digital Signature
|
||||
|
||||
Parameters:
|
||||
|
||||
1. A pointer to data to sign
|
||||
2. Length of the data
|
||||
3. Public Key Algorithm
|
||||
4. Public Key value
|
||||
5. Digital Signature Algorithm
|
||||
6. Digital Signature value
|
||||
|
||||
The Public Key parameters will be represented by the DER encoding of the
|
||||
following ASN.1 type:
|
||||
|
||||
```
|
||||
SubjectPublicKeyInfo ::= SEQUENCE {
|
||||
algorithm AlgorithmIdentifier{PUBLIC-KEY,{PublicKeyAlgorithms}},
|
||||
subjectPublicKey BIT STRING }
|
||||
```
|
||||
|
||||
The Digital Signature Algorithm will be represented by the DER encoding of
|
||||
the following ASN.1 types.
|
||||
|
||||
```
|
||||
AlgorithmIdentifier {ALGORITHM:IOSet } ::= SEQUENCE {
|
||||
algorithm ALGORITHM.&id({IOSet}),
|
||||
parameters ALGORITHM.&Type({IOSet}{@algorithm}) OPTIONAL
|
||||
}
|
||||
```
|
||||
|
||||
The digital signature will be represented by:
|
||||
```
|
||||
signature ::= BIT STRING
|
||||
```
|
||||
|
||||
The authentication framework will use the image descriptor to extract all the
|
||||
information related to authentication.
|
||||
|
||||
|
||||
3. Specifying a Chain of Trust
|
||||
-------------------------------
|
||||
|
||||
A CoT can be described as a set of image descriptors linked together in a
|
||||
particular order. The order dictates the sequence in which they must be
|
||||
verified. Each image has a set of properties which allow the AM to verify it.
|
||||
These properties are described below.
|
||||
|
||||
The PP is responsible for defining a single or multiple CoTs for a data image.
|
||||
Unless otherwise specified, the data structures described in the following
|
||||
sections are populated by the PP statically.
|
||||
|
||||
|
||||
### 3.1 Describing the image parsing methods
|
||||
|
||||
The parsing method refers to the format of a particular image. For example, an
|
||||
authentication image that represents a certificate could be in the X.509v3
|
||||
format. A data image that represents a boot loader stage could be in raw binary
|
||||
or ELF format. The IPM supports three parsing methods. An image has to use one
|
||||
of the three methods described below. An IPL is responsible for interpreting a
|
||||
single parsing method. There has to be one IPL for every method used by the
|
||||
platform.
|
||||
|
||||
1. Raw format: This format is effectively a nop as an image using this method
|
||||
is treated as being in raw binary format e.g. boot loader images used by ARM
|
||||
TF. This method should only be used by data images.
|
||||
|
||||
2. X509V3 method: This method uses industry standards like X.509 to represent
|
||||
PKI certificates (authentication images). It is expected that open source
|
||||
libraries will be available which can be used to parse an image represented
|
||||
by this method. Such libraries can be used to write the corresponding IPL
|
||||
e.g. the X.509 parsing library code in mbed TLS.
|
||||
|
||||
3. Platform defined method: This method caters for platform specific
|
||||
proprietary standards to represent authentication or data images. For
|
||||
example, The signature of a data image could be appended to the data image
|
||||
raw binary. A header could be prepended to the combined blob to specify the
|
||||
extents of each component. The platform will have to implement the
|
||||
corresponding IPL to interpret such a format.
|
||||
|
||||
The following enum can be used to define these three methods.
|
||||
|
||||
```
|
||||
typedef enum img_type_enum {
|
||||
IMG_RAW, /* Binary image */
|
||||
IMG_PLAT, /* Platform specific format */
|
||||
IMG_CERT, /* X509v3 certificate */
|
||||
IMG_MAX_TYPES,
|
||||
} img_type_t;
|
||||
```
|
||||
|
||||
An IPL must provide functions with the following prototypes:
|
||||
|
||||
```
|
||||
void init(void);
|
||||
int check_integrity(void *img, unsigned int img_len);
|
||||
int get_auth_param(const auth_param_type_desc_t *type_desc,
|
||||
void *img, unsigned int img_len,
|
||||
void **param, unsigned int *param_len);
|
||||
```
|
||||
|
||||
An IPL for each type must be registered using the following macro:
|
||||
|
||||
```
|
||||
REGISTER_IMG_PARSER_LIB(_type, _name, _init, _check_int, _get_param)
|
||||
```
|
||||
|
||||
* `_type`: one of the types described above.
|
||||
* `_name`: a string containing the IPL name for debugging purposes.
|
||||
* `_init`: initialization function pointer.
|
||||
* `_check_int`: check image integrity function pointer.
|
||||
* `_get_param`: extract authentication parameter funcion pointer.
|
||||
|
||||
The `init()` function will be used to initialize the IPL.
|
||||
|
||||
The `check_integrity()` function is passed a pointer to the memory where the
|
||||
image has been loaded by the IO framework and the image length. It should ensure
|
||||
that the image is in the format corresponding to the parsing method and has not
|
||||
been tampered with. For example, RFC-2459 describes a validation sequence for an
|
||||
X.509 certificate.
|
||||
|
||||
The `get_auth_param()` function is passed a parameter descriptor containing
|
||||
information about the parameter (`type_desc` and `cookie`) to identify and
|
||||
extract the data corresponding to that parameter from an image. This data will
|
||||
be used to verify either the current or the next image in the CoT sequence.
|
||||
|
||||
Each image in the CoT will specify the parsing method it uses. This information
|
||||
will be used by the IPM to find the right parser descriptor for the image.
|
||||
|
||||
|
||||
### 3.2 Describing the authentication method(s)
|
||||
|
||||
As part of the CoT, each image has to specify one or more authentication methods
|
||||
which will be used to verify it. As described in the Section "Authentication
|
||||
methods", there are three methods supported by the AM.
|
||||
|
||||
```
|
||||
typedef enum {
|
||||
AUTH_METHOD_NONE,
|
||||
AUTH_METHOD_HASH,
|
||||
AUTH_METHOD_SIG,
|
||||
AUTH_METHOD_NUM
|
||||
} auth_method_type_t;
|
||||
```
|
||||
|
||||
The AM defines the type of each parameter used by an authentication method. It
|
||||
uses this information to:
|
||||
|
||||
1. Specify to the `get_auth_param()` function exported by the IPM, which
|
||||
parameter should be extracted from an image.
|
||||
|
||||
2. Correctly marshall the parameters while calling the verification function
|
||||
exported by the CM and PP.
|
||||
|
||||
3. Extract authentication parameters from a parent image in order to verify a
|
||||
child image e.g. to verify the certificate image, the public key has to be
|
||||
obtained from the parent image.
|
||||
|
||||
```
|
||||
typedef enum {
|
||||
AUTH_PARAM_NONE,
|
||||
AUTH_PARAM_RAW_DATA, /* Raw image data */
|
||||
AUTH_PARAM_SIG, /* The image signature */
|
||||
AUTH_PARAM_SIG_ALG, /* The image signature algorithm */
|
||||
AUTH_PARAM_HASH, /* A hash (including the algorithm) */
|
||||
AUTH_PARAM_PUB_KEY, /* A public key */
|
||||
} auth_param_type_t;
|
||||
```
|
||||
|
||||
The AM defines the following structure to identify an authentication parameter
|
||||
required to verify an image.
|
||||
|
||||
```
|
||||
typedef struct auth_param_type_desc_s {
|
||||
auth_param_type_t type;
|
||||
void *cookie;
|
||||
} auth_param_type_desc_t;
|
||||
```
|
||||
|
||||
`cookie` is used by the platform to specify additional information to the IPM
|
||||
which enables it to uniquely identify the parameter that should be extracted
|
||||
from an image. For example, the hash of a BL3x image in its corresponding
|
||||
content certificate is stored in an X509v3 custom extension field. An extension
|
||||
field can only be identified using an OID. In this case, the `cookie` could
|
||||
contain the pointer to the OID defined by the platform for the hash extension
|
||||
field while the `type` field could be set to `AUTH_PARAM_HASH`. A value of 0 for
|
||||
the `cookie` field means that it is not used.
|
||||
|
||||
For each method, the AM defines a structure with the parameters required to
|
||||
verify the image.
|
||||
|
||||
```
|
||||
/*
|
||||
* Parameters for authentication by hash matching
|
||||
*/
|
||||
typedef struct auth_method_param_hash_s {
|
||||
auth_param_type_desc_t *data; /* Data to hash */
|
||||
auth_param_type_desc_t *hash; /* Hash to match with */
|
||||
} auth_method_param_hash_t;
|
||||
|
||||
/*
|
||||
* Parameters for authentication by signature
|
||||
*/
|
||||
typedef struct auth_method_param_sig_s {
|
||||
auth_param_type_desc_t *pk; /* Public key */
|
||||
auth_param_type_desc_t *sig; /* Signature to check */
|
||||
auth_param_type_desc_t *alg; /* Signature algorithm */
|
||||
auth_param_type_desc_t *tbs; /* Data signed */
|
||||
} auth_method_param_sig_t;
|
||||
|
||||
```
|
||||
|
||||
The AM defines the following structure to describe an authentication method for
|
||||
verifying an image
|
||||
|
||||
```
|
||||
/*
|
||||
* Authentication method descriptor
|
||||
*/
|
||||
typedef struct auth_method_desc_s {
|
||||
auth_method_type_t type;
|
||||
union {
|
||||
auth_method_param_hash_t hash;
|
||||
auth_method_param_sig_t sig;
|
||||
} param;
|
||||
} auth_method_desc_t;
|
||||
```
|
||||
|
||||
Using the method type specified in the `type` field, the AM finds out what field
|
||||
needs to access within the `param` union.
|
||||
|
||||
### 3.3 Storing Authentication parameters
|
||||
|
||||
A parameter described by `auth_param_type_desc_t` to verify an image could be
|
||||
obtained from either the image itself or its parent image. The memory allocated
|
||||
for loading the parent image will be reused for loading the child image. Hence
|
||||
parameters which are obtained from the parent for verifying a child image need
|
||||
to have memory allocated for them separately where they can be stored. This
|
||||
memory must be statically allocated by the platform port.
|
||||
|
||||
The AM defines the following structure to store the data corresponding to an
|
||||
authentication parameter.
|
||||
|
||||
```
|
||||
typedef struct auth_param_data_desc_s {
|
||||
void *auth_param_ptr;
|
||||
unsigned int auth_param_len;
|
||||
} auth_param_data_desc_t;
|
||||
```
|
||||
|
||||
The `auth_param_ptr` field is initialized by the platform. The `auth_param_len`
|
||||
field is used to specify the length of the data in the memory.
|
||||
|
||||
For parameters that can be obtained from the child image itself, the IPM is
|
||||
responsible for populating the `auth_param_ptr` and `auth_param_len` fields
|
||||
while executing the `img_get_auth_param()` function.
|
||||
|
||||
The AM defines the following structure to enable an image to describe the
|
||||
parameters that should be extracted from it and used to verify the next image
|
||||
(child) in a CoT.
|
||||
|
||||
```
|
||||
typedef struct auth_param_desc_s {
|
||||
auth_param_type_desc_t type_desc;
|
||||
auth_param_data_desc_t data;
|
||||
} auth_param_desc_t;
|
||||
```
|
||||
|
||||
### 3.4 Describing an image in a CoT
|
||||
|
||||
An image in a CoT is a consolidation of the following aspects of a CoT described
|
||||
above.
|
||||
|
||||
1. A unique identifier specified by the platform which allows the IO framework
|
||||
to locate the image in a FIP and load it in the memory reserved for the data
|
||||
image in the CoT.
|
||||
|
||||
2. A parsing method which is used by the AM to find the appropriate IPM.
|
||||
|
||||
3. Authentication methods and their parameters as described in the previous
|
||||
section. These are used to verify the current image.
|
||||
|
||||
4. Parameters which are used to verify the next image in the current CoT. These
|
||||
parameters are specified only by authentication images and can be extracted
|
||||
from the current image once it has been verified.
|
||||
|
||||
The following data structure describes an image in a CoT.
|
||||
```
|
||||
typedef struct auth_img_desc_s {
|
||||
unsigned int img_id;
|
||||
const struct auth_img_desc_s *parent;
|
||||
img_type_t img_type;
|
||||
auth_method_desc_t img_auth_methods[AUTH_METHOD_NUM];
|
||||
auth_param_desc_t authenticated_data[COT_MAX_VERIFIED_PARAMS];
|
||||
} auth_img_desc_t;
|
||||
```
|
||||
A CoT is defined as an array of `auth_image_desc_t` structures linked together
|
||||
by the `parent` field. Those nodes with no parent must be authenticated using
|
||||
the ROTPK stored in the platform.
|
||||
|
||||
|
||||
4. Implementation example
|
||||
--------------------------
|
||||
|
||||
This section is a detailed guide explaining a trusted boot implementation using
|
||||
the authentication framework. This example corresponds to the Applicative
|
||||
Functional Mode (AFM) as specified in the TBBR-Client document. It is
|
||||
recommended to read this guide along with the source code.
|
||||
|
||||
### 4.1 The TBBR CoT
|
||||
|
||||
The CoT can be found in `drivers/auth/tbbr/tbbr_cot.c`. This CoT consists of an
|
||||
array of image descriptors and it is registered in the framework using the macro
|
||||
`REGISTER_COT(cot_desc)`, where 'cot_desc' must be the name of the array
|
||||
(passing a pointer or any other type of indirection will cause the registration
|
||||
process to fail).
|
||||
|
||||
The number of images participating in the boot process depends on the CoT. There
|
||||
is, however, a minimum set of images that are mandatory in the Trusted Firmware
|
||||
and thus all CoTs must present:
|
||||
|
||||
* `BL2`
|
||||
* `SCP_BL2` (platform specific)
|
||||
* `BL31`
|
||||
* `BL32` (optional)
|
||||
* `BL33`
|
||||
|
||||
The TBBR specifies the additional certificates that must accompany these images
|
||||
for a proper authentication. Details about the TBBR CoT may be found in the
|
||||
[Trusted Board Boot] document.
|
||||
|
||||
Following the [Platform Porting Guide], a platform must provide unique
|
||||
identifiers for all the images and certificates that will be loaded during the
|
||||
boot process. If a platform is using the TBBR as a reference for trusted boot,
|
||||
these identifiers can be obtained from `include/common/tbbr/tbbr_img_def.h`.
|
||||
ARM platforms include this file in `include/plat/arm/common/arm_def.h`. Other
|
||||
platforms may also include this file or provide their own identifiers.
|
||||
|
||||
**Important**: the authentication module uses these identifiers to index the
|
||||
CoT array, so the descriptors location in the array must match the identifiers.
|
||||
|
||||
Each image descriptor must specify:
|
||||
|
||||
* `img_id`: the corresponding image unique identifier defined by the platform.
|
||||
* `img_type`: the image parser module uses the image type to call the proper
|
||||
parsing library to check the image integrity and extract the required
|
||||
authentication parameters. Three types of images are currently supported:
|
||||
* `IMG_RAW`: image is a raw binary. No parsing functions are available,
|
||||
other than reading the whole image.
|
||||
* `IMG_PLAT`: image format is platform specific. The platform may use this
|
||||
type for custom images not directly supported by the authentication
|
||||
framework.
|
||||
* `IMG_CERT`: image is an x509v3 certificate.
|
||||
* `parent`: pointer to the parent image descriptor. The parent will contain
|
||||
the information required to authenticate the current image. If the parent
|
||||
is NULL, the authentication parameters will be obtained from the platform
|
||||
(i.e. the BL2 and Trusted Key certificates are signed with the ROT private
|
||||
key, whose public part is stored in the platform).
|
||||
* `img_auth_methods`: this array defines the authentication methods that must
|
||||
be checked to consider an image authenticated. Each method consists of a
|
||||
type and a list of parameter descriptors. A parameter descriptor consists of
|
||||
a type and a cookie which will point to specific information required to
|
||||
extract that parameter from the image (i.e. if the parameter is stored in an
|
||||
x509v3 extension, the cookie will point to the extension OID). Depending on
|
||||
the method type, a different number of parameters must be specified.
|
||||
Supported methods are:
|
||||
* `AUTH_METHOD_HASH`: the hash of the image must match the hash extracted
|
||||
from the parent image. The following parameter descriptors must be
|
||||
specified:
|
||||
* `data`: data to be hashed (obtained from current image)
|
||||
* `hash`: reference hash (obtained from parent image)
|
||||
* `AUTH_METHOD_SIG`: the image (usually a certificate) must be signed with
|
||||
the private key whose public part is extracted from the parent image (or
|
||||
the platform if the parent is NULL). The following parameter descriptors
|
||||
must be specified:
|
||||
* `pk`: the public key (obtained from parent image)
|
||||
* `sig`: the digital signature (obtained from current image)
|
||||
* `alg`: the signature algorithm used (obtained from current image)
|
||||
* `data`: the data to be signed (obtained from current image)
|
||||
* `authenticated_data`: this array indicates what authentication parameters
|
||||
must be extracted from an image once it has been authenticated. Each
|
||||
parameter consists of a parameter descriptor and the buffer address/size
|
||||
to store the parameter. The CoT is responsible for allocating the required
|
||||
memory to store the parameters.
|
||||
|
||||
In the `tbbr_cot.c` file, a set of buffers are allocated to store the parameters
|
||||
extracted from the certificates. In the case of the TBBR CoT, these parameters
|
||||
are hashes and public keys. In DER format, an RSA-2048 public key requires 294
|
||||
bytes, and a hash requires 51 bytes. Depending on the CoT and the authentication
|
||||
process, some of the buffers may be reused at different stages during the boot.
|
||||
|
||||
Next in that file, the parameter descriptors are defined. These descriptors will
|
||||
be used to extract the parameter data from the corresponding image.
|
||||
|
||||
#### 4.1.1 Example: the BL31 Chain of Trust
|
||||
|
||||
Four image descriptors form the BL31 Chain of Trust:
|
||||
|
||||
```
|
||||
[TRUSTED_KEY_CERT_ID] = {
|
||||
.img_id = TRUSTED_KEY_CERT_ID,
|
||||
.img_type = IMG_CERT,
|
||||
.parent = NULL,
|
||||
.img_auth_methods = {
|
||||
[0] = {
|
||||
.type = AUTH_METHOD_SIG,
|
||||
.param.sig = {
|
||||
.pk = &subject_pk,
|
||||
.sig = &sig,
|
||||
.alg = &sig_alg,
|
||||
.data = &raw_data,
|
||||
}
|
||||
}
|
||||
},
|
||||
.authenticated_data = {
|
||||
[0] = {
|
||||
.type_desc = &trusted_world_pk,
|
||||
.data = {
|
||||
.ptr = (void *)trusted_world_pk_buf,
|
||||
.len = (unsigned int)PK_DER_LEN
|
||||
}
|
||||
},
|
||||
[1] = {
|
||||
.type_desc = &non_trusted_world_pk,
|
||||
.data = {
|
||||
.ptr = (void *)non_trusted_world_pk_buf,
|
||||
.len = (unsigned int)PK_DER_LEN
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
[SOC_FW_KEY_CERT_ID] = {
|
||||
.img_id = SOC_FW_KEY_CERT_ID,
|
||||
.img_type = IMG_CERT,
|
||||
.parent = &cot_desc[TRUSTED_KEY_CERT_ID],
|
||||
.img_auth_methods = {
|
||||
[0] = {
|
||||
.type = AUTH_METHOD_SIG,
|
||||
.param.sig = {
|
||||
.pk = &trusted_world_pk,
|
||||
.sig = &sig,
|
||||
.alg = &sig_alg,
|
||||
.data = &raw_data,
|
||||
}
|
||||
}
|
||||
},
|
||||
.authenticated_data = {
|
||||
[0] = {
|
||||
.type_desc = &soc_fw_content_pk,
|
||||
.data = {
|
||||
.ptr = (void *)content_pk_buf,
|
||||
.len = (unsigned int)PK_DER_LEN
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
[SOC_FW_CONTENT_CERT_ID] = {
|
||||
.img_id = SOC_FW_CONTENT_CERT_ID,
|
||||
.img_type = IMG_CERT,
|
||||
.parent = &cot_desc[SOC_FW_KEY_CERT_ID],
|
||||
.img_auth_methods = {
|
||||
[0] = {
|
||||
.type = AUTH_METHOD_SIG,
|
||||
.param.sig = {
|
||||
.pk = &soc_fw_content_pk,
|
||||
.sig = &sig,
|
||||
.alg = &sig_alg,
|
||||
.data = &raw_data,
|
||||
}
|
||||
}
|
||||
},
|
||||
.authenticated_data = {
|
||||
[0] = {
|
||||
.type_desc = &soc_fw_hash,
|
||||
.data = {
|
||||
.ptr = (void *)soc_fw_hash_buf,
|
||||
.len = (unsigned int)HASH_DER_LEN
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
[BL31_IMAGE_ID] = {
|
||||
.img_id = BL31_IMAGE_ID,
|
||||
.img_type = IMG_RAW,
|
||||
.parent = &cot_desc[SOC_FW_CONTENT_CERT_ID],
|
||||
.img_auth_methods = {
|
||||
[0] = {
|
||||
.type = AUTH_METHOD_HASH,
|
||||
.param.hash = {
|
||||
.data = &raw_data,
|
||||
.hash = &soc_fw_hash,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
The **Trusted Key certificate** is signed with the ROT private key and contains
|
||||
the Trusted World public key and the Non-Trusted World public key as x509v3
|
||||
extensions. This must be specified in the image descriptor using the
|
||||
`img_auth_methods` and `authenticated_data` arrays, respectively.
|
||||
|
||||
The Trusted Key certificate is authenticated by checking its digital signature
|
||||
using the ROTPK. Four parameters are required to check a signature: the public
|
||||
key, the algorithm, the signature and the data that has been signed. Therefore,
|
||||
four parameter descriptors must be specified with the authentication method:
|
||||
|
||||
* `subject_pk`: parameter descriptor of type `AUTH_PARAM_PUB_KEY`. This type
|
||||
is used to extract a public key from the parent image. If the cookie is an
|
||||
OID, the key is extracted from the corresponding x509v3 extension. If the
|
||||
cookie is NULL, the subject public key is retrieved. In this case, because
|
||||
the parent image is NULL, the public key is obtained from the platform
|
||||
(this key will be the ROTPK).
|
||||
* `sig`: parameter descriptor of type `AUTH_PARAM_SIG`. It is used to extract
|
||||
the signature from the certificate.
|
||||
* `sig_alg`: parameter descriptor of type `AUTH_PARAM_SIG`. It is used to
|
||||
extract the signature algorithm from the certificate.
|
||||
* `raw_data`: parameter descriptor of type `AUTH_PARAM_RAW_DATA`. It is used
|
||||
to extract the data to be signed from the certificate.
|
||||
|
||||
Once the signature has been checked and the certificate authenticated, the
|
||||
Trusted World public key needs to be extracted from the certificate. A new entry
|
||||
is created in the `authenticated_data` array for that purpose. In that entry,
|
||||
the corresponding parameter descriptor must be specified along with the buffer
|
||||
address to store the parameter value. In this case, the `tz_world_pk` descriptor
|
||||
is used to extract the public key from an x509v3 extension with OID
|
||||
`TRUSTED_WORLD_PK_OID`. The BL31 key certificate will use this descriptor as
|
||||
parameter in the signature authentication method. The key is stored in the
|
||||
`plat_tz_world_pk_buf` buffer.
|
||||
|
||||
The **BL31 Key certificate** is authenticated by checking its digital signature
|
||||
using the Trusted World public key obtained previously from the Trusted Key
|
||||
certificate. In the image descriptor, we specify a single authentication method
|
||||
by signature whose public key is the `tz_world_pk`. Once this certificate has
|
||||
been authenticated, we have to extract the BL31 public key, stored in the
|
||||
extension specified by `bl31_content_pk`. This key will be copied to the
|
||||
`plat_content_pk` buffer.
|
||||
|
||||
The **BL31 certificate** is authenticated by checking its digital signature
|
||||
using the BL31 public key obtained previously from the BL31 Key certificate.
|
||||
We specify the authentication method using `bl31_content_pk` as public key.
|
||||
After authentication, we need to extract the BL31 hash, stored in the extension
|
||||
specified by `bl31_hash`. This hash will be copied to the `plat_bl31_hash_buf`
|
||||
buffer.
|
||||
|
||||
The **BL31 image** is authenticated by calculating its hash and matching it
|
||||
with the hash obtained from the BL31 certificate. The image descriptor contains
|
||||
a single authentication method by hash. The parameters to the hash method are
|
||||
the reference hash, `bl31_hash`, and the data to be hashed. In this case, it is
|
||||
the whole image, so we specify `raw_data`.
|
||||
|
||||
### 4.2 The image parser library
|
||||
|
||||
The image parser module relies on libraries to check the image integrity and
|
||||
extract the authentication parameters. The number and type of parser libraries
|
||||
depend on the images used in the CoT. Raw images do not need a library, so
|
||||
only an x509v3 library is required for the TBBR CoT.
|
||||
|
||||
ARM platforms will use an x509v3 library based on mbed TLS. This library may be
|
||||
found in `drivers/auth/mbedtls/mbedtls_x509_parser.c`. It exports three
|
||||
functions:
|
||||
|
||||
```
|
||||
void init(void);
|
||||
int check_integrity(void *img, unsigned int img_len);
|
||||
int get_auth_param(const auth_param_type_desc_t *type_desc,
|
||||
void *img, unsigned int img_len,
|
||||
void **param, unsigned int *param_len);
|
||||
```
|
||||
|
||||
The library is registered in the framework using the macro
|
||||
`REGISTER_IMG_PARSER_LIB()`. Each time the image parser module needs to access
|
||||
an image of type `IMG_CERT`, it will call the corresponding function exported
|
||||
in this file.
|
||||
|
||||
The build system must be updated to include the corresponding library and
|
||||
mbed TLS sources. ARM platforms use the `arm_common.mk` file to pull the
|
||||
sources.
|
||||
|
||||
### 4.3 The cryptographic library
|
||||
|
||||
The cryptographic module relies on a library to perform the required operations,
|
||||
i.e. verify a hash or a digital signature. ARM platforms will use a library
|
||||
based on mbed TLS, which can be found in
|
||||
`drivers/auth/mbedtls/mbedtls_crypto.c`. This library is registered in the
|
||||
authentication framework using the macro `REGISTER_CRYPTO_LIB()` and exports
|
||||
three functions:
|
||||
|
||||
```
|
||||
void init(void);
|
||||
int verify_signature(void *data_ptr, unsigned int data_len,
|
||||
void *sig_ptr, unsigned int sig_len,
|
||||
void *sig_alg, unsigned int sig_alg_len,
|
||||
void *pk_ptr, unsigned int pk_len);
|
||||
int verify_hash(void *data_ptr, unsigned int data_len,
|
||||
void *digest_info_ptr, unsigned int digest_info_len);
|
||||
```
|
||||
|
||||
The key algorithm (rsa, ecdsa) must be specified in the build system using the
|
||||
`TF_MBEDTLS_KEY_ALG` variable, so the Makefile can include the corresponding
|
||||
sources in the build.
|
||||
|
||||
Note: If code size is a concern, the build option `MBEDTLS_SHA256_SMALLER` can
|
||||
be defined in the platform Makefile. It will make mbed TLS use an implementation
|
||||
of SHA-256 with smaller memory footprint (~1.5 KB less) but slower (~30%).
|
||||
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
_Copyright (c) 2015, ARM Limited and Contributors. All rights reserved._
|
||||
|
||||
|
||||
[Trusted Board Boot]: ./trusted-board-boot.md
|
||||
[Platform Porting Guide]: ./porting-guide.md
|
1103
docs/change-log.md
1103
docs/change-log.md
File diff suppressed because it is too large
Load diff
|
@ -1,132 +0,0 @@
|
|||
ARM CPU Specific Build Macros
|
||||
=============================
|
||||
|
||||
Contents
|
||||
--------
|
||||
|
||||
1. [Introduction](#1--introduction)
|
||||
2. [CPU Errata Workarounds](#2--cpu-errata-workarounds)
|
||||
3. [CPU Specific optimizations](#3--cpu-specific-optimizations)
|
||||
|
||||
|
||||
1. Introduction
|
||||
----------------
|
||||
|
||||
This document describes the various build options present in the CPU specific
|
||||
operations framework to enable errata workarounds and to enable optimizations
|
||||
for a specific CPU on a platform.
|
||||
|
||||
2. CPU Errata Workarounds
|
||||
--------------------------
|
||||
|
||||
ARM Trusted Firmware exports a series of build flags which control the
|
||||
errata workarounds that are applied to each CPU by the reset handler. The
|
||||
errata details can be found in the CPU specific errata documents published
|
||||
by ARM:
|
||||
|
||||
* [Cortex-A53 MPCore Software Developers Errata Notice][A53 Errata Notice]
|
||||
* [Cortex-A57 MPCore Software Developers Errata Notice][A57 Errata Notice]
|
||||
|
||||
The errata workarounds are implemented for a particular revision or a set of
|
||||
processor revisions. This is checked by the reset handler at runtime. Each
|
||||
errata workaround is identified by its `ID` as specified in the processor's
|
||||
errata notice document. The format of the define used to enable/disable the
|
||||
errata workaround is `ERRATA_<Processor name>_<ID>`, where the `Processor name`
|
||||
is for example `A57` for the `Cortex_A57` CPU.
|
||||
|
||||
Refer to the section _CPU errata status reporting_ in [Firmware Design
|
||||
guide][Firmware Design] for information on to write errata workaround functions.
|
||||
|
||||
All workarounds are disabled by default. The platform is responsible for
|
||||
enabling these workarounds according to its requirement by defining the
|
||||
errata workaround build flags in the platform specific makefile. In case
|
||||
these workarounds are enabled for the wrong CPU revision then the errata
|
||||
workaround is not applied. In the DEBUG build, this is indicated by
|
||||
printing a warning to the crash console.
|
||||
|
||||
In the current implementation, a platform which has more than 1 variant
|
||||
with different revisions of a processor has no runtime mechanism available
|
||||
for it to specify which errata workarounds should be enabled or not.
|
||||
|
||||
The value of the build flags are 0 by default, that is, disabled. Any other
|
||||
value will enable it.
|
||||
|
||||
For Cortex-A53, following errata build flags are defined :
|
||||
|
||||
* `ERRATA_A53_826319`: This applies errata 826319 workaround to Cortex-A53
|
||||
CPU. This needs to be enabled only for revision <= r0p2 of the CPU.
|
||||
|
||||
* `ERRATA_A53_836870`: This applies errata 836870 workaround to Cortex-A53
|
||||
CPU. This needs to be enabled only for revision <= r0p3 of the CPU. From
|
||||
r0p4 and onwards, this errata is enabled by default in hardware.
|
||||
|
||||
* `ERRATA_A53_855873`: This applies errata 855873 workaround to Cortex-A53
|
||||
CPUs. Though the erratum is present in every revision of the CPU,
|
||||
this workaround is only applied to CPUs from r0p3 onwards, which feature
|
||||
a chicken bit in CPUACTLR_EL1 to enable a hardware workaround.
|
||||
Earlier revisions of the CPU have other errata which require the same
|
||||
workaround in software, so they should be covered anyway.
|
||||
|
||||
For Cortex-A57, following errata build flags are defined :
|
||||
|
||||
* `ERRATA_A57_806969`: This applies errata 806969 workaround to Cortex-A57
|
||||
CPU. This needs to be enabled only for revision r0p0 of the CPU.
|
||||
|
||||
* `ERRATA_A57_813419`: This applies errata 813419 workaround to Cortex-A57
|
||||
CPU. This needs to be enabled only for revision r0p0 of the CPU.
|
||||
|
||||
* `ERRATA_A57_813420`: This applies errata 813420 workaround to Cortex-A57
|
||||
CPU. This needs to be enabled only for revision r0p0 of the CPU.
|
||||
|
||||
* `ERRATA_A57_826974`: This applies errata 826974 workaround to Cortex-A57
|
||||
CPU. This needs to be enabled only for revision <= r1p1 of the CPU.
|
||||
|
||||
* `ERRATA_A57_826977`: This applies errata 826977 workaround to Cortex-A57
|
||||
CPU. This needs to be enabled only for revision <= r1p1 of the CPU.
|
||||
|
||||
* `ERRATA_A57_828024`: This applies errata 828024 workaround to Cortex-A57
|
||||
CPU. This needs to be enabled only for revision <= r1p1 of the CPU.
|
||||
|
||||
* `ERRATA_A57_829520`: This applies errata 829520 workaround to Cortex-A57
|
||||
CPU. This needs to be enabled only for revision <= r1p2 of the CPU.
|
||||
|
||||
* `ERRATA_A57_833471`: This applies errata 833471 workaround to Cortex-A57
|
||||
CPU. This needs to be enabled only for revision <= r1p2 of the CPU.
|
||||
|
||||
3. CPU Specific optimizations
|
||||
------------------------------
|
||||
|
||||
This section describes some of the optimizations allowed by the CPU micro
|
||||
architecture that can be enabled by the platform as desired.
|
||||
|
||||
* `SKIP_A57_L1_FLUSH_PWR_DWN`: This flag enables an optimization in the
|
||||
Cortex-A57 cluster power down sequence by not flushing the Level 1 data
|
||||
cache. The L1 data cache and the L2 unified cache are inclusive. A flush
|
||||
of the L2 by set/way flushes any dirty lines from the L1 as well. This
|
||||
is a known safe deviation from the Cortex-A57 TRM defined power down
|
||||
sequence. Each Cortex-A57 based platform must make its own decision on
|
||||
whether to use the optimization.
|
||||
|
||||
* `A53_DISABLE_NON_TEMPORAL_HINT`: This flag disables the cache non-temporal
|
||||
hint. The LDNP/STNP instructions as implemented on Cortex-A53 do not behave
|
||||
in a way most programmers expect, and will most probably result in a
|
||||
significant speed degradation to any code that employs them. The ARMv8-A
|
||||
architecture (see ARM DDI 0487A.h, section D3.4.3) allows cores to ignore
|
||||
the non-temporal hint and treat LDNP/STNP as LDP/STP instead. Enabling this
|
||||
flag enforces this behaviour. This needs to be enabled only for revisions
|
||||
<= r0p3 of the CPU and is enabled by default.
|
||||
|
||||
* `A57_DISABLE_NON_TEMPORAL_HINT`: This flag has the same behaviour as
|
||||
`A53_DISABLE_NON_TEMPORAL_HINT` but for Cortex-A57. This needs to be
|
||||
enabled only for revisions <= r1p2 of the CPU and is enabled by default,
|
||||
as recommended in section "4.7 Non-Temporal Loads/Stores" of the
|
||||
[Cortex-A57 Software Optimization Guide][A57 SW Optimization Guide].
|
||||
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
_Copyright (c) 2014-2016, ARM Limited and Contributors. All rights reserved._
|
||||
|
||||
[A57 SW Optimization Guide]: http://infocenter.arm.com/help/topic/com.arm.doc.uan0015b/Cortex_A57_Software_Optimization_Guide_external.pdf
|
||||
[A53 Errata Notice]: http://infocenter.arm.com/help/topic/com.arm.doc.epm048406/index.html
|
||||
[A57 Errata Notice]: http://infocenter.arm.com/help/topic/com.arm.doc.epm049219/cortex_a57_mpcore_software_developers_errata_notice.pdf
|
||||
[Firmware Design]: firmware-design.md
|
File diff suppressed because it is too large
Load diff
|
@ -1,388 +0,0 @@
|
|||
ARM Trusted Firmware - Firmware Update Design Guide
|
||||
===================================================
|
||||
|
||||
Contents :
|
||||
|
||||
1. [Introduction](#1--introduction)
|
||||
2. [FWU Overview](#2--fwu-overview)
|
||||
3. [Image Identification](#3--image-identification)
|
||||
4. [FWU State Machine](#4--fwu-state-machine)
|
||||
5. [BL1 SMC Interface](#5--bl1-smc-interface)
|
||||
|
||||
- - - - - - - - - - - - - - - - - -
|
||||
|
||||
1. Introduction
|
||||
----------------
|
||||
|
||||
This document describes the design of the Firmware Update (FWU) feature, which
|
||||
enables authenticated firmware to update firmware images from external
|
||||
interfaces such as USB, UART, SD-eMMC, NAND, NOR or Ethernet to SoC Non-Volatile
|
||||
memories such as NAND Flash, LPPDR2-NVM or any memory determined by the
|
||||
platform. This feature functions even when the current firmware in the system
|
||||
is corrupt or missing; it therefore may be used as a recovery mode. It may also
|
||||
be complemented by other, higher level firmware update software.
|
||||
|
||||
FWU implements a specific part of the Trusted Board Boot Requirements (TBBR)
|
||||
specification, ARM DEN0006C-1. It should be used in conjunction with the
|
||||
[Trusted Board Boot] design document, which describes the image authentication
|
||||
parts of the Trusted Firmware (TF) TBBR implementation.
|
||||
|
||||
### Scope
|
||||
|
||||
This document describes the secure world FWU design. It is beyond its scope to
|
||||
describe how normal world FWU images should operate. To implement normal world
|
||||
FWU images, please refer to the "Non-Trusted Firmware Updater" requirements in
|
||||
the TBBR.
|
||||
|
||||
|
||||
2. FWU Overview
|
||||
----------------
|
||||
|
||||
The FWU boot flow is primarily mediated by BL1. Since BL1 executes in ROM, and
|
||||
it is usually desirable to minimize the amount of ROM code, the design allows
|
||||
some parts of FWU to be implemented in other secure and normal world images.
|
||||
Platform code may choose which parts are implemented in which images but the
|
||||
general expectation is:
|
||||
|
||||
* BL1 handles:
|
||||
* Detection and initiation of the FWU boot flow.
|
||||
* Copying images from non-secure to secure memory
|
||||
* FWU image authentication
|
||||
* Context switching between the normal and secure world during the FWU
|
||||
process.
|
||||
* Other secure world FWU images handle platform initialization required by
|
||||
the FWU process.
|
||||
* Normal world FWU images handle loading of firmware images from external
|
||||
interfaces to non-secure memory.
|
||||
|
||||
The primary requirements of the FWU feature are:
|
||||
|
||||
1. Export a BL1 SMC interface to interoperate with other FWU images executing
|
||||
at other Exception Levels.
|
||||
2. Export a platform interface to provide FWU common code with the information
|
||||
it needs, and to enable platform specific FWU functionality. See the
|
||||
[Porting Guide] for details of this interface.
|
||||
|
||||
TF uses abbreviated image terminology for FWU images like for other TF images.
|
||||
An overview of this terminology can be found [here][TF Image Terminology].
|
||||
|
||||
The following diagram shows the FWU boot flow for ARM development platforms.
|
||||
ARM CSS platforms like Juno have a System Control Processor (SCP), and these
|
||||
use all defined FWU images. Other platforms may use a subset of these.
|
||||
|
||||

|
||||
|
||||
|
||||
3. Image Identification
|
||||
------------------------
|
||||
|
||||
Each FWU image and certificate is identified by a unique ID, defined by the
|
||||
platform, which BL1 uses to fetch an image descriptor (`image_desc_t`) via a
|
||||
call to `bl1_plat_get_image_desc()`. The same ID is also used to prepare the
|
||||
Chain of Trust (Refer to the [Authentication Framework Design][Auth Framework]
|
||||
for more information).
|
||||
|
||||
The image descriptor includes the following information:
|
||||
|
||||
* Executable or non-executable image. This indicates whether the normal world
|
||||
is permitted to request execution of a secure world FWU image (after
|
||||
authentication). Secure world certificates and non-AP images are examples
|
||||
of non-executable images.
|
||||
* Secure or non-secure image. This indicates whether the image is
|
||||
authenticated/executed in secure or non-secure memory.
|
||||
* Image base address and size.
|
||||
* Image entry point configuration (an `entry_point_info_t`).
|
||||
* FWU image state.
|
||||
|
||||
BL1 uses the FWU image descriptors to:
|
||||
|
||||
* Validate the arguments of FWU SMCs
|
||||
* Manage the state of the FWU process
|
||||
* Initialize the execution state of the next FWU image.
|
||||
|
||||
|
||||
4. FWU State Machine
|
||||
---------------------
|
||||
|
||||
BL1 maintains state for each FWU image during FWU execution. FWU images at lower
|
||||
Exception Levels raise SMCs to invoke FWU functionality in BL1, which causes
|
||||
BL1 to update its FWU image state. The BL1 image states and valid state
|
||||
transitions are shown in the diagram below. Note that secure images have a more
|
||||
complex state machine than non-secure images.
|
||||
|
||||

|
||||
|
||||
The following is a brief description of the supported states:
|
||||
|
||||
* RESET: This is the initial state of every image at the start of FWU.
|
||||
Authentication failure also leads to this state. A secure
|
||||
image may yield to this state if it has completed execution.
|
||||
It can also be reached by using `FWU_SMC_IMAGE_RESET`.
|
||||
|
||||
* COPYING: This is the state of a secure image while BL1 is copying it
|
||||
in blocks from non-secure to secure memory.
|
||||
|
||||
* COPIED: This is the state of a secure image when BL1 has completed
|
||||
copying it to secure memory.
|
||||
|
||||
* AUTHENTICATED: This is the state of an image when BL1 has successfully
|
||||
authenticated it.
|
||||
|
||||
* EXECUTED: This is the state of a secure, executable image when BL1 has
|
||||
passed execution control to it.
|
||||
|
||||
* INTERRUPTED: This is the state of a secure, executable image after it has
|
||||
requested BL1 to resume normal world execution.
|
||||
|
||||
|
||||
5. BL1 SMC Interface
|
||||
---------------------
|
||||
|
||||
### BL1_SMC_CALL_COUNT
|
||||
|
||||
Arguments:
|
||||
uint32_t function ID : 0x0
|
||||
|
||||
Return:
|
||||
uint32_t
|
||||
|
||||
This SMC returns the number of SMCs supported by BL1.
|
||||
|
||||
### BL1_SMC_UID
|
||||
|
||||
Arguments:
|
||||
uint32_t function ID : 0x1
|
||||
|
||||
Return:
|
||||
UUID : 32 bits in each of w0-w3 (or r0-r3 for AArch32 callers)
|
||||
|
||||
This SMC returns the 128-bit [Universally Unique Identifier][UUID] for the
|
||||
BL1 SMC service.
|
||||
|
||||
### BL1_SMC_VERSION
|
||||
|
||||
Argument:
|
||||
uint32_t function ID : 0x3
|
||||
|
||||
Return:
|
||||
uint32_t : Bits [31:16] Major Version
|
||||
Bits [15:0] Minor Version
|
||||
|
||||
This SMC returns the current version of the BL1 SMC service.
|
||||
|
||||
### BL1_SMC_RUN_IMAGE
|
||||
|
||||
Arguments:
|
||||
uint32_t function ID : 0x4
|
||||
entry_point_info_t *ep_info
|
||||
|
||||
Return:
|
||||
void
|
||||
|
||||
Pre-conditions:
|
||||
if (normal world caller) synchronous exception
|
||||
if (ep_info not EL3) synchronous exception
|
||||
|
||||
This SMC passes execution control to an EL3 image described by the provided
|
||||
`entry_point_info_t` structure. In the normal TF boot flow, BL2 invokes this SMC
|
||||
for BL1 to pass execution control to BL31.
|
||||
|
||||
|
||||
### FWU_SMC_IMAGE_COPY
|
||||
|
||||
Arguments:
|
||||
uint32_t function ID : 0x10
|
||||
unsigned int image_id
|
||||
uintptr_t image_addr
|
||||
unsigned int block_size
|
||||
unsigned int image_size
|
||||
|
||||
Return:
|
||||
int : 0 (Success)
|
||||
: -ENOMEM
|
||||
: -EPERM
|
||||
|
||||
Pre-conditions:
|
||||
if (image_id is invalid) return -EPERM
|
||||
if (image_id is non-secure image) return -EPERM
|
||||
if (image_id state is not (RESET or COPYING)) return -EPERM
|
||||
if (secure world caller) return -EPERM
|
||||
if (image_addr + block_size overflows) return -ENOMEM
|
||||
if (image destination address + image_size overflows) return -ENOMEM
|
||||
if (source block is in secure memory) return -ENOMEM
|
||||
if (source block is not mapped into BL1) return -ENOMEM
|
||||
if (image_size > free secure memory) return -ENOMEM
|
||||
if (image overlaps another image) return -EPERM
|
||||
|
||||
This SMC copies the secure image indicated by `image_id` from non-secure memory
|
||||
to secure memory for later authentication. The image may be copied in a single
|
||||
block or multiple blocks. In either case, the total size of the image must be
|
||||
provided in `image_size` when invoking this SMC for the first time for each
|
||||
image; it is ignored in subsequent calls (if any) for the same image.
|
||||
|
||||
The `image_addr` and `block_size` specify the source memory block to copy from.
|
||||
The destination address is provided by the platform code.
|
||||
|
||||
If `block_size` is greater than the amount of remaining bytes to copy for this
|
||||
image then the former is truncated to the latter. The copy operation is then
|
||||
considered as complete and the FWU state machine transitions to the "COPIED"
|
||||
state. If there is still more to copy, the FWU state machine stays in or
|
||||
transitions to the COPYING state (depending on the previous state).
|
||||
|
||||
When using multiple blocks, the source blocks do not necessarily need to be in
|
||||
contiguous memory.
|
||||
|
||||
Once the SMC is handled, BL1 returns from exception to the normal world caller.
|
||||
|
||||
|
||||
### FWU_SMC_IMAGE_AUTH
|
||||
|
||||
Arguments:
|
||||
uint32_t function ID : 0x11
|
||||
unsigned int image_id
|
||||
uintptr_t image_addr
|
||||
unsigned int image_size
|
||||
|
||||
Return:
|
||||
int : 0 (Success)
|
||||
: -ENOMEM
|
||||
: -EPERM
|
||||
: -EAUTH
|
||||
|
||||
Pre-conditions:
|
||||
if (image_id is invalid) return -EPERM
|
||||
if (secure world caller)
|
||||
if (image_id state is not RESET) return -EPERM
|
||||
if (image_addr/image_size is not mappped into BL1) return -ENOMEM
|
||||
else // normal world caller
|
||||
if (image_id is secure image)
|
||||
if (image_id state is not COPIED) return -EPERM
|
||||
else // image_id is non-secure image
|
||||
if (image_id state is not RESET) return -EPERM
|
||||
if (image_addr/image_size is in secure memory) return -ENOMEM
|
||||
if (image_addr/image_size not mappped into BL1) return -ENOMEM
|
||||
|
||||
This SMC authenticates the image specified by `image_id`. If the image is in the
|
||||
RESET state, BL1 authenticates the image in place using the provided
|
||||
`image_addr` and `image_size`. If the image is a secure image in the COPIED
|
||||
state, BL1 authenticates the image from the secure memory that BL1 previously
|
||||
copied the image into.
|
||||
|
||||
BL1 returns from exception to the caller. If authentication succeeds then BL1
|
||||
sets the image state to AUTHENTICATED. If authentication fails then BL1 returns
|
||||
the -EAUTH error and sets the image state back to RESET.
|
||||
|
||||
|
||||
### FWU_SMC_IMAGE_EXECUTE
|
||||
|
||||
Arguments:
|
||||
uint32_t function ID : 0x12
|
||||
unsigned int image_id
|
||||
|
||||
Return:
|
||||
int : 0 (Success)
|
||||
: -EPERM
|
||||
|
||||
Pre-conditions:
|
||||
if (image_id is invalid) return -EPERM
|
||||
if (secure world caller) return -EPERM
|
||||
if (image_id is non-secure image) return -EPERM
|
||||
if (image_id is non-executable image) return -EPERM
|
||||
if (image_id state is not AUTHENTICATED) return -EPERM
|
||||
|
||||
This SMC initiates execution of a previously authenticated image specified by
|
||||
`image_id`, in the other security world to the caller. The current
|
||||
implementation only supports normal world callers initiating execution of a
|
||||
secure world image.
|
||||
|
||||
BL1 saves the normal world caller's context, sets the secure image state to
|
||||
EXECUTED, and returns from exception to the secure image.
|
||||
|
||||
|
||||
### FWU_SMC_IMAGE_RESUME
|
||||
|
||||
Arguments:
|
||||
uint32_t function ID : 0x13
|
||||
register_t image_param
|
||||
|
||||
Return:
|
||||
register_t : image_param (Success)
|
||||
: -EPERM
|
||||
|
||||
Pre-conditions:
|
||||
if (normal world caller and no INTERRUPTED secure image) return -EPERM
|
||||
|
||||
This SMC resumes execution in the other security world while there is a secure
|
||||
image in the EXECUTED/INTERRUPTED state.
|
||||
|
||||
For normal world callers, BL1 sets the previously interrupted secure image state
|
||||
to EXECUTED. For secure world callers, BL1 sets the previously executing secure
|
||||
image state to INTERRUPTED. In either case, BL1 saves the calling world's
|
||||
context, restores the resuming world's context and returns from exception into
|
||||
the resuming world. If the call is successful then the caller provided
|
||||
`image_param` is returned to the resumed world, otherwise an error code is
|
||||
returned to the caller.
|
||||
|
||||
|
||||
### FWU_SMC_SEC_IMAGE_DONE
|
||||
|
||||
Arguments:
|
||||
uint32_t function ID : 0x14
|
||||
|
||||
Return:
|
||||
int : 0 (Success)
|
||||
: -EPERM
|
||||
|
||||
Pre-conditions:
|
||||
if (normal world caller) return -EPERM
|
||||
|
||||
This SMC indicates completion of a previously executing secure image.
|
||||
|
||||
BL1 sets the previously executing secure image state to the RESET state,
|
||||
restores the normal world context and returns from exception into the normal
|
||||
world.
|
||||
|
||||
|
||||
### FWU_SMC_UPDATE_DONE
|
||||
|
||||
Arguments:
|
||||
uint32_t function ID : 0x15
|
||||
register_t client_cookie
|
||||
|
||||
Return:
|
||||
N/A
|
||||
|
||||
This SMC completes the firmware update process. BL1 calls the platform specific
|
||||
function `bl1_plat_fwu_done`, passing the optional argument `client_cookie` as
|
||||
a `void *`. The SMC does not return.
|
||||
|
||||
|
||||
### FWU_SMC_IMAGE_RESET
|
||||
|
||||
Arguments:
|
||||
uint32_t function ID : 0x16
|
||||
unsigned int image_id
|
||||
|
||||
Return:
|
||||
int : 0 (Success)
|
||||
: -EPERM
|
||||
|
||||
Pre-conditions:
|
||||
if (secure world caller) return -EPERM
|
||||
if (image in EXECUTED) return -EPERM
|
||||
|
||||
This SMC sets the state of an image to RESET and zeroes the memory used by it.
|
||||
|
||||
This is only allowed if the image is not being executed.
|
||||
|
||||
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
_Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved._
|
||||
|
||||
|
||||
[Porting Guide]: ./porting-guide.md
|
||||
[Auth Framework]: ./auth-framework.md
|
||||
[Trusted Board Boot]: ./trusted-board-boot.md
|
||||
[TF Image Terminology]: https://github.com/ARM-software/arm-trusted-firmware/wiki/ARM-Trusted-Firmware-Image-Terminology
|
||||
[UUID]: https://tools.ietf.org/rfc/rfc4122.txt "A Universally Unique IDentifier (UUID) URN Namespace"
|
|
@ -1,997 +0,0 @@
|
|||
ARM Trusted Firmware Interrupt Management Design guide
|
||||
======================================================
|
||||
|
||||
Contents :
|
||||
|
||||
1. [Introduction](#1-introduction)
|
||||
* [Concepts](#11-concepts)
|
||||
- [Interrupt Types](#111-interrupt-types)
|
||||
- [Routing Model](#112-routing-model)
|
||||
- [Valid Routing Models](#113-valid-routing-models)
|
||||
+ [Secure-EL1 Interrupts](#1131-secure-el1-interrupts)
|
||||
+ [Non-secure Interrupts](#1132-non-secure-interrupts)
|
||||
+ [EL3 interrupts](#1133-el3-interrupts)
|
||||
- [Mapping of Interrupt Type to Signal](#114-mapping-of-interrupt-type-to-signal)
|
||||
+ [Effect of mapping of several interrupt types to one signal](#1141-effect-of-mapping-of-several-interrupt-types-to-one-signal)
|
||||
- [Assumptions in Interrupt Management Framework](#12-assumptions-in-interrupt-management-framework)
|
||||
|
||||
2. [Interrupt Management](#2-interrupt-management)
|
||||
* [Software Components](#21-software-components)
|
||||
* [Interrupt Registration](#22-interrupt-registration)
|
||||
- [EL3 Runtime Firmware](#221-el3-runtime-firmware)
|
||||
- [Secure Payload Dispatcher](#222-secure-payload-dispatcher)
|
||||
+ [Test Secure Payload Dispatcher behavior](#2221-test-secure-payload-dispatcher-behavior)
|
||||
- [Secure Payload](#223-secure-payload)
|
||||
+ [Secure Payload IHF design w.r.t Secure-EL1 interrupts](#2231-secure-payload-ihf-design-wrt-secure-el1-interrupts)
|
||||
+ [Secure Payload IHF design w.r.t Non-secure interrupts](#2232-secure-payload-ihf-design-wrt-non-secure-interrupts)
|
||||
+ [Test Secure Payload behavior](#2233-test-secure-payload-behavior)
|
||||
* [Interrupt Handling](#23-interrupt-handling)
|
||||
- [EL3 Runtime Firmware](#231-el3-runtime-firmware)
|
||||
- [Secure Payload Dispatcher](#232-secure-payload-dispatcher)
|
||||
+ [Interrupt Entry](#2321-interrupt-entry)
|
||||
+ [Interrupt Exit](#2322-interrupt-exit)
|
||||
+ [Test secure payload dispatcher Secure-EL1 interrupt handling](#2323-test-secure-payload-dispatcher-secure-el1-interrupt-handling)
|
||||
+ [Test secure payload dispatcher non-secure interrupt handling](#2324-test-secure-payload-dispatcher-non-secure-interrupt-handling)
|
||||
- [Secure Payload](#233-secure-payload)
|
||||
+ [Test Secure Payload behavior](#2331-test-secure-payload-behavior)
|
||||
|
||||
3. [Other considerations](#3-other-considerations)
|
||||
* [Implication of preempted SMC on Non-Secure Software](#31-implication-of-preempted-smc-on-non-secure-software)
|
||||
|
||||
|
||||
1. Introduction
|
||||
----------------
|
||||
This document describes the design of the Interrupt management framework in ARM
|
||||
Trusted Firmware. This section briefly describes the requirements from this
|
||||
framework. It also briefly explains some concepts and assumptions. They will
|
||||
help in understanding the implementation of the framework explained in
|
||||
subsequent sections.
|
||||
|
||||
This framework is responsible for managing interrupts routed to EL3. It also
|
||||
allows EL3 software to configure the interrupt routing behavior. Its main
|
||||
objective is to implement the following two requirements.
|
||||
|
||||
1. It should be possible to route interrupts meant to be handled by secure
|
||||
software (Secure interrupts) to EL3, when execution is in non-secure state
|
||||
(normal world). The framework should then take care of handing control of
|
||||
the interrupt to either software in EL3 or Secure-EL1 depending upon the
|
||||
software configuration and the GIC implementation. This requirement ensures
|
||||
that secure interrupts are under the control of the secure software with
|
||||
respect to their delivery and handling without the possibility of
|
||||
intervention from non-secure software.
|
||||
|
||||
2. It should be possible to route interrupts meant to be handled by
|
||||
non-secure software (Non-secure interrupts) to the last executed exception
|
||||
level in the normal world when the execution is in secure world at
|
||||
exception levels lower than EL3. This could be done with or without the
|
||||
knowledge of software executing in Secure-EL1/Secure-EL0. The choice of
|
||||
approach should be governed by the secure software. This requirement
|
||||
ensures that non-secure software is able to execute in tandem with the
|
||||
secure software without overriding it.
|
||||
|
||||
### 1.1 Concepts
|
||||
|
||||
#### 1.1.1 Interrupt types
|
||||
The framework categorises an interrupt to be one of the following depending upon
|
||||
the exception level(s) it is handled in.
|
||||
|
||||
1. Secure EL1 interrupt. This type of interrupt can be routed to EL3 or
|
||||
Secure-EL1 depending upon the security state of the current execution
|
||||
context. It is always handled in Secure-EL1.
|
||||
|
||||
2. Non-secure interrupt. This type of interrupt can be routed to EL3,
|
||||
Secure-EL1, Non-secure EL1 or EL2 depending upon the security state of the
|
||||
current execution context. It is always handled in either Non-secure EL1
|
||||
or EL2.
|
||||
|
||||
3. EL3 interrupt. This type of interrupt can be routed to EL3 or Secure-EL1
|
||||
depending upon the security state of the current execution context. It is
|
||||
always handled in EL3.
|
||||
|
||||
The following constants define the various interrupt types in the framework
|
||||
implementation.
|
||||
|
||||
#define INTR_TYPE_S_EL1 0
|
||||
#define INTR_TYPE_EL3 1
|
||||
#define INTR_TYPE_NS 2
|
||||
|
||||
|
||||
#### 1.1.2 Routing model
|
||||
A type of interrupt can be either generated as an FIQ or an IRQ. The target
|
||||
exception level of an interrupt type is configured through the FIQ and IRQ bits
|
||||
in the Secure Configuration Register at EL3 (`SCR_EL3.FIQ` and `SCR_EL3.IRQ`
|
||||
bits). When `SCR_EL3.FIQ`=1, FIQs are routed to EL3. Otherwise they are routed
|
||||
to the First Exception Level (FEL) capable of handling interrupts. When
|
||||
`SCR_EL3.IRQ`=1, IRQs are routed to EL3. Otherwise they are routed to the
|
||||
FEL. This register is configured independently by EL3 software for each security
|
||||
state prior to entry into a lower exception level in that security state.
|
||||
|
||||
A routing model for a type of interrupt (generated as FIQ or IRQ) is defined as
|
||||
its target exception level for each security state. It is represented by a
|
||||
single bit for each security state. A value of `0` means that the interrupt
|
||||
should be routed to the FEL. A value of `1` means that the interrupt should be
|
||||
routed to EL3. A routing model is applicable only when execution is not in EL3.
|
||||
|
||||
The default routing model for an interrupt type is to route it to the FEL in
|
||||
either security state.
|
||||
|
||||
|
||||
#### 1.1.3 Valid routing models
|
||||
The framework considers certain routing models for each type of interrupt to be
|
||||
incorrect as they conflict with the requirements mentioned in Section 1. The
|
||||
following sub-sections describe all the possible routing models and specify
|
||||
which ones are valid or invalid. EL3 interrupts are currently supported only
|
||||
for GIC version 3.0 (ARM GICv3) and only the Secure-EL1 and Non-secure interrupt
|
||||
types are supported for GIC version 2.0 (ARM GICv2) (See 1.2). The terminology
|
||||
used in the following sub-sections is explained below.
|
||||
|
||||
1. __CSS__. Current Security State. `0` when secure and `1` when non-secure
|
||||
|
||||
2. __TEL3__. Target Exception Level 3. `0` when targeted to the FEL. `1` when
|
||||
targeted to EL3.
|
||||
|
||||
|
||||
##### 1.1.3.1 Secure-EL1 interrupts
|
||||
|
||||
1. __CSS=0, TEL3=0__. Interrupt is routed to the FEL when execution is in
|
||||
secure state. This is a valid routing model as secure software is in
|
||||
control of handling secure interrupts.
|
||||
|
||||
2. __CSS=0, TEL3=1__. Interrupt is routed to EL3 when execution is in secure
|
||||
state. This is a valid routing model as secure software in EL3 can
|
||||
handover the interrupt to Secure-EL1 for handling.
|
||||
|
||||
3. __CSS=1, TEL3=0__. Interrupt is routed to the FEL when execution is in
|
||||
non-secure state. This is an invalid routing model as a secure interrupt
|
||||
is not visible to the secure software which violates the motivation behind
|
||||
the ARM Security Extensions.
|
||||
|
||||
4. __CSS=1, TEL3=1__. Interrupt is routed to EL3 when execution is in
|
||||
non-secure state. This is a valid routing model as secure software in EL3
|
||||
can handover the interrupt to Secure-EL1 for handling.
|
||||
|
||||
|
||||
##### 1.1.3.2 Non-secure interrupts
|
||||
|
||||
1. __CSS=0, TEL3=0__. Interrupt is routed to the FEL when execution is in
|
||||
secure state. This allows the secure software to trap non-secure
|
||||
interrupts, perform its book-keeping and hand the interrupt to the
|
||||
non-secure software through EL3. This is a valid routing model as secure
|
||||
software is in control of how its execution is preempted by non-secure
|
||||
interrupts.
|
||||
|
||||
2. __CSS=0, TEL3=1__. Interrupt is routed to EL3 when execution is in secure
|
||||
state. This is a valid routing model as secure software in EL3 can save
|
||||
the state of software in Secure-EL1/Secure-EL0 before handing the
|
||||
interrupt to non-secure software. This model requires additional
|
||||
coordination between Secure-EL1 and EL3 software to ensure that the
|
||||
former's state is correctly saved by the latter.
|
||||
|
||||
3. __CSS=1, TEL3=0__. Interrupt is routed to FEL when execution is in
|
||||
non-secure state. This is an valid routing model as a non-secure interrupt
|
||||
is handled by non-secure software.
|
||||
|
||||
4. __CSS=1, TEL3=1__. Interrupt is routed to EL3 when execution is in
|
||||
non-secure state. This is an invalid routing model as there is no valid
|
||||
reason to route the interrupt to EL3 software and then hand it back to
|
||||
non-secure software for handling.
|
||||
|
||||
|
||||
##### 1.1.3.3 EL3 interrupts
|
||||
|
||||
1. __CSS=0, TEL3=0__. Interrupt is routed to the FEL when execution is in
|
||||
Secure-EL1/Secure-EL0. This is a valid routing model as secure software
|
||||
in Secure-EL1/Secure-EL0 is in control of how its execution is preempted
|
||||
by EL3 interrupt and can handover the interrupt to EL3 for handling.
|
||||
|
||||
2. __CSS=0, TEL3=1__. Interrupt is routed to EL3 when execution is in
|
||||
Secure-EL1/Secure-EL0. This is a valid routing model as secure software
|
||||
in EL3 can handle the interrupt.
|
||||
|
||||
3. __CSS=1, TEL3=0__. Interrupt is routed to the FEL when execution is in
|
||||
non-secure state. This is an invalid routing model as a secure interrupt
|
||||
is not visible to the secure software which violates the motivation behind
|
||||
the ARM Security Extensions.
|
||||
|
||||
4. __CSS=1, TEL3=1__. Interrupt is routed to EL3 when execution is in
|
||||
non-secure state. This is a valid routing model as secure software in EL3
|
||||
can handle the interrupt.
|
||||
|
||||
|
||||
#### 1.1.4 Mapping of interrupt type to signal
|
||||
The framework is meant to work with any interrupt controller implemented by a
|
||||
platform. A interrupt controller could generate a type of interrupt as either an
|
||||
FIQ or IRQ signal to the CPU depending upon the current security state. The
|
||||
mapping between the type and signal is known only to the platform. The framework
|
||||
uses this information to determine whether the IRQ or the FIQ bit should be
|
||||
programmed in `SCR_EL3` while applying the routing model for a type of
|
||||
interrupt. The platform provides this information through the
|
||||
`plat_interrupt_type_to_line()` API (described in the [Porting
|
||||
Guide]). For example, on the FVP port when the platform uses an ARM GICv2
|
||||
interrupt controller, Secure-EL1 interrupts are signaled through the FIQ signal
|
||||
while Non-secure interrupts are signaled through the IRQ signal. This applies
|
||||
when execution is in either security state.
|
||||
|
||||
|
||||
##### 1.1.4.1 Effect of mapping of several interrupt types to one signal
|
||||
It should be noted that if more than one interrupt type maps to a single
|
||||
interrupt signal, and if any one of the interrupt type sets __TEL3=1__ for a
|
||||
particular security state, then interrupt signal will be routed to EL3 when in
|
||||
that security state. This means that all the other interrupt types using the
|
||||
same interrupt signal will be forced to the same routing model. This should be
|
||||
borne in mind when choosing the routing model for an interrupt type.
|
||||
|
||||
For example, in ARM GICv3, when the execution context is Secure-EL1/
|
||||
Secure-EL0, both the EL3 and the non secure interrupt types map to the FIQ
|
||||
signal. So if either one of the interrupt type sets the routing model so
|
||||
that __TEL3=1__ when __CSS=0__, the FIQ bit in `SCR_EL3` will be programmed to
|
||||
route the FIQ signal to EL3 when executing in Secure-EL1/Secure-EL0, thereby
|
||||
effectively routing the other interrupt type also to EL3.
|
||||
|
||||
|
||||
### 1.2 Assumptions in Interrupt Management Framework
|
||||
The framework makes the following assumptions to simplify its implementation.
|
||||
|
||||
1. Although the framework has support for 2 types of secure interrupts (EL3
|
||||
and Secure-EL1 interrupt), only interrupt controller architectures
|
||||
like ARM GICv3 has architectural support for EL3 interrupts in the form of
|
||||
Group 0 interrupts. In ARM GICv2, all secure interrupts are assumed to be
|
||||
handled in Secure-EL1. They can be delivered to Secure-EL1 via EL3 but they
|
||||
cannot be handled in EL3.
|
||||
|
||||
2. Interrupt exceptions (`PSTATE.I` and `F` bits) are masked during execution
|
||||
in EL3.
|
||||
|
||||
|
||||
2. Interrupt management
|
||||
-----------------------
|
||||
The following sections describe how interrupts are managed by the interrupt
|
||||
handling framework. This entails:
|
||||
|
||||
1. Providing an interface to allow registration of a handler and specification
|
||||
of the routing model for a type of interrupt.
|
||||
|
||||
2. Implementing support to hand control of an interrupt type to its registered
|
||||
handler when the interrupt is generated.
|
||||
|
||||
Both aspects of interrupt management involve various components in the secure
|
||||
software stack spanning from EL3 to Secure-EL1. These components are described
|
||||
in the section 2.1. The framework stores information associated with each type
|
||||
of interrupt in the following data structure.
|
||||
|
||||
```
|
||||
typedef struct intr_type_desc {
|
||||
interrupt_type_handler_t handler;
|
||||
uint32_t flags;
|
||||
uint32_t scr_el3[2];
|
||||
} intr_type_desc_t;
|
||||
```
|
||||
|
||||
The `flags` field stores the routing model for the interrupt type in
|
||||
bits[1:0]. Bit[0] stores the routing model when execution is in the secure
|
||||
state. Bit[1] stores the routing model when execution is in the non-secure
|
||||
state. As mentioned in Section 1.2.2, a value of `0` implies that the interrupt
|
||||
should be targeted to the FEL. A value of `1` implies that it should be targeted
|
||||
to EL3. The remaining bits are reserved and SBZ. The helper macro
|
||||
`set_interrupt_rm_flag()` should be used to set the bits in the `flags`
|
||||
parameter.
|
||||
|
||||
The `scr_el3[2]` field also stores the routing model but as a mapping of the
|
||||
model in the `flags` field to the corresponding bit in the `SCR_EL3` for each
|
||||
security state.
|
||||
|
||||
The framework also depends upon the platform port to configure the interrupt
|
||||
controller to distinguish between secure and non-secure interrupts. The platform
|
||||
is expected to be aware of the secure devices present in the system and their
|
||||
associated interrupt numbers. It should configure the interrupt controller to
|
||||
enable the secure interrupts, ensure that their priority is always higher than
|
||||
the non-secure interrupts and target them to the primary CPU. It should also
|
||||
export the interface described in the [Porting Guide] to enable
|
||||
handling of interrupts.
|
||||
|
||||
In the remainder of this document, for the sake of simplicity a ARM GICv2 system
|
||||
is considered and it is assumed that the FIQ signal is used to generate Secure-EL1
|
||||
interrupts and the IRQ signal is used to generate non-secure interrupts in either
|
||||
security state. EL3 interrupts are not considered.
|
||||
|
||||
|
||||
### 2.1 Software components
|
||||
Roles and responsibilities for interrupt management are sub-divided between the
|
||||
following components of software running in EL3 and Secure-EL1. Each component is
|
||||
briefly described below.
|
||||
|
||||
1. EL3 Runtime Firmware. This component is common to all ports of the ARM
|
||||
Trusted Firmware.
|
||||
|
||||
2. Secure Payload Dispatcher (SPD) service. This service interfaces with the
|
||||
Secure Payload (SP) software which runs in Secure-EL1/Secure-EL0 and is
|
||||
responsible for switching execution between secure and non-secure states.
|
||||
A switch is triggered by a Secure Monitor Call and it uses the APIs
|
||||
exported by the Context management library to implement this functionality.
|
||||
Switching execution between the two security states is a requirement for
|
||||
interrupt management as well. This results in a significant dependency on
|
||||
the SPD service. ARM Trusted firmware implements an example Test Secure
|
||||
Payload Dispatcher (TSPD) service.
|
||||
|
||||
An SPD service plugs into the EL3 runtime firmware and could be common to
|
||||
some ports of the ARM Trusted Firmware.
|
||||
|
||||
3. Secure Payload (SP). On a production system, the Secure Payload corresponds
|
||||
to a Secure OS which runs in Secure-EL1/Secure-EL0. It interfaces with the
|
||||
SPD service to manage communication with non-secure software. ARM Trusted
|
||||
Firmware implements an example secure payload called Test Secure Payload
|
||||
(TSP) which runs only in Secure-EL1.
|
||||
|
||||
A Secure payload implementation could be common to some ports of the ARM
|
||||
Trusted Firmware just like the SPD service.
|
||||
|
||||
|
||||
### 2.2 Interrupt registration
|
||||
This section describes in detail the role of each software component (see 2.1)
|
||||
during the registration of a handler for an interrupt type.
|
||||
|
||||
|
||||
#### 2.2.1 EL3 runtime firmware
|
||||
This component declares the following prototype for a handler of an interrupt type.
|
||||
|
||||
typedef uint64_t (*interrupt_type_handler_t)(uint32_t id,
|
||||
uint32_t flags,
|
||||
void *handle,
|
||||
void *cookie);
|
||||
|
||||
The `id` is parameter is reserved and could be used in the future for passing
|
||||
the interrupt id of the highest pending interrupt only if there is a foolproof
|
||||
way of determining the id. Currently it contains `INTR_ID_UNAVAILABLE`.
|
||||
|
||||
The `flags` parameter contains miscellaneous information as follows.
|
||||
|
||||
1. Security state, bit[0]. This bit indicates the security state of the lower
|
||||
exception level when the interrupt was generated. A value of `1` means
|
||||
that it was in the non-secure state. A value of `0` indicates that it was
|
||||
in the secure state. This bit can be used by the handler to ensure that
|
||||
interrupt was generated and routed as per the routing model specified
|
||||
during registration.
|
||||
|
||||
2. Reserved, bits[31:1]. The remaining bits are reserved for future use.
|
||||
|
||||
The `handle` parameter points to the `cpu_context` structure of the current CPU
|
||||
for the security state specified in the `flags` parameter.
|
||||
|
||||
Once the handler routine completes, execution will return to either the secure
|
||||
or non-secure state. The handler routine must return a pointer to
|
||||
`cpu_context` structure of the current CPU for the target security state. On
|
||||
AArch64, this return value is currently ignored by the caller as the
|
||||
appropriate `cpu_context` to be used is expected to be set by the handler
|
||||
via the context management library APIs.
|
||||
A portable interrupt handler implementation must set the target context both in
|
||||
the structure pointed to by the returned pointer and via the context management
|
||||
library APIs. The handler should treat all error conditions as critical errors
|
||||
and take appropriate action within its implementation e.g. use assertion
|
||||
failures.
|
||||
|
||||
The runtime firmware provides the following API for registering a handler for a
|
||||
particular type of interrupt. A Secure Payload Dispatcher service should use
|
||||
this API to register a handler for Secure-EL1 and optionally for non-secure
|
||||
interrupts. This API also requires the caller to specify the routing model for
|
||||
the type of interrupt.
|
||||
|
||||
int32_t register_interrupt_type_handler(uint32_t type,
|
||||
interrupt_type_handler handler,
|
||||
uint64_t flags);
|
||||
|
||||
|
||||
The `type` parameter can be one of the three interrupt types listed above i.e.
|
||||
`INTR_TYPE_S_EL1`, `INTR_TYPE_NS` & `INTR_TYPE_EL3`. The `flags` parameter
|
||||
is as described in Section 2.
|
||||
|
||||
The function will return `0` upon a successful registration. It will return
|
||||
`-EALREADY` in case a handler for the interrupt type has already been
|
||||
registered. If the `type` is unrecognised or the `flags` or the `handler` are
|
||||
invalid it will return `-EINVAL`.
|
||||
|
||||
Interrupt routing is governed by the configuration of the `SCR_EL3.FIQ/IRQ` bits
|
||||
prior to entry into a lower exception level in either security state. The
|
||||
context management library maintains a copy of the `SCR_EL3` system register for
|
||||
each security state in the `cpu_context` structure of each CPU. It exports the
|
||||
following APIs to let EL3 Runtime Firmware program and retrieve the routing
|
||||
model for each security state for the current CPU. The value of `SCR_EL3` stored
|
||||
in the `cpu_context` is used by the `el3_exit()` function to program the
|
||||
`SCR_EL3` register prior to returning from the EL3 exception level.
|
||||
|
||||
uint32_t cm_get_scr_el3(uint32_t security_state);
|
||||
void cm_write_scr_el3_bit(uint32_t security_state,
|
||||
uint32_t bit_pos,
|
||||
uint32_t value);
|
||||
|
||||
`cm_get_scr_el3()` returns the value of the `SCR_EL3` register for the specified
|
||||
security state of the current CPU. `cm_write_scr_el3()` writes a `0` or `1` to
|
||||
the bit specified by `bit_pos`. `register_interrupt_type_handler()` invokes
|
||||
`set_routing_model()` API which programs the `SCR_EL3` according to the routing
|
||||
model using the `cm_get_scr_el3()` and `cm_write_scr_el3_bit()` APIs.
|
||||
|
||||
It is worth noting that in the current implementation of the framework, the EL3
|
||||
runtime firmware is responsible for programming the routing model. The SPD is
|
||||
responsible for ensuring that the routing model has been adhered to upon
|
||||
receiving an interrupt.
|
||||
|
||||
|
||||
#### 2.2.2 Secure payload dispatcher
|
||||
A SPD service is responsible for determining and maintaining the interrupt
|
||||
routing model supported by itself and the Secure Payload. It is also responsible
|
||||
for ferrying interrupts between secure and non-secure software depending upon
|
||||
the routing model. It could determine the routing model at build time or at
|
||||
runtime. It must use this information to register a handler for each interrupt
|
||||
type using the `register_interrupt_type_handler()` API in EL3 runtime firmware.
|
||||
|
||||
If the routing model is not known to the SPD service at build time, then it must
|
||||
be provided by the SP as the result of its initialisation. The SPD should
|
||||
program the routing model only after SP initialisation has completed e.g. in the
|
||||
SPD initialisation function pointed to by the `bl32_init` variable.
|
||||
|
||||
The SPD should determine the mechanism to pass control to the Secure Payload
|
||||
after receiving an interrupt from the EL3 runtime firmware. This information
|
||||
could either be provided to the SPD service at build time or by the SP at
|
||||
runtime.
|
||||
|
||||
|
||||
#### 2.2.2.1 Test secure payload dispatcher behavior
|
||||
The TSPD only handles Secure-EL1 interrupts and is provided with the following
|
||||
routing model at build time.
|
||||
|
||||
* Secure-EL1 interrupts are routed to EL3 when execution is in non-secure
|
||||
state and are routed to the FEL when execution is in the secure state
|
||||
i.e __CSS=0, TEL3=0__ & __CSS=1, TEL3=1__ for Secure-EL1 interrupts
|
||||
|
||||
* When the build flag `TSP_NS_INTR_ASYNC_PREEMPT` is zero, the default routing
|
||||
model is used for non-secure interrupts. They are routed to the FEL in
|
||||
either security state i.e __CSS=0, TEL3=0__ & __CSS=1, TEL3=0__ for
|
||||
Non-secure interrupts.
|
||||
|
||||
* When the build flag `TSP_NS_INTR_ASYNC_PREEMPT` is defined to 1, then the
|
||||
non secure interrupts are routed to EL3 when execution is in secure state
|
||||
i.e __CSS=0, TEL3=1__ for non-secure interrupts. This effectively preempts
|
||||
Secure-EL1. The default routing model is used for non secure interrupts in
|
||||
non-secure state. i.e __CSS=1, TEL3=0__.
|
||||
|
||||
It performs the following actions in the `tspd_init()` function to fulfill the
|
||||
requirements mentioned earlier.
|
||||
|
||||
1. It passes control to the Test Secure Payload to perform its
|
||||
initialisation. The TSP provides the address of the vector table
|
||||
`tsp_vectors` in the SP which also includes the handler for Secure-EL1
|
||||
interrupts in the `sel1_intr_entry` field. The TSPD passes control to the TSP at
|
||||
this address when it receives a Secure-EL1 interrupt.
|
||||
|
||||
The handover agreement between the TSP and the TSPD requires that the TSPD
|
||||
masks all interrupts (`PSTATE.DAIF` bits) when it calls
|
||||
`tsp_sel1_intr_entry()`. The TSP has to preserve the callee saved general
|
||||
purpose, SP_EL1/Secure-EL0, LR, VFP and system registers. It can use
|
||||
`x0-x18` to enable its C runtime.
|
||||
|
||||
2. The TSPD implements a handler function for Secure-EL1 interrupts. This
|
||||
function is registered with the EL3 runtime firmware using the
|
||||
`register_interrupt_type_handler()` API as follows
|
||||
|
||||
/* Forward declaration */
|
||||
interrupt_type_handler tspd_secure_el1_interrupt_handler;
|
||||
int32_t rc, flags = 0;
|
||||
set_interrupt_rm_flag(flags, NON_SECURE);
|
||||
rc = register_interrupt_type_handler(INTR_TYPE_S_EL1,
|
||||
tspd_secure_el1_interrupt_handler,
|
||||
flags);
|
||||
if (rc)
|
||||
panic();
|
||||
|
||||
3. When the build flag `TSP_NS_INTR_ASYNC_PREEMPT` is defined to 1, the TSPD
|
||||
implements a handler function for non-secure interrupts. This function is
|
||||
registered with the EL3 runtime firmware using the
|
||||
`register_interrupt_type_handler()` API as follows
|
||||
|
||||
/* Forward declaration */
|
||||
interrupt_type_handler tspd_ns_interrupt_handler;
|
||||
int32_t rc, flags = 0;
|
||||
set_interrupt_rm_flag(flags, SECURE);
|
||||
rc = register_interrupt_type_handler(INTR_TYPE_NS,
|
||||
tspd_ns_interrupt_handler,
|
||||
flags);
|
||||
if (rc)
|
||||
panic();
|
||||
|
||||
|
||||
#### 2.2.3 Secure payload
|
||||
A Secure Payload must implement an interrupt handling framework at Secure-EL1
|
||||
(Secure-EL1 IHF) to support its chosen interrupt routing model. Secure payload
|
||||
execution will alternate between the below cases.
|
||||
|
||||
1. In the code where IRQ, FIQ or both interrupts are enabled, if an interrupt
|
||||
type is targeted to the FEL, then it will be routed to the Secure-EL1
|
||||
exception vector table. This is defined as the __asynchronous mode__ of
|
||||
handling interrupts. This mode applies to both Secure-EL1 and non-secure
|
||||
interrupts.
|
||||
|
||||
2. In the code where both interrupts are disabled, if an interrupt type is
|
||||
targeted to the FEL, then execution will eventually migrate to the
|
||||
non-secure state. Any non-secure interrupts will be handled as described
|
||||
in the routing model where __CSS=1 and TEL3=0__. Secure-EL1 interrupts
|
||||
will be routed to EL3 (as per the routing model where __CSS=1 and
|
||||
TEL3=1__) where the SPD service will hand them to the SP. This is defined
|
||||
as the __synchronous mode__ of handling interrupts.
|
||||
|
||||
The interrupt handling framework implemented by the SP should support one or
|
||||
both these interrupt handling models depending upon the chosen routing model.
|
||||
|
||||
The following list briefly describes how the choice of a valid routing model
|
||||
(See 1.2.3) effects the implementation of the Secure-EL1 IHF. If the choice of
|
||||
the interrupt routing model is not known to the SPD service at compile time,
|
||||
then the SP should pass this information to the SPD service at runtime during
|
||||
its initialisation phase.
|
||||
|
||||
As mentioned earlier, a ARM GICv2 system is considered and it is assumed that
|
||||
the FIQ signal is used to generate Secure-EL1 interrupts and the IRQ signal
|
||||
is used to generate non-secure interrupts in either security state.
|
||||
|
||||
|
||||
##### 2.2.3.1 Secure payload IHF design w.r.t secure-EL1 interrupts
|
||||
1. __CSS=0, TEL3=0__. If `PSTATE.F=0`, Secure-EL1 interrupts will be
|
||||
triggered at one of the Secure-EL1 FIQ exception vectors. The Secure-EL1
|
||||
IHF should implement support for handling FIQ interrupts asynchronously.
|
||||
|
||||
If `PSTATE.F=1` then Secure-EL1 interrupts will be handled as per the
|
||||
synchronous interrupt handling model. The SP could implement this scenario
|
||||
by exporting a separate entrypoint for Secure-EL1 interrupts to the SPD
|
||||
service during the registration phase. The SPD service would also need to
|
||||
know the state of the system, general purpose and the `PSTATE` registers
|
||||
in which it should arrange to return execution to the SP. The SP should
|
||||
provide this information in an implementation defined way during the
|
||||
registration phase if it is not known to the SPD service at build time.
|
||||
|
||||
2. __CSS=1, TEL3=1__. Interrupts are routed to EL3 when execution is in
|
||||
non-secure state. They should be handled through the synchronous interrupt
|
||||
handling model as described in 1. above.
|
||||
|
||||
3. __CSS=0, TEL3=1__. Secure-EL1 interrupts are routed to EL3 when execution
|
||||
is in secure state. They will not be visible to the SP. The `PSTATE.F` bit
|
||||
in Secure-EL1/Secure-EL0 will not mask FIQs. The EL3 runtime firmware will
|
||||
call the handler registered by the SPD service for Secure-EL1 interrupts.
|
||||
Secure-EL1 IHF should then handle all Secure-EL1 interrupt through the
|
||||
synchronous interrupt handling model described in 1. above.
|
||||
|
||||
|
||||
##### 2.2.3.2 Secure payload IHF design w.r.t non-secure interrupts
|
||||
1. __CSS=0, TEL3=0__. If `PSTATE.I=0`, non-secure interrupts will be
|
||||
triggered at one of the Secure-EL1 IRQ exception vectors . The Secure-EL1
|
||||
IHF should co-ordinate with the SPD service to transfer execution to the
|
||||
non-secure state where the interrupt should be handled e.g the SP could
|
||||
allocate a function identifier to issue a SMC64 or SMC32 to the SPD
|
||||
service which indicates that the SP execution has been preempted by a
|
||||
non-secure interrupt. If this function identifier is not known to the SPD
|
||||
service at compile time then the SP could provide it during the
|
||||
registration phase.
|
||||
|
||||
If `PSTATE.I=1` then the non-secure interrupt will pend until execution
|
||||
resumes in the non-secure state.
|
||||
|
||||
2. __CSS=0, TEL3=1__. Non-secure interrupts are routed to EL3. They will not
|
||||
be visible to the SP. The `PSTATE.I` bit in Secure-EL1/Secure-EL0 will
|
||||
have not effect. The SPD service should register a non-secure interrupt
|
||||
handler which should save the SP state correctly and resume execution in
|
||||
the non-secure state where the interrupt will be handled. The Secure-EL1
|
||||
IHF does not need to take any action.
|
||||
|
||||
3. __CSS=1, TEL3=0__. Non-secure interrupts are handled in the FEL in
|
||||
non-secure state (EL1/EL2) and are not visible to the SP. This routing
|
||||
model does not affect the SP behavior.
|
||||
|
||||
A Secure Payload must also ensure that all Secure-EL1 interrupts are correctly
|
||||
configured at the interrupt controller by the platform port of the EL3 runtime
|
||||
firmware. It should configure any additional Secure-EL1 interrupts which the EL3
|
||||
runtime firmware is not aware of through its platform port.
|
||||
|
||||
|
||||
#### 2.2.3.3 Test secure payload behavior
|
||||
The routing model for Secure-EL1 and non-secure interrupts chosen by the TSP is
|
||||
described in Section 2.2.2. It is known to the TSPD service at build time.
|
||||
|
||||
The TSP implements an entrypoint (`tsp_sel1_intr_entry()`) for handling Secure-EL1
|
||||
interrupts taken in non-secure state and routed through the TSPD service
|
||||
(synchronous handling model). It passes the reference to this entrypoint via
|
||||
`tsp_vectors` to the TSPD service.
|
||||
|
||||
The TSP also replaces the default exception vector table referenced through the
|
||||
`early_exceptions` variable, with a vector table capable of handling FIQ and IRQ
|
||||
exceptions taken at the same (Secure-EL1) exception level. This table is
|
||||
referenced through the `tsp_exceptions` variable and programmed into the
|
||||
VBAR_EL1. It caters for the asynchronous handling model.
|
||||
|
||||
The TSP also programs the Secure Physical Timer in the ARM Generic Timer block
|
||||
to raise a periodic interrupt (every half a second) for the purpose of testing
|
||||
interrupt management across all the software components listed in 2.1
|
||||
|
||||
|
||||
### 2.3 Interrupt handling
|
||||
This section describes in detail the role of each software component (see
|
||||
Section 2.1) in handling an interrupt of a particular type.
|
||||
|
||||
|
||||
#### 2.3.1 EL3 runtime firmware
|
||||
The EL3 runtime firmware populates the IRQ and FIQ exception vectors referenced
|
||||
by the `runtime_exceptions` variable as follows.
|
||||
|
||||
1. IRQ and FIQ exceptions taken from the current exception level with
|
||||
`SP_EL0` or `SP_EL3` are reported as irrecoverable error conditions. As
|
||||
mentioned earlier, EL3 runtime firmware always executes with the
|
||||
`PSTATE.I` and `PSTATE.F` bits set.
|
||||
|
||||
2. The following text describes how the IRQ and FIQ exceptions taken from a
|
||||
lower exception level using AArch64 or AArch32 are handled.
|
||||
|
||||
When an interrupt is generated, the vector for each interrupt type is
|
||||
responsible for:
|
||||
|
||||
1. Saving the entire general purpose register context (x0-x30) immediately
|
||||
upon exception entry. The registers are saved in the per-cpu `cpu_context`
|
||||
data structure referenced by the `SP_EL3`register.
|
||||
|
||||
2. Saving the `ELR_EL3`, `SP_EL0` and `SPSR_EL3` system registers in the
|
||||
per-cpu `cpu_context` data structure referenced by the `SP_EL3` register.
|
||||
|
||||
3. Switching to the C runtime stack by restoring the `CTX_RUNTIME_SP` value
|
||||
from the per-cpu `cpu_context` data structure in `SP_EL0` and
|
||||
executing the `msr spsel, #0` instruction.
|
||||
|
||||
4. Determining the type of interrupt. Secure-EL1 interrupts will be signaled
|
||||
at the FIQ vector. Non-secure interrupts will be signaled at the IRQ
|
||||
vector. The platform should implement the following API to determine the
|
||||
type of the pending interrupt.
|
||||
|
||||
uint32_t plat_ic_get_interrupt_type(void);
|
||||
|
||||
It should return either `INTR_TYPE_S_EL1` or `INTR_TYPE_NS`.
|
||||
|
||||
5. Determining the handler for the type of interrupt that has been generated.
|
||||
The following API has been added for this purpose.
|
||||
|
||||
interrupt_type_handler get_interrupt_type_handler(uint32_t interrupt_type);
|
||||
|
||||
It returns the reference to the registered handler for this interrupt
|
||||
type. The `handler` is retrieved from the `intr_type_desc_t` structure as
|
||||
described in Section 2. `NULL` is returned if no handler has been
|
||||
registered for this type of interrupt. This scenario is reported as an
|
||||
irrecoverable error condition.
|
||||
|
||||
6. Calling the registered handler function for the interrupt type generated.
|
||||
The `id` parameter is set to `INTR_ID_UNAVAILABLE` currently. The id along
|
||||
with the current security state and a reference to the `cpu_context_t`
|
||||
structure for the current security state are passed to the handler function
|
||||
as its arguments.
|
||||
|
||||
The handler function returns a reference to the per-cpu `cpu_context_t`
|
||||
structure for the target security state.
|
||||
|
||||
7. Calling `el3_exit()` to return from EL3 into a lower exception level in
|
||||
the security state determined by the handler routine. The `el3_exit()`
|
||||
function is responsible for restoring the register context from the
|
||||
`cpu_context_t` data structure for the target security state.
|
||||
|
||||
|
||||
#### 2.3.2 Secure payload dispatcher
|
||||
|
||||
##### 2.3.2.1 Interrupt entry
|
||||
The SPD service begins handling an interrupt when the EL3 runtime firmware calls
|
||||
the handler function for that type of interrupt. The SPD service is responsible
|
||||
for the following:
|
||||
|
||||
1. Validating the interrupt. This involves ensuring that the interrupt was
|
||||
generating according to the interrupt routing model specified by the SPD
|
||||
service during registration. It should use the security state of the
|
||||
exception level (passed in the `flags` parameter of the handler) where
|
||||
the interrupt was taken from to determine this. If the interrupt is not
|
||||
recognised then the handler should treat it as an irrecoverable error
|
||||
condition.
|
||||
|
||||
A SPD service can register a handler for Secure-EL1 and/or Non-secure
|
||||
interrupts. A non-secure interrupt should never be routed to EL3 from
|
||||
from non-secure state. Also if a routing model is chosen where Secure-EL1
|
||||
interrupts are routed to S-EL1 when execution is in Secure state, then a
|
||||
S-EL1 interrupt should never be routed to EL3 from secure state. The handler
|
||||
could use the security state flag to check this.
|
||||
|
||||
2. Determining whether a context switch is required. This depends upon the
|
||||
routing model and interrupt type. For non secure and S-EL1 interrupt,
|
||||
if the security state of the execution context where the interrupt was
|
||||
generated is not the same as the security state required for handling
|
||||
the interrupt, a context switch is required. The following 2 cases
|
||||
require a context switch from secure to non-secure or vice-versa:
|
||||
|
||||
1. A Secure-EL1 interrupt taken from the non-secure state should be
|
||||
routed to the Secure Payload.
|
||||
|
||||
2. A non-secure interrupt taken from the secure state should be routed
|
||||
to the last known non-secure exception level.
|
||||
|
||||
The SPD service must save the system register context of the current
|
||||
security state. It must then restore the system register context of the
|
||||
target security state. It should use the `cm_set_next_eret_context()` API
|
||||
to ensure that the next `cpu_context` to be restored is of the target
|
||||
security state.
|
||||
|
||||
If the target state is secure then execution should be handed to the SP as
|
||||
per the synchronous interrupt handling model it implements. A Secure-EL1
|
||||
interrupt can be routed to EL3 while execution is in the SP. This implies
|
||||
that SP execution can be preempted while handling an interrupt by a
|
||||
another higher priority Secure-EL1 interrupt or a EL3 interrupt. The SPD
|
||||
service should be able to handle this preemption or manage secure interrupt
|
||||
priorities before handing control to the SP.
|
||||
|
||||
3. Setting the return value of the handler to the per-cpu `cpu_context` if
|
||||
the interrupt has been successfully validated and ready to be handled at a
|
||||
lower exception level.
|
||||
|
||||
The routing model allows non-secure interrupts to interrupt Secure-EL1 when in
|
||||
secure state if it has been configured to do so. The SPD service and the SP
|
||||
should implement a mechanism for routing these interrupts to the last known
|
||||
exception level in the non-secure state. The former should save the SP context,
|
||||
restore the non-secure context and arrange for entry into the non-secure state
|
||||
so that the interrupt can be handled.
|
||||
|
||||
|
||||
##### 2.3.2.2 Interrupt exit
|
||||
When the Secure Payload has finished handling a Secure-EL1 interrupt, it could
|
||||
return control back to the SPD service through a SMC32 or SMC64. The SPD service
|
||||
should handle this secure monitor call so that execution resumes in the
|
||||
exception level and the security state from where the Secure-EL1 interrupt was
|
||||
originally taken.
|
||||
|
||||
|
||||
##### 2.3.2.3 Test secure payload dispatcher Secure-EL1 interrupt handling
|
||||
The example TSPD service registers a handler for Secure-EL1 interrupts taken
|
||||
from the non-secure state. During execution in S-EL1, the TSPD expects that the
|
||||
Secure-EL1 interrupts are handled in S-EL1 by TSP. Its handler
|
||||
`tspd_secure_el1_interrupt_handler()` expects only to be invoked for Secure-EL1
|
||||
originating from the non-secure state. It takes the following actions upon being
|
||||
invoked.
|
||||
|
||||
1. It uses the security state provided in the `flags` parameter to ensure
|
||||
that the secure interrupt originated from the non-secure state. It asserts
|
||||
if this is not the case.
|
||||
|
||||
2. It saves the system register context for the non-secure state by calling
|
||||
`cm_el1_sysregs_context_save(NON_SECURE);`.
|
||||
|
||||
3. It sets the `ELR_EL3` system register to `tsp_sel1_intr_entry` and sets the
|
||||
`SPSR_EL3.DAIF` bits in the secure CPU context. It sets `x0` to
|
||||
`TSP_HANDLE_SEL1_INTR_AND_RETURN`. If the TSP was preempted earlier by a non
|
||||
secure interrupt during `yielding` SMC processing, save the registers that
|
||||
will be trashed, which is the `ELR_EL3` and `SPSR_EL3`, in order to be able
|
||||
to re-enter TSP for Secure-EL1 interrupt processing. It does not need to
|
||||
save any other secure context since the TSP is expected to preserve it
|
||||
(see Section 2.2.2.1).
|
||||
|
||||
4. It restores the system register context for the secure state by calling
|
||||
`cm_el1_sysregs_context_restore(SECURE);`.
|
||||
|
||||
5. It ensures that the secure CPU context is used to program the next
|
||||
exception return from EL3 by calling `cm_set_next_eret_context(SECURE);`.
|
||||
|
||||
6. It returns the per-cpu `cpu_context` to indicate that the interrupt can
|
||||
now be handled by the SP. `x1` is written with the value of `elr_el3`
|
||||
register for the non-secure state. This information is used by the SP for
|
||||
debugging purposes.
|
||||
|
||||
The figure below describes how the interrupt handling is implemented by the TSPD
|
||||
when a Secure-EL1 interrupt is generated when execution is in the non-secure
|
||||
state.
|
||||
|
||||

|
||||
|
||||
The TSP issues an SMC with `TSP_HANDLED_S_EL1_INTR` as the function identifier to
|
||||
signal completion of interrupt handling.
|
||||
|
||||
The TSPD service takes the following actions in `tspd_smc_handler()` function
|
||||
upon receiving an SMC with `TSP_HANDLED_S_EL1_INTR` as the function identifier:
|
||||
|
||||
1. It ensures that the call originated from the secure state otherwise
|
||||
execution returns to the non-secure state with `SMC_UNK` in `x0`.
|
||||
|
||||
2. It restores the saved `ELR_EL3` and `SPSR_EL3` system registers back to
|
||||
the secure CPU context (see step 3 above) in case the TSP had been preempted
|
||||
by a non secure interrupt earlier.
|
||||
|
||||
3. It restores the system register context for the non-secure state by
|
||||
calling `cm_el1_sysregs_context_restore(NON_SECURE)`.
|
||||
|
||||
4. It ensures that the non-secure CPU context is used to program the next
|
||||
exception return from EL3 by calling `cm_set_next_eret_context(NON_SECURE)`.
|
||||
|
||||
5. `tspd_smc_handler()` returns a reference to the non-secure `cpu_context`
|
||||
as the return value.
|
||||
|
||||
|
||||
##### 2.3.2.4 Test secure payload dispatcher non-secure interrupt handling
|
||||
The TSP in Secure-EL1 can be preempted by a non-secure interrupt during
|
||||
`yielding` SMC processing or by a higher priority EL3 interrupt during
|
||||
Secure-EL1 interrupt processing. Currently only non-secure interrupts can
|
||||
cause preemption of TSP since there are no EL3 interrupts in the
|
||||
system.
|
||||
|
||||
It should be noted that while TSP is preempted, the TSPD only allows entry into
|
||||
the TSP either for Secure-EL1 interrupt handling or for resuming the preempted
|
||||
`yielding` SMC in response to the `TSP_FID_RESUME` SMC from the normal world.
|
||||
(See Section 3).
|
||||
|
||||
The non-secure interrupt triggered in Secure-EL1 during `yielding` SMC processing
|
||||
can be routed to either EL3 or Secure-EL1 and is controlled by build option
|
||||
`TSP_NS_INTR_ASYNC_PREEMPT` (see Section 2.2.2.1). If the build option is set,
|
||||
the TSPD will set the routing model for the non-secure interrupt to be routed to
|
||||
EL3 from secure state i.e. __TEL3=1, CSS=0__ and registers
|
||||
`tspd_ns_interrupt_handler()` as the non-secure interrupt handler. The
|
||||
`tspd_ns_interrupt_handler()` on being invoked ensures that the interrupt
|
||||
originated from the secure state and disables routing of non-secure interrupts
|
||||
from secure state to EL3. This is to prevent further preemption (by a non-secure
|
||||
interrupt) when TSP is reentered for handling Secure-EL1 interrupts that
|
||||
triggered while execution was in the normal world. The
|
||||
`tspd_ns_interrupt_handler()` then invokes `tspd_handle_sp_preemption()` for
|
||||
further handling.
|
||||
|
||||
If the `TSP_NS_INTR_ASYNC_PREEMPT` build option is zero (default), the default
|
||||
routing model for non-secure interrupt in secure state is in effect
|
||||
i.e. __TEL3=0, CSS=0__. During `yielding` SMC processing, the IRQ
|
||||
exceptions are unmasked i.e. `PSTATE.I=0`, and a non-secure interrupt will
|
||||
trigger at Secure-EL1 IRQ exception vector. The TSP saves the general purpose
|
||||
register context and issues an SMC with `TSP_PREEMPTED` as the function
|
||||
identifier to signal preemption of TSP. The TSPD SMC handler,
|
||||
`tspd_smc_handler()`, ensures that the SMC call originated from the
|
||||
secure state otherwise execution returns to the non-secure state with
|
||||
`SMC_UNK` in `x0`. It then invokes `tspd_handle_sp_preemption()` for
|
||||
further handling.
|
||||
|
||||
The `tspd_handle_sp_preemption()` takes the following actions upon being
|
||||
invoked:
|
||||
|
||||
1. It saves the system register context for the secure state by calling
|
||||
`cm_el1_sysregs_context_save(SECURE)`.
|
||||
|
||||
2. It restores the system register context for the non-secure state by
|
||||
calling `cm_el1_sysregs_context_restore(NON_SECURE)`.
|
||||
|
||||
3. It ensures that the non-secure CPU context is used to program the next
|
||||
exception return from EL3 by calling `cm_set_next_eret_context(NON_SECURE)`.
|
||||
|
||||
4. `SMC_PREEMPTED` is set in x0 and return to non secure state after
|
||||
restoring non secure context.
|
||||
|
||||
The Normal World is expected to resume the TSP after the `yielding` SMC preemption
|
||||
by issuing an SMC with `TSP_FID_RESUME` as the function identifier (see section 3).
|
||||
The TSPD service takes the following actions in `tspd_smc_handler()` function
|
||||
upon receiving this SMC:
|
||||
|
||||
1. It ensures that the call originated from the non secure state. An
|
||||
assertion is raised otherwise.
|
||||
|
||||
2. Checks whether the TSP needs a resume i.e check if it was preempted. It
|
||||
then saves the system register context for the non-secure state by calling
|
||||
`cm_el1_sysregs_context_save(NON_SECURE)`.
|
||||
|
||||
3. Restores the secure context by calling
|
||||
`cm_el1_sysregs_context_restore(SECURE)`
|
||||
|
||||
4. It ensures that the secure CPU context is used to program the next
|
||||
exception return from EL3 by calling `cm_set_next_eret_context(SECURE)`.
|
||||
|
||||
5. `tspd_smc_handler()` returns a reference to the secure `cpu_context` as the
|
||||
return value.
|
||||
|
||||
The figure below describes how the TSP/TSPD handle a non-secure interrupt when
|
||||
it is generated during execution in the TSP with `PSTATE.I` = 0 when the
|
||||
`TSP_NS_INTR_ASYNC_PREEMPT` build flag is 0.
|
||||
|
||||

|
||||
|
||||
|
||||
#### 2.3.3 Secure payload
|
||||
The SP should implement one or both of the synchronous and asynchronous
|
||||
interrupt handling models depending upon the interrupt routing model it has
|
||||
chosen (as described in 2.2.3).
|
||||
|
||||
In the synchronous model, it should begin handling a Secure-EL1 interrupt after
|
||||
receiving control from the SPD service at an entrypoint agreed upon during build
|
||||
time or during the registration phase. Before handling the interrupt, the SP
|
||||
should save any Secure-EL1 system register context which is needed for resuming
|
||||
normal execution in the SP later e.g. `SPSR_EL1, `ELR_EL1`. After handling the
|
||||
interrupt, the SP could return control back to the exception level and security
|
||||
state where the interrupt was originally taken from. The SP should use an SMC32
|
||||
or SMC64 to ask the SPD service to do this.
|
||||
|
||||
In the asynchronous model, the Secure Payload is responsible for handling
|
||||
non-secure and Secure-EL1 interrupts at the IRQ and FIQ vectors in its exception
|
||||
vector table when `PSTATE.I` and `PSTATE.F` bits are 0. As described earlier,
|
||||
when a non-secure interrupt is generated, the SP should coordinate with the SPD
|
||||
service to pass control back to the non-secure state in the last known exception
|
||||
level. This will allow the non-secure interrupt to be handled in the non-secure
|
||||
state.
|
||||
|
||||
|
||||
##### 2.3.3.1 Test secure payload behavior
|
||||
The TSPD hands control of a Secure-EL1 interrupt to the TSP at the
|
||||
`tsp_sel1_intr_entry()`. The TSP handles the interrupt while ensuring that the
|
||||
handover agreement described in Section 2.2.2.1 is maintained. It updates some
|
||||
statistics by calling `tsp_update_sync_sel1_intr_stats()`. It then calls
|
||||
`tsp_common_int_handler()` which.
|
||||
|
||||
1. Checks whether the interrupt is the secure physical timer interrupt. It
|
||||
uses the platform API `plat_ic_get_pending_interrupt_id()` to get the
|
||||
interrupt number. If it is not the secure physical timer interrupt, then
|
||||
that means that a higher priority interrupt has preempted it. Invoke
|
||||
`tsp_handle_preemption()` to handover control back to EL3 by issuing
|
||||
an SMC with `TSP_PREEMPTED` as the function identifier.
|
||||
|
||||
2. Handles the secure timer interrupt interrupt by acknowledging it using the
|
||||
`plat_ic_acknowledge_interrupt()` platform API, calling
|
||||
`tsp_generic_timer_handler()` to reprogram the secure physical generic
|
||||
timer and calling the `plat_ic_end_of_interrupt()` platform API to signal
|
||||
end of interrupt processing.
|
||||
|
||||
The TSP passes control back to the TSPD by issuing an SMC64 with
|
||||
`TSP_HANDLED_S_EL1_INTR` as the function identifier.
|
||||
|
||||
The TSP handles interrupts under the asynchronous model as follows.
|
||||
|
||||
1. Secure-EL1 interrupts are handled by calling the `tsp_common_int_handler()`
|
||||
function. The function has been described above.
|
||||
|
||||
2. Non-secure interrupts are handled by by calling the `tsp_common_int_handler()`
|
||||
function which ends up invoking `tsp_handle_preemption()` and issuing an
|
||||
SMC64 with `TSP_PREEMPTED` as the function identifier. Execution resumes at
|
||||
the instruction that follows this SMC instruction when the TSPD hands
|
||||
control to the TSP in response to an SMC with `TSP_FID_RESUME` as the
|
||||
function identifier from the non-secure state (see section 2.3.2.4).
|
||||
|
||||
|
||||
3. Other considerations
|
||||
-----------------------
|
||||
|
||||
### 3.1 Implication of preempted SMC on Non-Secure Software
|
||||
A `yielding` SMC call to Secure payload can be preempted by a non-secure
|
||||
interrupt and the execution can return to the non-secure world for handling
|
||||
the interrupt (For details on `yielding` SMC refer [SMC calling convention]).
|
||||
In this case, the SMC call has not completed its execution and the execution
|
||||
must return back to the secure payload to resume the preempted SMC call.
|
||||
This can be achieved by issuing an SMC call which instructs to resume the
|
||||
preempted SMC.
|
||||
|
||||
A `fast` SMC cannot be preempted and hence this case will not happen for
|
||||
a fast SMC call.
|
||||
|
||||
In the Test Secure Payload implementation, `TSP_FID_RESUME` is designated
|
||||
as the resume SMC FID. It is important to note that `TSP_FID_RESUME` is a
|
||||
`yielding` SMC which means it too can be be preempted. The typical non
|
||||
secure software sequence for issuing a `yielding` SMC would look like this,
|
||||
assuming `P.STATE.I=0` in the non secure state :
|
||||
|
||||
int rc;
|
||||
rc = smc(TSP_YIELD_SMC_FID, ...); /* Issue a Yielding SMC call */
|
||||
/* The pending non-secure interrupt is handled by the interrupt handler
|
||||
and returns back here. */
|
||||
while (rc == SMC_PREEMPTED) { /* Check if the SMC call is preempted */
|
||||
rc = smc(TSP_FID_RESUME); /* Issue resume SMC call */
|
||||
}
|
||||
|
||||
The `TSP_YIELD_SMC_FID` is any `yielding` SMC function identifier and the smc()
|
||||
function invokes a SMC call with the required arguments. The pending non-secure
|
||||
interrupt causes an IRQ exception and the IRQ handler registered at the
|
||||
exception vector handles the non-secure interrupt and returns. The return value
|
||||
from the SMC call is tested for `SMC_PREEMPTED` to check whether it is
|
||||
preempted. If it is, then the resume SMC call `TSP_FID_RESUME` is issued. The
|
||||
return value of the SMC call is tested again to check if it is preempted.
|
||||
This is done in a loop till the SMC call succeeds or fails. If a `yielding`
|
||||
SMC is preempted, until it is resumed using `TSP_FID_RESUME` SMC and
|
||||
completed, the current TSPD prevents any other SMC call from re-entering
|
||||
TSP by returning `SMC_UNK` error.
|
||||
|
||||
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
_Copyright (c) 2014-2015, ARM Limited and Contributors. All rights reserved._
|
||||
|
||||
[Porting Guide]: ./porting-guide.md
|
||||
[SMC calling convention]: http://infocenter.arm.com/help/topic/com.arm.doc.den0028a/index.html "SMC Calling Convention PDD (ARM DEN 0028A)"
|
|
@ -1,147 +0,0 @@
|
|||
|
||||
Description
|
||||
====================
|
||||
HiKey is one of 96boards. Hisilicon Kirin6220 processor is installed on HiKey.
|
||||
|
||||
More information are listed in [link](https://github.com/96boards/documentation/blob/master/ConsumerEdition/HiKey/Quickstart/README.md).
|
||||
|
||||
|
||||
How to build
|
||||
====================
|
||||
|
||||
1. Code Locations
|
||||
-----------------
|
||||
|
||||
* ARM Trusted Firmware:
|
||||
[link](https://github.com/ARM-software/arm-trusted-firmware)
|
||||
|
||||
* edk2:
|
||||
[link](https://github.com/96boards-hikey/edk2/tree/testing/hikey960_v2.5)
|
||||
|
||||
* OpenPlatformPkg:
|
||||
[link](https://github.com/96boards-hikey/OpenPlatformPkg/tree/testing/hikey960_v1.3.4)
|
||||
|
||||
* l-loader:
|
||||
[link](https://github.com/96boards-hikey/l-loader/tree/testing/hikey960_v1.2)
|
||||
|
||||
* uefi-tools:
|
||||
[link](https://github.com/96boards-hikey/uefi-tools/tree/testing/hikey960_v1)
|
||||
|
||||
* atf-fastboot:
|
||||
[link](https://github.com/96boards-hikey/atf-fastboot/tree/master)
|
||||
|
||||
|
||||
2. Build Procedure
|
||||
------------------
|
||||
|
||||
* Fetch all the above repositories into local host.
|
||||
Make all the repositories in the same ${BUILD_PATH}.
|
||||
|
||||
* Create the symbol link to OpenPlatformPkg in edk2.
|
||||
```shell
|
||||
$cd ${BUILD_PATH}/edk2
|
||||
$ln -sf ../OpenPlatformPkg
|
||||
```
|
||||
|
||||
* Prepare AARCH64 && AARCH32 toolchain. Prepare python.
|
||||
|
||||
* If your hikey hardware is built by CircuitCo, update _uefi-tools/platform.config_ first. _(optional)_
|
||||
__Uncomment the below sentence. Otherwise, UEFI can't output messages on serial
|
||||
console on hikey.__
|
||||
```shell
|
||||
BUILDFLAGS=-DSERIAL_BASE=0xF8015000
|
||||
```
|
||||
If your hikey hardware is built by LeMarker, nothing to do.
|
||||
|
||||
* Build it as debug mode. Create your own build script file or you could refer to __build_uefi.sh__ in l-loader git repository.
|
||||
```shell
|
||||
BUILD_OPTION=DEBUG
|
||||
export AARCH64_TOOLCHAIN=GCC5
|
||||
export UEFI_TOOLS_DIR=${BUILD_PATH}/uefi-tools
|
||||
export EDK2_DIR=${BUILD_PATH}/edk2
|
||||
EDK2_OUTPUT_DIR=${EDK2_DIR}/Build/HiKey/${BUILD_OPTION}_${AARCH64_TOOLCHAIN}
|
||||
# Build fastboot for ARM Trust Firmware. It's used for recovery mode.
|
||||
cd ${BUILD_PATH}/atf-fastboot
|
||||
CROSS_COMPILE=aarch64-linux-gnu- make PLAT=hikey DEBUG=1
|
||||
# Convert DEBUG/RELEASE to debug/release
|
||||
FASTBOOT_BUILD_OPTION=$(echo ${BUILD_OPTION} | tr '[A-Z]' '[a-z]')
|
||||
cd ${EDK2_DIR}
|
||||
# Build UEFI & ARM Trust Firmware
|
||||
${UEFI_TOOLS_DIR}/uefi-build.sh -b ${BUILD_OPTION} -a ../arm-trusted-firmware hikey
|
||||
# Generate l-loader.bin
|
||||
cd ${BUILD_PATH}/l-loader
|
||||
ln -sf ${EDK2_OUTPUT_DIR}/FV/bl1.bin
|
||||
ln -sf ${EDK2_OUTPUT_DIR}/FV/fip.bin
|
||||
ln -sf ${BUILD_PATH}/atf-fastboot/build/hikey/${FASTBOOT_BUILD_OPTION}/bl1.bin fastboot.bin
|
||||
python gen_loader.py -o l-loader.bin --img_bl1=bl1.bin --img_ns_bl1u=BL33_AP_UEFI.fd
|
||||
arm-linux-gnueabihf-gcc -c -o start.o start.S
|
||||
arm-linux-gnueabihf-ld -Bstatic -Tl-loader.lds -Ttext 0xf9800800 start.o -o loader
|
||||
arm-linux-gnueabihf-objcopy -O binary loader temp
|
||||
python gen_loader_hikey.py -o l-loader.bin --img_loader=temp --img_bl1=bl1.bin --img_ns_bl1u=fastboot.bin
|
||||
```
|
||||
|
||||
* Generate partition table for aosp. The eMMC capacity is either 4GB or 8GB. Just change "aosp-4g" to "linux-4g" for debian.
|
||||
```shell
|
||||
$PTABLE=aosp-4g SECTOR_SIZE=512 bash -x generate_ptable.sh
|
||||
```
|
||||
|
||||
|
||||
3. Setup Console
|
||||
----------------
|
||||
|
||||
* Install ser2net. Use telnet as the console since UEFI fails to display Boot Manager GUI in minicom. __If you don't need Boot Manager GUI, just ignore this section.__
|
||||
```shell
|
||||
$sudo apt-get install ser2net
|
||||
```
|
||||
|
||||
* Configure ser2net.
|
||||
```shell
|
||||
$sudo vi /etc/ser2net.conf
|
||||
```
|
||||
|
||||
Append one line for serial-over-USB in below.
|
||||
_#ser2net.conf_
|
||||
```shell
|
||||
2004:telnet:0:/dev/ttyUSB0:115200 8DATABITS NONE 1STOPBIT banner
|
||||
```
|
||||
|
||||
* Open the console.
|
||||
```shell
|
||||
$telnet localhost 2004
|
||||
```
|
||||
|
||||
And you could open the console remotely, too.
|
||||
|
||||
|
||||
4. Flush images in recovery mode
|
||||
-----------------------------
|
||||
|
||||
* Make sure Pin3-Pin4 on J15 are connected for recovery mode. Then power on HiKey.
|
||||
|
||||
* Remove the modemmanager package. This package may cause the idt tool failure.
|
||||
```shell
|
||||
$sudo apt-get purge modemmanager
|
||||
```
|
||||
|
||||
* Run the command to download l-loader.bin into HiKey.
|
||||
```shell
|
||||
$sudo python hisi-idt.py -d /dev/ttyUSB1 --img1 l-loader.bin
|
||||
```
|
||||
|
||||
* Update images. All aosp or debian images could be fetched from [link](https://builds.96boards.org/).
|
||||
```shell
|
||||
$sudo fastboot flash ptable prm_ptable.img
|
||||
$sudo fastboot flash fastboot fip.bin
|
||||
$sudo fastboot flash boot boot.img
|
||||
$sudo fastboot flash cache cache.img
|
||||
$sudo fastboot flash system system.img
|
||||
$sudo fastboot flash userdata userdata.img
|
||||
```
|
||||
|
||||
|
||||
5. Boot UEFI in normal mode
|
||||
-----------------------------
|
||||
|
||||
* Make sure Pin3-Pin4 on J15 are open for normal boot mode. Then power on HiKey.
|
||||
|
||||
* Reference [link](https://github.com/96boards-hikey/tools-images-hikey960/blob/master/build-from-source/README-ATF-UEFI-build-from-source.md)
|
|
@ -1,159 +0,0 @@
|
|||
|
||||
Description
|
||||
====================
|
||||
HiKey960 is one of 96boards. Hisilicon Hi3660 processor is installed on HiKey960.
|
||||
|
||||
More information are listed in [link](http://www.96boards.org/documentation/ConsumerEdition/HiKey960/README.md).
|
||||
|
||||
|
||||
How to build
|
||||
====================
|
||||
|
||||
1. Code Locations
|
||||
-----------------
|
||||
|
||||
* ARM Trusted Firmware:
|
||||
[link](https://github.com/ARM-software/arm-trusted-firmware)
|
||||
|
||||
* edk2:
|
||||
[link](https://github.com/96boards-hikey/edk2/tree/testing/hikey960_v2.5)
|
||||
|
||||
* OpenPlatformPkg:
|
||||
[link](https://github.com/96boards-hikey/OpenPlatformPkg/tree/testing/hikey960_v1.3.4)
|
||||
|
||||
* l-loader:
|
||||
[link](https://github.com/96boards-hikey/l-loader/tree/testing/hikey960_v1.2)
|
||||
|
||||
* uefi-tools:
|
||||
[link](https://github.com/96boards-hikey/uefi-tools/tree/hikey960_v1)
|
||||
|
||||
|
||||
2. Build Procedure
|
||||
------------------
|
||||
|
||||
* Fetch all the above 5 repositories into local host.
|
||||
Make all the repositories in the same ${BUILD_PATH}.
|
||||
|
||||
* Create the symbol link to OpenPlatformPkg in edk2.
|
||||
```shell
|
||||
$cd ${BUILD_PATH}/edk2
|
||||
$ln -sf ../OpenPlatformPkg
|
||||
```
|
||||
|
||||
* Prepare AARCH64 toolchain.
|
||||
|
||||
* If your hikey960 hardware is v1, update _uefi-tools/platform.config_ first. _(optional)_
|
||||
__Uncomment the below sentence. Otherwise, UEFI can't output messages on serial
|
||||
console on hikey960 v1.__
|
||||
```shell
|
||||
BUILDFLAGS=-DSERIAL_BASE=0xFDF05000
|
||||
```
|
||||
If your hikey960 hardware is v2 or newer, nothing to do.
|
||||
|
||||
* Build it as debug mode. Create script file for build.
|
||||
```shell
|
||||
BUILD_OPTION=DEBUG
|
||||
export AARCH64_TOOLCHAIN=GCC48
|
||||
export UEFI_TOOLS_DIR=${BUILD_PATH}/uefi-tools
|
||||
export EDK2_DIR=${BUILD_PATH}/edk2
|
||||
EDK2_OUTPUT_DIR=${EDK2_DIR}/Build/HiKey960/${BUILD_OPTION}_${AARCH64_TOOLCHAIN}
|
||||
cd ${EDK2_DIR}
|
||||
# Build UEFI & ARM Trust Firmware
|
||||
${UEFI_TOOLS_DIR}/uefi-build.sh -b ${BUILD_OPTION} -a ../arm-trusted-firmware hikey960
|
||||
# Generate l-loader.bin
|
||||
cd ${BUILD_PATH}/l-loader
|
||||
ln -sf ${EDK2_OUTPUT_DIR}/FV/bl1.bin
|
||||
ln -sf ${EDK2_OUTPUT_DIR}/FV/fip.bin
|
||||
ln -sf ${EDK2_OUTPUT_DIR}/FV/BL33_AP_UEFI.fd
|
||||
python gen_loader.py -o l-loader.bin --img_bl1=bl1.bin --img_ns_bl1u=BL33_AP_UEFI.fd
|
||||
```
|
||||
|
||||
* Generate partition table.
|
||||
_Make sure that you're using the sgdisk in the l-loader directory._
|
||||
```shell
|
||||
$PTABLE=aosp-32g SECTOR_SIZE=4096 SGDISK=./sgdisk bash -x generate_ptable.sh
|
||||
```
|
||||
|
||||
|
||||
3. Setup Console
|
||||
----------------
|
||||
|
||||
* Install ser2net. Use telnet as the console since UEFI will output window
|
||||
that fails to display in minicom.
|
||||
```shell
|
||||
$sudo apt-get install ser2net
|
||||
```
|
||||
|
||||
* Configure ser2net.
|
||||
```shell
|
||||
$sudo vi /etc/ser2net.conf
|
||||
```
|
||||
Append one line for serial-over-USB in _#ser2net.conf_
|
||||
```
|
||||
2004:telnet:0:/dev/ttyUSB0:115200 8DATABITS NONE 1STOPBIT banner
|
||||
```
|
||||
|
||||
* Open the console.
|
||||
```shell
|
||||
$telnet localhost 2004
|
||||
```
|
||||
And you could open the console remotely, too.
|
||||
|
||||
|
||||
4. Boot UEFI in recovery mode
|
||||
-----------------------------
|
||||
|
||||
* Fetch that are used in recovery mode. The code location is in below.
|
||||
[link](https://github.com/96boards-hikey/tools-images-hikey960)
|
||||
|
||||
* Generate l-loader.bin.
|
||||
```shell
|
||||
$cd tools-images-hikey960
|
||||
$ln -sf ${BUILD_PATH}/l-loader/l-loader.bin
|
||||
```
|
||||
|
||||
* Prepare config file.
|
||||
```shell
|
||||
$vi config
|
||||
# The content of config file
|
||||
./sec_user_xloader.img 0x00020000
|
||||
./sec_uce_boot.img 0x6A908000
|
||||
./l-loader.bin 0x1AC00000
|
||||
```
|
||||
|
||||
* Remove the modemmanager package. This package may causes hikey_idt tool failure.
|
||||
```shell
|
||||
$sudo apt-get purge modemmanager
|
||||
```
|
||||
|
||||
* Run the command to download l-loader.bin into HiKey960.
|
||||
```shell
|
||||
$sudo ./hikey_idt -c config -p /dev/ttyUSB1
|
||||
```
|
||||
|
||||
* UEFI running in recovery mode.
|
||||
When prompt '.' is displayed on console, press hotkey 'f' in keyboard. Then Android fastboot app is running.
|
||||
The timeout of prompt '.' is 10 seconds.
|
||||
|
||||
* Update images.
|
||||
```shell
|
||||
$sudo fastboot flash ptable prm_ptable.img
|
||||
$sudo fastboot flash xloader sec_xloader.img
|
||||
$sudo fastboot flash fastboot l-loader.bin
|
||||
$sudo fastboot flash fip fip.bin
|
||||
$sudo fastboot flash boot boot.img
|
||||
$sudo fastboot flash cache cache.img
|
||||
$sudo fastboot flash system system.img
|
||||
$sudo fastboot flash userdata userdata.img
|
||||
```
|
||||
|
||||
* Notice: UEFI could also boot kernel in recovery mode, but BL31 isn't loaded in
|
||||
recovery mode.
|
||||
|
||||
|
||||
5. Boot UEFI in normal mode
|
||||
-----------------------------
|
||||
|
||||
* Make sure "Boot Mode" switch is OFF for normal boot mode. Then power on HiKey960.
|
||||
|
||||
* Reference [link](https://github.com/96boards-hikey/tools-images-hikey960/blob/master/build-from-source/README-ATF-UEFI-build-from-source.md)
|
|
@ -1,95 +0,0 @@
|
|||
Tegra SoCs - Overview
|
||||
======================
|
||||
|
||||
* T210
|
||||
-------
|
||||
|
||||
T210 has Quad ARM® Cortex®-A57 cores in a switched configuration with a
|
||||
companion set of quad ARM Cortex-A53 cores. The Cortex-A57 and A53 cores
|
||||
support ARMv8, executing both 64-bit Aarch64 code, and 32-bit Aarch32 code
|
||||
including legacy ARMv7 applications. The Cortex-A57 processors each have
|
||||
48 KB Instruction and 32 KB Data Level 1 caches; and have a 2 MB shared
|
||||
Level 2 unified cache. The Cortex-A53 processors each have 32 KB Instruction
|
||||
and 32 KB Data Level 1 caches; and have a 512 KB shared Level 2 unified cache.
|
||||
|
||||
* T132
|
||||
-------
|
||||
|
||||
Denver is NVIDIA's own custom-designed, 64-bit, dual-core CPU which is
|
||||
fully ARMv8 architecture compatible. Each of the two Denver cores
|
||||
implements a 7-way superscalar microarchitecture (up to 7 concurrent
|
||||
micro-ops can be executed per clock), and includes a 128KB 4-way L1
|
||||
instruction cache, a 64KB 4-way L1 data cache, and a 2MB 16-way L2
|
||||
cache, which services both cores.
|
||||
|
||||
Denver implements an innovative process called Dynamic Code Optimization,
|
||||
which optimizes frequently used software routines at runtime into dense,
|
||||
highly tuned microcode-equivalent routines. These are stored in a
|
||||
dedicated, 128MB main-memory-based optimization cache. After being read
|
||||
into the instruction cache, the optimized micro-ops are executed,
|
||||
re-fetched and executed from the instruction cache as long as needed and
|
||||
capacity allows.
|
||||
|
||||
Effectively, this reduces the need to re-optimize the software routines.
|
||||
Instead of using hardware to extract the instruction-level parallelism
|
||||
(ILP) inherent in the code, Denver extracts the ILP once via software
|
||||
techniques, and then executes those routines repeatedly, thus amortizing
|
||||
the cost of ILP extraction over the many execution instances.
|
||||
|
||||
Denver also features new low latency power-state transitions, in addition
|
||||
to extensive power-gating and dynamic voltage and clock scaling based on
|
||||
workloads.
|
||||
|
||||
Directory structure
|
||||
====================
|
||||
|
||||
* plat/nvidia/tegra/common - Common code for all Tegra SoCs
|
||||
* plat/nvidia/tegra/soc/txxx - Chip specific code
|
||||
|
||||
Trusted OS dispatcher
|
||||
=====================
|
||||
Tegra supports multiple Trusted OS', Trusted Little Kernel (TLK) being one of
|
||||
them. In order to include the 'tlkd' dispatcher in the image, pass 'SPD=tlkd'
|
||||
on the command line while preparing a bl31 image. This allows other Trusted OS
|
||||
vendors to use the upstream code and include their dispatchers in the image
|
||||
without changing any makefiles.
|
||||
|
||||
Preparing the BL31 image to run on Tegra SoCs
|
||||
===================================================
|
||||
```shell
|
||||
CROSS_COMPILE=<path-to-aarch64-gcc>/bin/aarch64-none-elf- make PLAT=tegra \
|
||||
TARGET_SOC=<target-soc e.g. t210|t132> SPD=<dispatcher e.g. tlkd> bl31
|
||||
```
|
||||
|
||||
Platforms wanting to use different TZDRAM_BASE, can add `TZDRAM_BASE=<value>`
|
||||
to the build command line.
|
||||
|
||||
The Tegra platform code expects a pointer to the following platform specific
|
||||
structure via 'x1' register from the BL2 layer which is used by the
|
||||
bl31_early_platform_setup() handler to extract the TZDRAM carveout base and
|
||||
size for loading the Trusted OS and the UART port ID to be used. The Tegra
|
||||
memory controller driver programs this base/size in order to restrict NS
|
||||
accesses.
|
||||
|
||||
typedef struct plat_params_from_bl2 {
|
||||
/* TZ memory size */
|
||||
uint64_t tzdram_size;
|
||||
/* TZ memory base */
|
||||
uint64_t tzdram_base;
|
||||
/* UART port ID */
|
||||
int uart_id;
|
||||
} plat_params_from_bl2_t;
|
||||
|
||||
Power Management
|
||||
================
|
||||
The PSCI implementation expects each platform to expose the 'power state'
|
||||
parameter to be used during the 'SYSTEM SUSPEND' call. The state-id field
|
||||
is implementation defined on Tegra SoCs and is preferably defined by
|
||||
tegra_def.h.
|
||||
|
||||
Tegra configs
|
||||
=============
|
||||
|
||||
* 'tegra_enable_l2_ecc_parity_prot': This flag enables the L2 ECC and Parity
|
||||
Protection bit, for ARM Cortex-A57 CPUs, during CPU boot. This flag will
|
||||
be enabled by Tegrs SoCs during 'Cluster power up' or 'System Suspend' exit.
|
|
@ -1,44 +0,0 @@
|
|||
ARM Trusted Firmware for QEMU virt ARMv8-A
|
||||
==========================================
|
||||
|
||||
ARM Trusted Firmware implements the EL3 firmware layer for QEMU virt
|
||||
ARMv8-A. BL1 is used as the BootROM, supplied with the -bios argument.
|
||||
When QEMU starts all CPUs are released simultaneously, BL1 selects a
|
||||
primary CPU to handle the boot and the secondaries are placed in a polling
|
||||
loop to be released by normal world via PSCI.
|
||||
|
||||
BL2 edits the Flattened Device Tree, FDT, generated by QEMU at run-time to
|
||||
add a node describing PSCI and also enable methods for the CPUs.
|
||||
|
||||
An ARM64 defonfig v4.5 Linux kernel is known to boot, FTD doesn't need to be
|
||||
provided as it's generated by QEMU.
|
||||
|
||||
Current limitations:
|
||||
* Only cold boot is supported
|
||||
* No build instructions for QEMU_EFI.fd and rootfs-arm64.cpio.gz
|
||||
* No instructions for how to load a BL32 (Secure Payload)
|
||||
|
||||
`QEMU_EFI.fd` can be dowloaded from
|
||||
http://snapshots.linaro.org/components/kernel/leg-virt-tianocore-edk2-upstream/latest/QEMU-KERNEL-AARCH64/RELEASE_GCC49/QEMU_EFI.fd
|
||||
|
||||
Boot binaries, except BL1, are primarily loaded via semi-hosting so all
|
||||
binaries has to reside in the same directory as QEMU is started from. This
|
||||
is conveniently achieved with symlinks the local names as:
|
||||
* `bl2.bin` -> BL2
|
||||
* `bl31.bin` -> BL31
|
||||
* `bl33.bin` -> BL33 (`QEMU_EFI.fd`)
|
||||
* `Image` -> linux/Image
|
||||
|
||||
To build:
|
||||
```
|
||||
make CROSS_COMPILE=aarch64-none-elf- PLAT=qemu
|
||||
```
|
||||
|
||||
To start (QEMU v2.6.0):
|
||||
```
|
||||
qemu-system-aarch64 -nographic -machine virt,secure=on -cpu cortex-a57 \
|
||||
-kernel Image \
|
||||
-append console=ttyAMA0,38400 keep_bootcon root=/dev/vda2 \
|
||||
-initrd rootfs-arm64.cpio.gz -smp 2 -m 1024 -bios bl1.bin \
|
||||
-d unimp -semihosting-config enable,target=native
|
||||
```
|
|
@ -1,130 +0,0 @@
|
|||
ARM Trusted Firmware for Socionext UniPhier SoCs
|
||||
================================================
|
||||
|
||||
Socionext UniPhier ARMv8-A SoCs use ARM Trusted Firmware as the secure world
|
||||
firmware, supporting BL1, BL2, and BL31.
|
||||
|
||||
UniPhier SoC family implements its internal boot ROM, so BL1 is used as pseudo
|
||||
ROM (i.e. runs in RAM). The internal boot ROM loads 64KB [1] image from a
|
||||
non-volatile storage to the on-chip SRAM. Unfortunately, BL1 does not fit in
|
||||
the 64KB limit if [Trusted Board Boot] (TBB) is enabled. To solve this problem,
|
||||
Socionext provides a first stage loader called [UniPhier BL]. This loader runs
|
||||
in the on-chip SRAM, initializes the DRAM, expands BL1 there, and hands the
|
||||
control over to it. Therefore, all images of ARM Trusted Firmware run in DRAM.
|
||||
|
||||
The UniPhier platform works with/without TBB. See below for the build process
|
||||
of each case. The image authentication for the UniPhier platform fully
|
||||
complies with the Trusted Board Boot Requirements (TBBR) specification.
|
||||
|
||||
The UniPhier BL does not implement the authentication functionality, that is,
|
||||
it can not verify the BL1 image by itself. Instead, the UniPhier BL assures
|
||||
the BL1 validity in a different way; BL1 is GZIP-compressed and appended to
|
||||
the UniPhier BL. The concatenation of the UniPhier BL and the compressed BL1
|
||||
fits in the 64KB limit. The concatenated image is loaded by the boot ROM
|
||||
(and verified if the chip fuses are blown).
|
||||
|
||||
[1]: Some SoCs can load 80KB, but the software implementation must be aligned
|
||||
to the lowest common denominator.
|
||||
|
||||
[Trusted Board Boot]: ../trusted-board-boot.md
|
||||
|
||||
[UniPhier BL]: https://github.com/uniphier/uniphier-bl
|
||||
|
||||
|
||||
Boot Flow
|
||||
---------
|
||||
|
||||
1. The Boot ROM
|
||||
|
||||
This is hard-wired ROM, so never corrupted. It loads the UniPhier BL (with
|
||||
compressed-BL1 appended) into the on-chip SRAM. If the SoC fuses are blown,
|
||||
the image is verified by the SoC's own method.
|
||||
|
||||
2. UniPhier BL
|
||||
|
||||
This runs in the on-chip SRAM. After the minimum SoC initialization and DRAM
|
||||
setup, it decompresses the appended BL1 image into the DRAM, then jumps to
|
||||
the BL1 entry.
|
||||
|
||||
3. BL1
|
||||
|
||||
This runs in the DRAM. It extracts BL2 from FIP (Firmware Image Package).
|
||||
If TBB is enabled, the BL2 is authenticated by the standard mechanism of ARM
|
||||
Trusted Firmware.
|
||||
|
||||
4. BL2, BL31, and more
|
||||
|
||||
They all run in the DRAM, and are authenticated by the standard mechanism if
|
||||
TBB is enabled. See [Firmware Design] for details.
|
||||
|
||||
[Firmware Design]: ../firmware-design.md
|
||||
|
||||
|
||||
Basic Build
|
||||
-----------
|
||||
|
||||
BL1 must be compressed for the reason above. The UniPhier's platform makefile
|
||||
provides a build target `bl1_gzip` for this.
|
||||
|
||||
For a non-secure boot loader (aka BL33), U-Boot is well supported for UniPhier
|
||||
SoCs. The U-Boot image (`u-boot.bin`) must be built in advance. For the build
|
||||
procedure of U-Boot, refer to the document in the [U-Boot] project.
|
||||
|
||||
[U-Boot]: https://www.denx.de/wiki/U-Boot
|
||||
|
||||
To build minimum functionality for UniPhier (without TBB):
|
||||
|
||||
```
|
||||
make CROSS_COMPILE=<gcc-prefix> PLAT=uniphier BL33=<path-to-BL33> bl1_gzip fip
|
||||
```
|
||||
|
||||
Output images:
|
||||
|
||||
- `bl1.bin.gzip`
|
||||
- `fip.bin`
|
||||
|
||||
|
||||
Optional features
|
||||
-----------------
|
||||
|
||||
- Trusted Board Boot
|
||||
|
||||
[mbed TLS] is needed as the cryptographic and image parser modules.
|
||||
Refer to the [User Guide] for the appropriate version of mbed TLS.
|
||||
|
||||
To enable TBB, add the following options to the build command:
|
||||
|
||||
```
|
||||
TRUSTED_BOARD_BOOT=1 GENERATE_COT=1 MBEDTLS_DIR=<path-to-mbedtls>
|
||||
```
|
||||
|
||||
[mbed TLS]: https://tls.mbed.org/
|
||||
|
||||
[User Guide]: ../user-guide.md
|
||||
|
||||
- System Control Processor (SCP)
|
||||
|
||||
If desired, FIP can include an SCP BL2 image. If BL2 finds an SCP BL2 image
|
||||
in FIP, BL2 loads it into DRAM and kicks the SCP. Most of UniPhier boards
|
||||
still work without SCP, but SCP provides better power management support.
|
||||
|
||||
To include SCP_BL2, add the following option to the build command:
|
||||
|
||||
```
|
||||
SCP_BL2=<path-to-SCP>
|
||||
```
|
||||
|
||||
- BL32 (Secure Payload)
|
||||
|
||||
To enable BL32, add the following option to the build command:
|
||||
|
||||
```
|
||||
SPD=<spd> BL32=<path-to-BL32>
|
||||
```
|
||||
|
||||
If you use TSP for BL32, `BL32=<path-to-BL32>` is not required. Just add the
|
||||
following:
|
||||
|
||||
```
|
||||
SPD=tspd
|
||||
```
|
|
@ -1,56 +0,0 @@
|
|||
ARM Trusted Firmware for Xilinx Zynq UltraScale+ MPSoC
|
||||
================================
|
||||
|
||||
ARM Trusted Firmware implements the EL3 firmware layer for Xilinx Zynq
|
||||
UltraScale + MPSoC.
|
||||
The platform only uses the runtime part of ATF as ZynqMP already has a
|
||||
BootROM (BL1) and FSBL (BL2).
|
||||
|
||||
BL31 is ATF.
|
||||
BL32 is an optional Secure Payload.
|
||||
BL33 is the non-secure world software (U-Boot, Linux etc).
|
||||
|
||||
To build:
|
||||
```bash
|
||||
make ERROR_DEPRECATED=1 CROSS_COMPILE=aarch64-none-elf- PLAT=zynqmp bl31
|
||||
```
|
||||
|
||||
To build bl32 TSP you have to rebuild bl31 too:
|
||||
```bash
|
||||
make ERROR_DEPRECATED=1 CROSS_COMPILE=aarch64-none-elf- PLAT=zynqmp SPD=tspd bl31 bl32
|
||||
```
|
||||
|
||||
# ZynqMP platform specific build options
|
||||
* `ZYNQMP_ATF_MEM_BASE`: Specifies the base address of the bl31 binary.
|
||||
* `ZYNQMP_ATF_MEM_SIZE`: Specifies the size of the memory region of the bl31 binary.
|
||||
* `ZYNQMP_BL32_MEM_BASE`: Specifies the base address of the bl32 binary.
|
||||
* `ZYNQMP_BL32_MEM_SIZE`: Specifies the size of the memory region of the bl32 binary.
|
||||
|
||||
* `ZYNQMP_CONSOLE`: Select the console driver. Options:
|
||||
- `cadence`, `cadence0`: Cadence UART 0
|
||||
- `cadence1` : Cadence UART 1
|
||||
|
||||
# FSBL->ATF Parameter Passing
|
||||
The FSBL populates a data structure with image information for the ATF. The ATF
|
||||
uses that data to hand off to the loaded images. The address of the handoff data
|
||||
structure is passed in the ```PMU_GLOBAL.GLOBAL_GEN_STORAGE6``` register. The
|
||||
register is free to be used by other software once the ATF is bringing up
|
||||
further firmware images.
|
||||
|
||||
# Power Domain Tree
|
||||
The following power domain tree represents the power domain model used by the
|
||||
ATF for ZynqMP:
|
||||
```
|
||||
+-+
|
||||
|0|
|
||||
+-+
|
||||
+-------+---+---+-------+
|
||||
| | | |
|
||||
| | | |
|
||||
v v v v
|
||||
+-+ +-+ +-+ +-+
|
||||
|0| |1| |2| |3|
|
||||
+-+ +-+ +-+ +-+
|
||||
```
|
||||
The 4 leaf power domains represent the individual A53 cores, while resources
|
||||
common to the cluster are grouped in the power domain on the top.
|
|
@ -1,575 +0,0 @@
|
|||
Guide to migrate to new Platform porting interface
|
||||
==================================================
|
||||
|
||||
Contents
|
||||
--------
|
||||
|
||||
1. [Introduction](#1--introduction)
|
||||
2. [Platform API modification due to PSCI framework changes](#2--platform-api-modification-due-to-psci-framework-changes)
|
||||
* [Power domain topology framework platform API modifications](#21-power-domain-topology-framework-platform-api-modifications)
|
||||
* [Composite power state framework platform API modifications](#22-composite-power-state-framework-platform-api-modifications)
|
||||
* [Miscellaneous modifications](#23-miscellaneous-modifications)
|
||||
3. [Compatibility layer](#3--compatibility-layer)
|
||||
4. [Deprecated Platform API](#4--deprecated-platform-api)
|
||||
|
||||
- - - - - - - - - - - - - - - - - -
|
||||
|
||||
|
||||
1. Introduction
|
||||
----------------
|
||||
|
||||
The PSCI implementation in Trusted Firmware has undergone a redesign because of
|
||||
three requirements that the PSCI 1.0 specification introduced :
|
||||
|
||||
* Removing the framework assumption about the structure of the MPIDR, and
|
||||
its relation to the power topology enables support for deeper and more
|
||||
complex hierarchies.
|
||||
|
||||
* Reworking the power state coordination implementation in the framework
|
||||
to support the more detailed PSCI 1.0 requirements and reduce platform
|
||||
port complexity
|
||||
|
||||
* Enable the use of the extended power_state parameter and the larger StateID
|
||||
field
|
||||
|
||||
The PSCI 1.0 implementation introduces new frameworks to fulfill the above
|
||||
requirements. These framework changes mean that the platform porting API must
|
||||
also be modified. This document is a guide to assist migration of the existing
|
||||
platform ports to the new platform API.
|
||||
|
||||
This document describes the new platform API and compares it with the
|
||||
deprecated API. It also describes the compatibility layer that enables the
|
||||
existing platform ports to work with the PSCI 1.0 implementation. The
|
||||
deprecated platform API is documented for reference.
|
||||
|
||||
|
||||
2. Platform API modification due to PSCI framework changes
|
||||
-----------------------------------------------------------
|
||||
|
||||
This section describes changes to the platform APIs.
|
||||
|
||||
|
||||
2.1 Power domain topology framework platform API modifications
|
||||
--------------------------------------------------------------
|
||||
|
||||
This removes the assumption in the PSCI implementation that MPIDR
|
||||
based affinity instances map directly to power domains. A power domain, as
|
||||
described in section 4.2 of [PSCI], could contain a core or a logical group
|
||||
of cores (a cluster) which share some state on which power management
|
||||
operations can be performed. The existing affinity instance based APIs
|
||||
`plat_get_aff_count()` and `plat_get_aff_state()` are deprecated. The new
|
||||
platform interfaces that are introduced for this framework are:
|
||||
|
||||
* `plat_core_pos_by_mpidr()`
|
||||
* `plat_my_core_pos()`
|
||||
* `plat_get_power_domain_tree_desc()`
|
||||
|
||||
`plat_my_core_pos()` and `plat_core_pos_by_mpidr()` are mandatory
|
||||
and are meant to replace the existing `platform_get_core_pos()` API.
|
||||
The description of these APIs can be found in the [Porting Guide][my_core_pos].
|
||||
These are used by the power domain topology framework such that:
|
||||
|
||||
1. The generic PSCI code does not generate MPIDRs or use them to query the
|
||||
platform about the number of power domains at a particular power level. The
|
||||
`plat_get_power_domain_tree_desc()` provides a description of the power
|
||||
domain tree on the SoC through a pointer to the byte array containing the
|
||||
power domain topology tree description data structure.
|
||||
|
||||
2. The linear indices returned by `plat_core_pos_by_mpidr()` and
|
||||
`plat_my_core_pos()` are used to retrieve core power domain nodes from
|
||||
the power domain tree. These core indices are unique for a core and it is a
|
||||
number between `0` and `PLATFORM_CORE_COUNT - 1`. The platform can choose
|
||||
to implement a static mapping between `MPIDR` and core index or implement
|
||||
a dynamic mapping, choosing to skip the unavailable/unused cores to compact
|
||||
the core indices.
|
||||
|
||||
In addition, the platforms must define the macros `PLAT_NUM_PWR_DOMAINS` and
|
||||
`PLAT_MAX_PWR_LVL` which replace the macros `PLAT_NUM_AFFS` and
|
||||
`PLATFORM_MAX_AFFLVL` respectively. On platforms where the affinity instances
|
||||
correspond to power domains, the values of new macros remain the same as the
|
||||
old ones.
|
||||
|
||||
More details on the power domain topology description and its platform
|
||||
interface can be found in [psci pd tree].
|
||||
|
||||
|
||||
2.2 Composite power state framework platform API modifications
|
||||
--------------------------------------------------------------
|
||||
|
||||
The state-ID field in the power-state parameter of a CPU_SUSPEND call can be
|
||||
used to describe the composite power states specific to a platform. The existing
|
||||
PSCI state coordination had the limitation that it operates on a run/off
|
||||
granularity of power states and it did not interpret the state-ID field. This
|
||||
was acceptable as the specification requirement in PSCI 0.2 and the framework's
|
||||
approach to coordination only required maintaining a reference
|
||||
count of the number of cores that have requested the cluster to remain powered.
|
||||
|
||||
In the PSCI 1.0 specification, this approach is non optimal. If composite
|
||||
power states are used, the PSCI implementation cannot make global
|
||||
decisions about state coordination required because it does not understand the
|
||||
platform specific states.
|
||||
|
||||
The PSCI 1.0 implementation now defines a generic representation of the
|
||||
power-state parameter :
|
||||
|
||||
typedef struct psci_power_state {
|
||||
plat_local_state_t pwr_domain_state[PLAT_MAX_PWR_LVL + 1];
|
||||
} psci_power_state_t;
|
||||
|
||||
|
||||
`pwr_domain_state` is an array where each index corresponds to a power level.
|
||||
Each entry in the array contains the local power state the power domain at
|
||||
that power level could enter. The meaning of the local power state value is
|
||||
platform defined, and can vary between levels in a single platform. The PSCI
|
||||
implementation constraints the values only so that it can classify the state
|
||||
as RUN, RETENTION or OFF as required by the specification:
|
||||
|
||||
1. Zero means RUN
|
||||
|
||||
2. All OFF state values at all levels must be higher than all
|
||||
RETENTION state values at all levels
|
||||
|
||||
The platform is required to define the macros `PLAT_MAX_RET_STATE` and
|
||||
`PLAT_MAX_OFF_STATE` to the framework. The requirement for these macros can
|
||||
be found in the [Porting Guide].
|
||||
|
||||
The PSCI 1.0 implementation adds support to involve the platform in state
|
||||
coordination. This enables the platform to decide the final target state.
|
||||
During a request to place a power domain in a low power state, the platform
|
||||
is passed an array of requested `plat_local_state_t` for that power domain by
|
||||
each core within it through the `plat_get_target_pwr_state()` API. This API
|
||||
coordinates amongst these requested states to determine a target
|
||||
`plat_local_state_t` for that power domain. A default weak implementation of
|
||||
this API is provided in the platform layer which returns the minimum of the
|
||||
requested local states back to the PSCI state coordination. More details
|
||||
of `plat_get_target_pwr_state()` API can be found in the
|
||||
[Porting Guide][get_target_pwr_state].
|
||||
|
||||
The PSCI Generic implementation expects platform ports to populate the handlers
|
||||
for the `plat_psci_ops` structure which is declared as :
|
||||
|
||||
typedef struct plat_psci_ops {
|
||||
void (*cpu_standby)(plat_local_state_t cpu_state);
|
||||
int (*pwr_domain_on)(u_register_t mpidr);
|
||||
void (*pwr_domain_off)(const psci_power_state_t *target_state);
|
||||
void (*pwr_domain_suspend)(const psci_power_state_t *target_state);
|
||||
void (*pwr_domain_on_finish)(const psci_power_state_t *target_state);
|
||||
void (*pwr_domain_suspend_finish)(
|
||||
const psci_power_state_t *target_state);
|
||||
void (*system_off)(void) __dead2;
|
||||
void (*system_reset)(void) __dead2;
|
||||
int (*validate_power_state)(unsigned int power_state,
|
||||
psci_power_state_t *req_state);
|
||||
int (*validate_ns_entrypoint)(unsigned long ns_entrypoint);
|
||||
void (*get_sys_suspend_power_state)(
|
||||
psci_power_state_t *req_state);
|
||||
} plat_psci_ops_t;
|
||||
|
||||
The description of these handlers can be found in the [Porting Guide][psci_ops].
|
||||
The previous `plat_pm_ops` structure is deprecated. Compared with the previous
|
||||
handlers, the major differences are:
|
||||
|
||||
* Difference in parameters
|
||||
|
||||
The PSCI 1.0 implementation depends on the `validate_power_state` handler to
|
||||
convert the power-state parameter (possibly encoding a composite power state)
|
||||
passed in a PSCI `CPU_SUSPEND` to the `psci_power_state` format. This handler
|
||||
is now mandatory for PSCI `CPU_SUSPEND` support.
|
||||
|
||||
The `plat_psci_ops` handlers, `pwr_domain_off` and `pwr_domain_suspend`, are
|
||||
passed the target local state for each affected power domain. The platform
|
||||
must execute operations specific to these target states. Similarly,
|
||||
`pwr_domain_on_finish` and `pwr_domain_suspend_finish` are passed the local
|
||||
states of the affected power domains before wakeup. The platform
|
||||
must execute actions to restore these power domains from these specific
|
||||
local states.
|
||||
|
||||
* Difference in invocation
|
||||
|
||||
Whereas the power management handlers in `plat_pm_ops` used to be invoked
|
||||
for each affinity level till the target affinity level, the new handlers
|
||||
are only invoked once. The `target_state` encodes the target low power
|
||||
state or the low power state woken up from for each affected power domain.
|
||||
|
||||
* Difference in semantics
|
||||
|
||||
Although the previous `suspend` handlers could be used for power down as well
|
||||
as retention at different affinity levels, the new handlers make this support
|
||||
explicit. The `pwr_domain_suspend` can be used to specify powerdown and
|
||||
retention at various power domain levels subject to the conditions mentioned
|
||||
in section 4.2.1 of [PSCI]
|
||||
|
||||
Unlike the previous `standby` handler, the `cpu_standby()` handler is only used
|
||||
as a fast path for placing a core power domain into a standby or retention
|
||||
state.
|
||||
|
||||
The below diagram shows the sequence of a PSCI SUSPEND call and the interaction
|
||||
with the platform layer depicting the exchange of data between PSCI Generic
|
||||
layer and the platform layer.
|
||||
|
||||

|
||||
|
||||
Refer [plat/arm/board/fvp/fvp_pm.c] for the implementation details of
|
||||
these handlers for the FVP. The commit 38dce70f51fb83b27958ba3e2ad15f5635cb1061
|
||||
demonstrates the migration of ARM reference platforms to the new platform API.
|
||||
|
||||
|
||||
2.3 Miscellaneous modifications
|
||||
-------------------------------
|
||||
|
||||
In addition to the framework changes, unification of warm reset entry points on
|
||||
wakeup from low power modes has led to a change in the platform API. In the
|
||||
earlier implementation, the warm reset entry used to be programmed into the
|
||||
mailboxes by the 'ON' and 'SUSPEND' power management hooks. In the PSCI 1.0
|
||||
implementation, this information is not required, because it can figure that
|
||||
out by querying affinity info state whether to execute the 'suspend_finisher`
|
||||
or 'on_finisher'.
|
||||
|
||||
As a result, the warm reset entry point must be programmed only once. The
|
||||
`plat_setup_psci_ops()` API takes the secure entry point as an
|
||||
additional parameter to enable the platforms to configure their mailbox. The
|
||||
plat_psci_ops handlers `pwr_domain_on` and `pwr_domain_suspend` no longer take
|
||||
the warm reset entry point as a parameter.
|
||||
|
||||
Also, some platform APIs which took `MPIDR` as an argument were only ever
|
||||
invoked to perform actions specific to the caller core which makes the argument
|
||||
redundant. Therefore the platform APIs `plat_get_my_entrypoint()`,
|
||||
`plat_is_my_cpu_primary()`, `plat_set_my_stack()` and
|
||||
`plat_get_my_stack()` are defined which are meant to be invoked only for
|
||||
operations on the current caller core instead of `platform_get_entrypoint()`,
|
||||
`platform_is_primary_cpu()`, `platform_set_stack()` and `platform_get_stack()`.
|
||||
|
||||
|
||||
3. Compatibility layer
|
||||
----------------------
|
||||
|
||||
To ease the migration of the platform ports to the new porting interface,
|
||||
a compatibility layer is introduced that essentially implements a glue layer
|
||||
between the old platform API and the new API. The build flag
|
||||
`ENABLE_PLAT_COMPAT` (enabled by default), specifies whether to enable this
|
||||
layer or not. A platform port which has migrated to the new API can disable
|
||||
this flag within the platform specific makefile.
|
||||
|
||||
The compatibility layer works on the assumption that the onus of
|
||||
state coordination, in case multiple low power states are supported,
|
||||
is with the platform. The generic PSCI implementation only takes into
|
||||
account whether the suspend request is power down or not. This corresponds
|
||||
with the behavior of the PSCI implementation before the introduction of
|
||||
new frameworks. Also, it assumes that the affinity levels of the platform
|
||||
correspond directly to the power domain levels.
|
||||
|
||||
The compatibility layer dynamically constructs the new topology
|
||||
description array by querying the platform using `plat_get_aff_count()`
|
||||
and `plat_get_aff_state()` APIs. The linear index returned by
|
||||
`platform_get_core_pos()` is used as the core index for the cores. The
|
||||
higher level (non-core) power domain nodes must know the cores contained
|
||||
within its domain. It does so by storing the core index of first core
|
||||
within it and number of core indexes following it. This means that core
|
||||
indices returned by `platform_get_core_pos()` for cores within a particular
|
||||
power domain must be consecutive. We expect that this is the case for most
|
||||
platform ports including ARM reference platforms.
|
||||
|
||||
The old PSCI helpers like `psci_get_suspend_powerstate()`,
|
||||
`psci_get_suspend_stateid()`, `psci_get_suspend_stateid_by_mpidr()`,
|
||||
`psci_get_max_phys_off_afflvl()` and `psci_get_suspend_afflvl()` are also
|
||||
implemented for the compatibility layer. This allows the existing
|
||||
platform ports to work with the new PSCI frameworks without significant
|
||||
rework.
|
||||
|
||||
|
||||
4. Deprecated Platform API
|
||||
---------------------------
|
||||
|
||||
This section documents the deprecated platform porting API.
|
||||
|
||||
## Common mandatory modifications
|
||||
|
||||
The mandatory macros to be defined by the platform port in `platform_def.h`
|
||||
|
||||
* **#define : PLATFORM_NUM_AFFS**
|
||||
|
||||
Defines the total number of nodes in the affinity hierarchy at all affinity
|
||||
levels used by the platform.
|
||||
|
||||
* **#define : PLATFORM_MAX_AFFLVL**
|
||||
|
||||
Defines the maximum affinity level that the power management operations
|
||||
should apply to. ARMv8-A has support for four affinity levels. It is likely
|
||||
that hardware will implement fewer affinity levels. This macro allows the
|
||||
PSCI implementation to consider only those affinity levels in the system
|
||||
that the platform implements. For example, the Base AEM FVP implements two
|
||||
clusters with a configurable number of cores. It reports the maximum
|
||||
affinity level as 1, resulting in PSCI power control up to the cluster
|
||||
level.
|
||||
|
||||
The following functions must be implemented by the platform port to enable
|
||||
the reset vector code to perform the required tasks.
|
||||
|
||||
### Function : platform_get_entrypoint() [mandatory]
|
||||
|
||||
Argument : unsigned long
|
||||
Return : unsigned long
|
||||
|
||||
This function is called with the `SCTLR.M` and `SCTLR.C` bits disabled. The core
|
||||
is identified by its `MPIDR`, which is passed as the argument. The function is
|
||||
responsible for distinguishing between a warm and cold reset using platform-
|
||||
specific means. If it is a warm reset, it returns the entrypoint into the
|
||||
BL31 image that the core must jump to. If it is a cold reset, this function
|
||||
must return zero.
|
||||
|
||||
This function is also responsible for implementing a platform-specific mechanism
|
||||
to handle the condition where the core has been warm reset but there is no
|
||||
entrypoint to jump to.
|
||||
|
||||
This function does not follow the Procedure Call Standard used by the
|
||||
Application Binary Interface for the ARM 64-bit architecture. The caller should
|
||||
not assume that callee saved registers are preserved across a call to this
|
||||
function.
|
||||
|
||||
### Function : platform_is_primary_cpu() [mandatory]
|
||||
|
||||
Argument : unsigned long
|
||||
Return : unsigned int
|
||||
|
||||
This function identifies a core by its `MPIDR`, which is passed as the argument,
|
||||
to determine whether this core is the primary core or a secondary core. A return
|
||||
value of zero indicates that the core is not the primary core, while a non-zero
|
||||
return value indicates that the core is the primary core.
|
||||
|
||||
## Common optional modifications
|
||||
|
||||
### Function : platform_get_core_pos()
|
||||
|
||||
Argument : unsigned long
|
||||
Return : int
|
||||
|
||||
A platform may need to convert the `MPIDR` of a core to an absolute number, which
|
||||
can be used as a core-specific linear index into blocks of memory (for example
|
||||
while allocating per-core stacks). This routine contains a simple mechanism
|
||||
to perform this conversion, using the assumption that each cluster contains a
|
||||
maximum of four cores:
|
||||
|
||||
linear index = cpu_id + (cluster_id * 4)
|
||||
|
||||
cpu_id = 8-bit value in MPIDR at affinity level 0
|
||||
cluster_id = 8-bit value in MPIDR at affinity level 1
|
||||
|
||||
|
||||
### Function : platform_set_stack()
|
||||
|
||||
Argument : unsigned long
|
||||
Return : void
|
||||
|
||||
This function sets the current stack pointer to the normal memory stack that
|
||||
has been allocated for the core specified by MPIDR. For BL images that only
|
||||
require a stack for the primary core the parameter is ignored. The size of
|
||||
the stack allocated to each core is specified by the platform defined constant
|
||||
`PLATFORM_STACK_SIZE`.
|
||||
|
||||
Common implementations of this function for the UP and MP BL images are
|
||||
provided in [plat/common/aarch64/platform_up_stack.S] and
|
||||
[plat/common/aarch64/platform_mp_stack.S]
|
||||
|
||||
|
||||
### Function : platform_get_stack()
|
||||
|
||||
Argument : unsigned long
|
||||
Return : unsigned long
|
||||
|
||||
This function returns the base address of the normal memory stack that
|
||||
has been allocated for the core specificed by MPIDR. For BL images that only
|
||||
require a stack for the primary core the parameter is ignored. The size of
|
||||
the stack allocated to each core is specified by the platform defined constant
|
||||
`PLATFORM_STACK_SIZE`.
|
||||
|
||||
Common implementations of this function for the UP and MP BL images are
|
||||
provided in [plat/common/aarch64/platform_up_stack.S] and
|
||||
[plat/common/aarch64/platform_mp_stack.S]
|
||||
|
||||
|
||||
## Modifications for Power State Coordination Interface (in BL31)
|
||||
|
||||
The following functions must be implemented to initialize PSCI functionality in
|
||||
the ARM Trusted Firmware.
|
||||
|
||||
|
||||
### Function : plat_get_aff_count() [mandatory]
|
||||
|
||||
Argument : unsigned int, unsigned long
|
||||
Return : unsigned int
|
||||
|
||||
This function may execute with the MMU and data caches enabled if the platform
|
||||
port does the necessary initializations in `bl31_plat_arch_setup()`. It is only
|
||||
called by the primary core.
|
||||
|
||||
This function is called by the PSCI initialization code to detect the system
|
||||
topology. Its purpose is to return the number of affinity instances implemented
|
||||
at a given `affinity level` (specified by the first argument) and a given
|
||||
`MPIDR` (specified by the second argument). For example, on a dual-cluster
|
||||
system where first cluster implements two cores and the second cluster
|
||||
implements four cores, a call to this function with an `MPIDR` corresponding
|
||||
to the first cluster (`0x0`) and affinity level 0, would return 2. A call
|
||||
to this function with an `MPIDR` corresponding to the second cluster (`0x100`)
|
||||
and affinity level 0, would return 4.
|
||||
|
||||
|
||||
### Function : plat_get_aff_state() [mandatory]
|
||||
|
||||
Argument : unsigned int, unsigned long
|
||||
Return : unsigned int
|
||||
|
||||
This function may execute with the MMU and data caches enabled if the platform
|
||||
port does the necessary initializations in `bl31_plat_arch_setup()`. It is only
|
||||
called by the primary core.
|
||||
|
||||
This function is called by the PSCI initialization code. Its purpose is to
|
||||
return the state of an affinity instance. The affinity instance is determined by
|
||||
the affinity ID at a given `affinity level` (specified by the first argument)
|
||||
and an `MPIDR` (specified by the second argument). The state can be one of
|
||||
`PSCI_AFF_PRESENT` or `PSCI_AFF_ABSENT`. The latter state is used to cater for
|
||||
system topologies where certain affinity instances are unimplemented. For
|
||||
example, consider a platform that implements a single cluster with four cores and
|
||||
another core implemented directly on the interconnect with the cluster. The
|
||||
`MPIDR`s of the cluster would range from `0x0-0x3`. The `MPIDR` of the single
|
||||
core is 0x100 to indicate that it does not belong to cluster 0. Cluster 1
|
||||
is missing but needs to be accounted for to reach this single core in the
|
||||
topology tree. Therefore it is marked as `PSCI_AFF_ABSENT`.
|
||||
|
||||
|
||||
### Function : platform_setup_pm() [mandatory]
|
||||
|
||||
Argument : const plat_pm_ops **
|
||||
Return : int
|
||||
|
||||
This function may execute with the MMU and data caches enabled if the platform
|
||||
port does the necessary initializations in `bl31_plat_arch_setup()`. It is only
|
||||
called by the primary core.
|
||||
|
||||
This function is called by PSCI initialization code. Its purpose is to export
|
||||
handler routines for platform-specific power management actions by populating
|
||||
the passed pointer with a pointer to the private `plat_pm_ops` structure of
|
||||
BL31.
|
||||
|
||||
A description of each member of this structure is given below. A platform port
|
||||
is expected to implement these handlers if the corresponding PSCI operation
|
||||
is to be supported and these handlers are expected to succeed if the return
|
||||
type is `void`.
|
||||
|
||||
#### plat_pm_ops.affinst_standby()
|
||||
|
||||
Perform the platform-specific setup to enter the standby state indicated by the
|
||||
passed argument. The generic code expects the handler to succeed.
|
||||
|
||||
#### plat_pm_ops.affinst_on()
|
||||
|
||||
Perform the platform specific setup to power on an affinity instance, specified
|
||||
by the `MPIDR` (first argument) and `affinity level` (third argument). The
|
||||
`state` (fourth argument) contains the current state of that affinity instance
|
||||
(ON or OFF). This is useful to determine whether any action must be taken. For
|
||||
example, while powering on a core, the cluster that contains this core might
|
||||
already be in the ON state. The platform decides what actions must be taken to
|
||||
transition from the current state to the target state (indicated by the power
|
||||
management operation). The generic code expects the platform to return
|
||||
E_SUCCESS on success or E_INTERN_FAIL for any failure.
|
||||
|
||||
#### plat_pm_ops.affinst_off()
|
||||
|
||||
Perform the platform specific setup to power off an affinity instance of the
|
||||
calling core. It is called by the PSCI `CPU_OFF` API implementation.
|
||||
|
||||
The `affinity level` (first argument) and `state` (second argument) have
|
||||
a similar meaning as described in the `affinst_on()` operation. They
|
||||
identify the affinity instance on which the call is made and its
|
||||
current state. This gives the platform port an indication of the
|
||||
state transition it must make to perform the requested action. For example, if
|
||||
the calling core is the last powered on core in the cluster, after powering down
|
||||
affinity level 0 (the core), the platform port should power down affinity
|
||||
level 1 (the cluster) as well. The generic code expects the handler to succeed.
|
||||
|
||||
#### plat_pm_ops.affinst_suspend()
|
||||
|
||||
Perform the platform specific setup to power off an affinity instance of the
|
||||
calling core. It is called by the PSCI `CPU_SUSPEND` API and `SYSTEM_SUSPEND`
|
||||
API implementation
|
||||
|
||||
The `affinity level` (second argument) and `state` (third argument) have a
|
||||
similar meaning as described in the `affinst_on()` operation. They are used to
|
||||
identify the affinity instance on which the call is made and its current state.
|
||||
This gives the platform port an indication of the state transition it must
|
||||
make to perform the requested action. For example, if the calling core is the
|
||||
last powered on core in the cluster, after powering down affinity level 0
|
||||
(the core), the platform port should power down affinity level 1 (the cluster)
|
||||
as well.
|
||||
|
||||
The difference between turning an affinity instance off and suspending it
|
||||
is that in the former case, the affinity instance is expected to re-initialize
|
||||
its state when it is next powered on (see `affinst_on_finish()`). In the latter
|
||||
case, the affinity instance is expected to save enough state so that it can
|
||||
resume execution by restoring this state when it is powered on (see
|
||||
`affinst_suspend_finish()`).The generic code expects the handler to succeed.
|
||||
|
||||
#### plat_pm_ops.affinst_on_finish()
|
||||
|
||||
This function is called by the PSCI implementation after the calling core is
|
||||
powered on and released from reset in response to an earlier PSCI `CPU_ON` call.
|
||||
It performs the platform-specific setup required to initialize enough state for
|
||||
this core to enter the Normal world and also provide secure runtime firmware
|
||||
services.
|
||||
|
||||
The `affinity level` (first argument) and `state` (second argument) have a
|
||||
similar meaning as described in the previous operations. The generic code
|
||||
expects the handler to succeed.
|
||||
|
||||
#### plat_pm_ops.affinst_suspend_finish()
|
||||
|
||||
This function is called by the PSCI implementation after the calling core is
|
||||
powered on and released from reset in response to an asynchronous wakeup
|
||||
event, for example a timer interrupt that was programmed by the core during the
|
||||
`CPU_SUSPEND` call or `SYSTEM_SUSPEND` call. It performs the platform-specific
|
||||
setup required to restore the saved state for this core to resume execution
|
||||
in the Normal world and also provide secure runtime firmware services.
|
||||
|
||||
The `affinity level` (first argument) and `state` (second argument) have a
|
||||
similar meaning as described in the previous operations. The generic code
|
||||
expects the platform to succeed.
|
||||
|
||||
#### plat_pm_ops.validate_power_state()
|
||||
|
||||
This function is called by the PSCI implementation during the `CPU_SUSPEND`
|
||||
call to validate the `power_state` parameter of the PSCI API. If the
|
||||
`power_state` is known to be invalid, the platform must return
|
||||
PSCI_E_INVALID_PARAMS as an error, which is propagated back to the Normal
|
||||
world PSCI client.
|
||||
|
||||
#### plat_pm_ops.validate_ns_entrypoint()
|
||||
|
||||
This function is called by the PSCI implementation during the `CPU_SUSPEND`,
|
||||
`SYSTEM_SUSPEND` and `CPU_ON` calls to validate the Non-secure `entry_point`
|
||||
parameter passed by the Normal world. If the `entry_point` is known to be
|
||||
invalid, the platform must return PSCI_E_INVALID_PARAMS as an error, which is
|
||||
propagated back to the Normal world PSCI client.
|
||||
|
||||
#### plat_pm_ops.get_sys_suspend_power_state()
|
||||
|
||||
This function is called by the PSCI implementation during the `SYSTEM_SUSPEND`
|
||||
call to return the `power_state` parameter. This allows the platform to encode
|
||||
the appropriate State-ID field within the `power_state` parameter which can be
|
||||
utilized in `affinst_suspend()` to suspend to system affinity level. The
|
||||
`power_state` parameter should be in the same format as specified by the
|
||||
PSCI specification for the CPU_SUSPEND API.
|
||||
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
_Copyright (c) 2015, ARM Limited and Contributors. All rights reserved._
|
||||
|
||||
|
||||
[Porting Guide]: porting-guide.md
|
||||
[Power Domain Topology Design]: psci-pd-tree.md
|
||||
[PSCI]: http://infocenter.arm.com/help/topic/com.arm.doc.den0022c/DEN0022C_Power_State_Coordination_Interface.pdf
|
||||
[psci pd tree]: psci-pd-tree.md
|
||||
[my_core_pos]: porting-guide.md#function--plat_my_core_pos
|
||||
[get_target_pwr_state]: porting-guide.md#function--plat_get_target_pwr_state-optional
|
||||
[psci_ops]: porting-guide.md#function--plat_setup_psci_ops-mandatory
|
||||
[plat/arm/board/fvp/fvp_pm.c]: ../plat/arm/board/fvp/fvp_pm.c
|
||||
[plat/common/aarch64/platform_mp_stack.S]: ../plat/common/aarch64/platform_mp_stack.S
|
||||
[plat/common/aarch64/platform_up_stack.S]: ../plat/common/aarch64/platform_up_stack.S
|
File diff suppressed because it is too large
Load diff
|
@ -1,536 +0,0 @@
|
|||
PSCI Library Integration guide for ARMv8-A AArch32 systems
|
||||
==========================================================
|
||||
|
||||
Contents
|
||||
|
||||
1. [Introduction](#1-introduction)
|
||||
2. [Generic call sequence for PSCI Library interface (AArch32)](#2-generic-call-sequence-for-psci-library-interface-aarch32)
|
||||
3. [PSCI CPU context management](#3-psci-cpu-context-management)
|
||||
4. [PSCI Library Interface](#4-psci-library-interface)
|
||||
5. [EL3 Runtime Software dependencies](#5-el3-runtime-software-dependencies)
|
||||
|
||||
|
||||
1. Introduction
|
||||
---------------
|
||||
|
||||
This document describes the PSCI library interface with a focus on how to
|
||||
integrate with a suitable Trusted OS for an ARMv8-A AArch32 system. The PSCI
|
||||
Library implements the PSCI Standard as described in [PSCI spec] and is meant
|
||||
to be integrated with EL3 Runtime Software which invokes the PSCI Library
|
||||
interface appropriately. **EL3 Runtime Software** refers to software executing
|
||||
at the highest secure privileged mode, which is EL3 in AArch64 or Secure SVC/
|
||||
Monitor mode in AArch32, and provides runtime services to the non-secure world.
|
||||
The runtime service request is made via SMC (Secure Monitor Call) and the call
|
||||
must adhere to [SMCCC]. In AArch32, EL3 Runtime Software may additionally
|
||||
include Trusted OS functionality. A minimal AArch32 Secure Payload, SP-MIN, is
|
||||
provided in ARM Trusted Firmware to illustrate the usage and integration of the
|
||||
PSCI library. The description of PSCI library interface and its integration
|
||||
with EL3 Runtime Software in this document is targeted towards AArch32 systems.
|
||||
|
||||
2. Generic call sequence for PSCI Library interface (AArch32)
|
||||
-------------------------------------------------------------
|
||||
|
||||
The generic call sequence of PSCI Library interfaces (see
|
||||
[section 4](#4-psci-library-interface)) during cold boot in AArch32
|
||||
system is described below:
|
||||
|
||||
1. After cold reset, the EL3 Runtime Software performs its cold boot
|
||||
initialization including the PSCI library pre-requisites mentioned in
|
||||
[section 4](#4-psci-library-interface), and also the necessary platform
|
||||
setup.
|
||||
|
||||
2. Call `psci_setup()` in Monitor mode.
|
||||
|
||||
3. Optionally call `psci_register_spd_pm_hook()` to register callbacks to
|
||||
do bookkeeping for the EL3 Runtime Software during power management.
|
||||
|
||||
4. Call `psci_prepare_next_non_secure_ctx()` to initialize the non-secure CPU
|
||||
context.
|
||||
|
||||
5. Get the non-secure `cpu_context_t` for the current CPU by calling
|
||||
`cm_get_context()` , then programming the registers in the non-secure
|
||||
context and exiting to non-secure world. If the EL3 Runtime Software needs
|
||||
additional configuration to be set for non-secure context, like routing
|
||||
FIQs to the secure world, the values of the registers can be modified prior
|
||||
to programming. See [section 3](#3-psci-cpu-context-management) for more
|
||||
details on CPU context management.
|
||||
|
||||
The generic call sequence of PSCI library interfaces during warm boot in
|
||||
AArch32 systems is described below:
|
||||
|
||||
1. After warm reset, the EL3 Runtime Software performs the necessary warm
|
||||
boot initialization including the PSCI library pre-requisites mentioned in
|
||||
[section 4](#4-psci-library-interface) (Note that the Data cache
|
||||
**must not** be enabled).
|
||||
|
||||
2. Call `psci_warmboot_entrypoint()` in Monitor mode. This interface
|
||||
initializes/restores the non-secure CPU context as well.
|
||||
|
||||
3. Do step 5 of the cold boot call sequence described above.
|
||||
|
||||
The generic call sequence of PSCI library interfaces on receipt of a PSCI SMC
|
||||
on an AArch32 system is described below:
|
||||
|
||||
1. On receipt of an SMC, save the register context as per [SMCCC].
|
||||
|
||||
2. If the SMC function identifier corresponds to a SMC32 PSCI API, construct
|
||||
the appropriate arguments and call the `psci_smc_handler()` interface.
|
||||
The invocation may or may not return back to the caller depending on
|
||||
whether the PSCI API resulted in power down of the CPU.
|
||||
|
||||
3. If `psci_smc_handler()` returns, populate the return value in R0 (AArch32)/
|
||||
X0 (AArch64) and restore other registers as per [SMCCC].
|
||||
|
||||
|
||||
3. PSCI CPU context management
|
||||
------------------------------
|
||||
|
||||
PSCI library is in charge of initializing/restoring the non-secure CPU system
|
||||
registers according to [PSCI specification][PSCI spec] during cold/warm boot.
|
||||
This is referred to as `PSCI CPU Context Management`. Registers that need to
|
||||
be preserved across CPU power down/power up cycles are maintained in
|
||||
`cpu_context_t` data structure. The initialization of other non-secure CPU
|
||||
system registers which do not require coordination with the EL3 Runtime
|
||||
Software is done directly by the PSCI library (see `cm_prepare_el3_exit()`).
|
||||
|
||||
The EL3 Runtime Software is responsible for managing register context
|
||||
during switch between Normal and Secure worlds. The register context to be
|
||||
saved and restored depends on the mechanism used to trigger the world switch.
|
||||
For example, if the world switch was triggered by an SMC call, then the
|
||||
registers need to be saved and restored according to [SMCCC]. In AArch64,
|
||||
due to the tight integration with BL31, both BL31 and PSCI library
|
||||
use the same `cpu_context_t` data structure for PSCI CPU context management
|
||||
and register context management during world switch. This cannot be assumed
|
||||
for AArch32 EL3 Runtime Software since most AArch32 Trusted OSes already implement
|
||||
a mechanism for register context management during world switch. Hence, when
|
||||
the PSCI library is integrated with a AArch32 EL3 Runtime Software, the
|
||||
`cpu_context_t` is stripped down for just PSCI CPU context management.
|
||||
|
||||
During cold/warm boot, after invoking appropriate PSCI library interfaces, it
|
||||
is expected that the EL3 Runtime Software will query the `cpu_context_t` and
|
||||
write appropriate values to the corresponding system registers. This mechanism
|
||||
resolves 2 additional problems for AArch32 EL3 Runtime Software:
|
||||
|
||||
1. Values for certain system registers like SCR and SCTLR cannot be
|
||||
unilaterally determined by PSCI library and need inputs from the EL3
|
||||
Runtime Software. Using `cpu_context_t` as an intermediary data store
|
||||
allows EL3 Runtime Software to modify the register values appropriately
|
||||
before programming them.
|
||||
|
||||
2. The PSCI library provides appropriate LR and SPSR values (entrypoint
|
||||
information) for exit into non-secure world. Using `cpu_context_t` as an
|
||||
intermediary data store allows the EL3 Runtime Software to store these
|
||||
values safely until it is ready for exit to non-secure world.
|
||||
|
||||
Currently the `cpu_context_t` data structure for AArch32 stores the following
|
||||
registers: R0 - R3, LR (R14), SCR, SPSR, SCTLR.
|
||||
|
||||
The EL3 Runtime Software must implement accessors to get/set pointers
|
||||
to CPU context `cpu_context_t` data and these are described in
|
||||
[section 5.2](#52-cpu-context-management-api).
|
||||
|
||||
|
||||
4. PSCI Library Interface
|
||||
-------------------------
|
||||
|
||||
The PSCI library implements the [PSCI Specification][PSCI spec]. The interfaces
|
||||
to this library are declared in `psci.h` and are as listed below:
|
||||
|
||||
```
|
||||
u_register_t psci_smc_handler(uint32_t smc_fid, u_register_t x1,
|
||||
u_register_t x2, u_register_t x3,
|
||||
u_register_t x4, void *cookie,
|
||||
void *handle, u_register_t flags);
|
||||
int psci_setup(const psci_lib_args_t *lib_args);
|
||||
void psci_warmboot_entrypoint(void);
|
||||
void psci_register_spd_pm_hook(const spd_pm_ops_t *pm);
|
||||
void psci_prepare_next_non_secure_ctx(entry_point_info_t *next_image_info);
|
||||
```
|
||||
|
||||
The CPU context data 'cpu_context_t' is programmed to the registers differently
|
||||
when PSCI is integrated with an AArch32 EL3 Runtime Software compared to
|
||||
when the PSCI is integrated with an AArch64 EL3 Runtime Software (BL31). For
|
||||
example, in the case of AArch64, there is no need to retrieve `cpu_context_t`
|
||||
data and program the registers as it will done implicitly as part of
|
||||
`el3_exit`. The description below of the PSCI interfaces is targeted at
|
||||
integration with an AArch32 EL3 Runtime Software.
|
||||
|
||||
The PSCI library is responsible for initializing/restoring the non-secure world
|
||||
to an appropriate state after boot and may choose to directly program the
|
||||
non-secure system registers. The PSCI generic code takes care not to directly
|
||||
modify any of the system registers affecting the secure world and instead
|
||||
returns the values to be programmed to these registers via `cpu_context_t`.
|
||||
The EL3 Runtime Software is responsible for programming those registers and
|
||||
can use the proposed values provided in the `cpu_context_t`, modifying the
|
||||
values if required.
|
||||
|
||||
PSCI library needs the flexibility to access both secure and non-secure
|
||||
copies of banked registers. Hence it needs to be invoked in Monitor mode
|
||||
for AArch32 and in EL3 for AArch64. The NS bit in SCR (in AArch32) or SCR_EL3
|
||||
(in AArch64) must be set to 0. Additional requirements for the PSCI library
|
||||
interfaces are:
|
||||
|
||||
* Instruction cache must be enabled
|
||||
* Both IRQ and FIQ must be masked for the current CPU
|
||||
* The page tables must be setup and the MMU enabled
|
||||
* The C runtime environment must be setup and stack initialized
|
||||
* The Data cache must be enabled prior to invoking any of the PSCI library
|
||||
interfaces except for `psci_warmboot_entrypoint()`. For
|
||||
`psci_warmboot_entrypoint()`, if the build option `HW_ASSISTED_COHERENCY`
|
||||
is enabled however, data caches are expected to be enabled.
|
||||
|
||||
Further requirements for each interface can be found in the interface
|
||||
description.
|
||||
|
||||
### 4.1 Interface : psci_setup()
|
||||
|
||||
Argument : const psci_lib_args_t *lib_args
|
||||
Return : void
|
||||
|
||||
This function is to be called by the primary CPU during cold boot before
|
||||
any other interface to the PSCI library. It takes `lib_args`, a const pointer
|
||||
to `psci_lib_args_t`, as the argument. The `psci_lib_args_t` is a versioned
|
||||
structure and is declared in `psci.h` header as follows:
|
||||
|
||||
```
|
||||
typedef struct psci_lib_args {
|
||||
/* The version information of PSCI Library Interface */
|
||||
param_header_t h;
|
||||
/* The warm boot entrypoint function */
|
||||
mailbox_entrypoint_t mailbox_ep;
|
||||
} psci_lib_args_t;
|
||||
```
|
||||
|
||||
The first field `h`, of `param_header_t` type, provides the version
|
||||
information. The second field `mailbox_ep` is the warm boot entrypoint address
|
||||
and is used to configure the platform mailbox. Helper macros are provided in
|
||||
psci.h to construct the `lib_args` argument statically or during runtime. Prior
|
||||
to calling the `psci_setup()` interface, the platform setup for cold boot
|
||||
must have completed. Major actions performed by this interface are:
|
||||
|
||||
* Initializes architecture.
|
||||
* Initializes PSCI power domain and state coordination data structures.
|
||||
* Calls `plat_setup_psci_ops()` with warm boot entrypoint `mailbox_ep` as
|
||||
argument.
|
||||
* Calls `cm_set_context_by_index()` (see
|
||||
[section 5.2](#52-cpu-context-management-api)) for all the CPUs in the
|
||||
platform
|
||||
|
||||
### 4.2 Interface : psci_prepare_next_non_secure_ctx()
|
||||
|
||||
Argument : entry_point_info_t *next_image_info
|
||||
Return : void
|
||||
|
||||
After `psci_setup()` and prior to exit to the non-secure world, this function
|
||||
must be called by the EL3 Runtime Software to initialize the non-secure world
|
||||
context. The non-secure world entrypoint information `next_image_info` (first
|
||||
argument) will be used to determine the non-secure context. After this function
|
||||
returns, the EL3 Runtime Software must retrieve the `cpu_context_t` (using
|
||||
cm_get_context()) for the current CPU and program the registers prior to exit
|
||||
to the non-secure world.
|
||||
|
||||
### 4.3 Interface : psci_register_spd_pm_hook()
|
||||
|
||||
Argument : const spd_pm_ops_t *
|
||||
Return : void
|
||||
|
||||
As explained in [section 5.4](#54-secure-payload-power-management-callback),
|
||||
the EL3 Runtime Software may want to perform some bookkeeping during power
|
||||
management operations. This function is used to register the `spd_pm_ops_t`
|
||||
(first argument) callbacks with the PSCI library which will be called
|
||||
ppropriately during power management. Calling this function is optional and
|
||||
need to be called by the primary CPU during the cold boot sequence after
|
||||
`psci_setup()` has completed.
|
||||
|
||||
### 4.4 Interface : psci_smc_handler()
|
||||
|
||||
Argument : uint32_t smc_fid, u_register_t x1,
|
||||
u_register_t x2, u_register_t x3,
|
||||
u_register_t x4, void *cookie,
|
||||
void *handle, u_register_t flags
|
||||
Return : u_register_t
|
||||
|
||||
This function is the top level handler for SMCs which fall within the
|
||||
PSCI service range specified in [SMCCC]. The function ID `smc_fid` (first
|
||||
argument) determines the PSCI API to be called. The `x1` to `x4` (2nd to 5th
|
||||
arguments), are the values of the registers r1 - r4 (in AArch32) or x1 - x4
|
||||
(in AArch64) when the SMC is received. These are the arguments to PSCI API as
|
||||
described in [PSCI spec]. The 'flags' (8th argument) is a bit field parameter
|
||||
and is detailed in 'smcc.h' header. It includes whether the call is from the
|
||||
secure or non-secure world. The `cookie` (6th argument) and the `handle`
|
||||
(7th argument) are not used and are reserved for future use.
|
||||
|
||||
The return value from this interface is the return value from the underlying
|
||||
PSCI API corresponding to `smc_fid`. This function may not return back to the
|
||||
caller if PSCI API causes power down of the CPU. In this case, when the CPU
|
||||
wakes up, it will start execution from the warm reset address.
|
||||
|
||||
### 4.5 Interface : psci_warmboot_entrypoint()
|
||||
|
||||
Argument : void
|
||||
Return : void
|
||||
|
||||
This function performs the warm boot initialization/restoration as mandated by
|
||||
[PSCI spec]. For AArch32, on wakeup from power down the CPU resets to secure SVC
|
||||
mode and the EL3 Runtime Software must perform the prerequisite initializations
|
||||
mentioned at top of this section. This function must be called with Data cache
|
||||
disabled (unless build option `HW_ASSISTED_COHERENCY` is enabled) but with MMU
|
||||
initialized and enabled. The major actions performed by this function are:
|
||||
|
||||
* Invalidates the stack and enables the data cache.
|
||||
* Initializes architecture and PSCI state coordination.
|
||||
* Restores/Initializes the peripheral drivers to the required state via
|
||||
appropriate `plat_psci_ops_t` hooks
|
||||
* Restores the EL3 Runtime Software context via appropriate `spd_pm_ops_t`
|
||||
callbacks.
|
||||
* Restores/Initializes the non-secure context and populates the
|
||||
`cpu_context_t` for the current CPU.
|
||||
|
||||
Upon the return of this function, the EL3 Runtime Software must retrieve the
|
||||
non-secure `cpu_context_t` using `cm_get_context()` and program the registers
|
||||
prior to exit to the non-secure world.
|
||||
|
||||
|
||||
5. EL3 Runtime Software dependencies
|
||||
---------------------------------------
|
||||
|
||||
The PSCI Library includes supporting frameworks like context management,
|
||||
cpu operations (cpu_ops) and per-cpu data framework. Other helper library
|
||||
functions like bakery locks and spin locks are also included in the library.
|
||||
The dependencies which must be fulfilled by the EL3 Runtime Software
|
||||
for integration with PSCI library are described below.
|
||||
|
||||
### 5.1 General dependencies
|
||||
|
||||
The PSCI library being a Multiprocessor (MP) implementation, EL3 Runtime
|
||||
Software must provide an SMC handling framework capable of MP adhering to
|
||||
[SMCCC] specification.
|
||||
|
||||
The EL3 Runtime Software must also export cache maintenance primitives
|
||||
and some helper utilities for assert, print and memory operations as listed
|
||||
below. The ARM Trusted Firmware source tree provides implementations for all
|
||||
these functions but the EL3 Runtime Software may use its own implementation.
|
||||
|
||||
**Functions : assert(), memcpy(), memset**
|
||||
|
||||
These must be implemented as described in ISO C Standard.
|
||||
|
||||
**Function : flush_dcache_range()**
|
||||
|
||||
Argument : uintptr_t addr, size_t size
|
||||
Return : void
|
||||
|
||||
This function cleans and invalidates (flushes) the data cache for memory
|
||||
at address `addr` (first argument) address and of size `size` (second argument).
|
||||
|
||||
**Function : inv_dcache_range()**
|
||||
|
||||
Argument : uintptr_t addr, size_t size
|
||||
Return : void
|
||||
|
||||
This function invalidates (flushes) the data cache for memory at address
|
||||
`addr` (first argument) address and of size `size` (second argument).
|
||||
|
||||
**Function : do_panic()**
|
||||
|
||||
Argument : void
|
||||
Return : void
|
||||
|
||||
This function will be called by the PSCI library on encountering a critical
|
||||
failure that cannot be recovered from. This function **must not** return.
|
||||
|
||||
**Function : tf_printf()**
|
||||
|
||||
This is printf-compatible function, but unlike printf, it does not return any
|
||||
value. The ARM Trusted Firmware source tree provides an implementation which
|
||||
is optimized for stack usage and supports only a subset of format specifiers.
|
||||
The details of the format specifiers supported can be found in the
|
||||
`tf_printf.c` file in ARM Trusted Firmware source tree.
|
||||
|
||||
### 5.2 CPU Context management API
|
||||
|
||||
The CPU context management data memory is statically allocated by PSCI library
|
||||
in BSS section. The PSCI library requires the EL3 Runtime Software to implement
|
||||
APIs to store and retrieve pointers to this CPU context data. SP-MIN
|
||||
demonstrates how these APIs can be implemented but the EL3 Runtime Software can
|
||||
choose a more optimal implementation (like dedicating the secure TPIDRPRW
|
||||
system register (in AArch32) for storing these pointers).
|
||||
|
||||
**Function : cm_set_context_by_index()**
|
||||
|
||||
Argument : unsigned int cpu_idx, void *context, unsigned int security_state
|
||||
Return : void
|
||||
|
||||
This function is called during cold boot when the `psci_setup()` PSCI library
|
||||
interface is called.
|
||||
|
||||
This function must store the pointer to the CPU context data, `context` (2nd
|
||||
argument), for the specified `security_state` (3rd argument) and CPU identified
|
||||
by `cpu_idx` (first argument). The `security_state` will always be non-secure
|
||||
when called by PSCI library and this argument is retained for compatibility
|
||||
with BL31. The `cpu_idx` will correspond to the index returned by the
|
||||
`plat_core_pos_by_mpidr()` for `mpidr` of the CPU.
|
||||
|
||||
The actual method of storing the `context` pointers is implementation specific.
|
||||
For example, SP-MIN stores the pointers in the array `sp_min_cpu_ctx_ptr`
|
||||
declared in `sp_min_main.c`.
|
||||
|
||||
**Function : cm_get_context()**
|
||||
|
||||
Argument : uint32_t security_state
|
||||
Return : void *
|
||||
|
||||
This function must return the pointer to the `cpu_context_t` structure for
|
||||
the specified `security_state` (first argument) for the current CPU. The caller
|
||||
must ensure that `cm_set_context_by_index` is called first and the appropriate
|
||||
context pointers are stored prior to invoking this API. The `security_state`
|
||||
will always be non-secure when called by PSCI library and this argument
|
||||
is retained for compatibility with BL31.
|
||||
|
||||
**Function : cm_get_context_by_index()**
|
||||
|
||||
Argument : unsigned int cpu_idx, unsigned int security_state
|
||||
Return : void *
|
||||
|
||||
This function must return the pointer to the `cpu_context_t` structure for
|
||||
the specified `security_state` (second argument) for the CPU identified by
|
||||
`cpu_idx` (first argument). The caller must ensure that
|
||||
`cm_set_context_by_index` is called first and the appropriate context
|
||||
pointers are stored prior to invoking this API. The `security_state` will
|
||||
always be non-secure when called by PSCI library and this argument is
|
||||
retained for compatibility with BL31. The `cpu_idx` will correspond to the
|
||||
index returned by the `plat_core_pos_by_mpidr()` for `mpidr` of the CPU.
|
||||
|
||||
### 5.3 Platform API
|
||||
|
||||
The platform layer abstracts the platform-specific details from the generic
|
||||
PSCI library. The following platform APIs/macros must be defined by the EL3
|
||||
Runtime Software for integration with the PSCI library.
|
||||
|
||||
The mandatory platform APIs are:
|
||||
|
||||
* plat_my_core_pos
|
||||
* plat_core_pos_by_mpidr
|
||||
* plat_get_syscnt_freq2
|
||||
* plat_get_power_domain_tree_desc
|
||||
* plat_setup_psci_ops
|
||||
* plat_reset_handler
|
||||
* plat_panic_handler
|
||||
* plat_get_my_stack
|
||||
|
||||
The mandatory platform macros are:
|
||||
|
||||
* PLATFORM_CORE_COUNT
|
||||
* PLAT_MAX_PWR_LVL
|
||||
* PLAT_NUM_PWR_DOMAINS
|
||||
* CACHE_WRITEBACK_GRANULE
|
||||
* PLAT_MAX_OFF_STATE
|
||||
* PLAT_MAX_RET_STATE
|
||||
* PLAT_MAX_PWR_LVL_STATES (optional)
|
||||
* PLAT_PCPU_DATA_SIZE (optional)
|
||||
|
||||
The details of these APIs/macros can be found in [Porting Guide].
|
||||
|
||||
All platform specific operations for power management are done via
|
||||
`plat_psci_ops_t` callbacks registered by the platform when
|
||||
`plat_setup_psci_ops()` API is called. The description of each of
|
||||
the callbacks in `plat_psci_ops_t` can be found in PSCI section of the
|
||||
[Porting Guide]. If any these callbacks are not registered, then the
|
||||
PSCI API associated with that callback will not be supported by PSCI
|
||||
library.
|
||||
|
||||
### 5.4 Secure payload power management callback
|
||||
|
||||
During PSCI power management operations, the EL3 Runtime Software may
|
||||
need to perform some bookkeeping, and PSCI library provides
|
||||
`spd_pm_ops_t` callbacks for this purpose. These hooks must be
|
||||
populated and registered by using `psci_register_spd_pm_hook()` PSCI
|
||||
library interface.
|
||||
|
||||
Typical bookkeeping during PSCI power management calls include save/restore
|
||||
of the EL3 Runtime Software context. Also if the EL3 Runtime Software makes
|
||||
use of secure interrupts, then these interrupts must also be managed
|
||||
appropriately during CPU power down/power up. Any secure interrupt targeted
|
||||
to the current CPU must be disabled or re-targeted to other running CPU prior
|
||||
to power down of the current CPU. During power up, these interrupt can be
|
||||
enabled/re-targeted back to the current CPU.
|
||||
|
||||
```
|
||||
typedef struct spd_pm_ops {
|
||||
void (*svc_on)(u_register_t target_cpu);
|
||||
int32_t (*svc_off)(u_register_t __unused);
|
||||
void (*svc_suspend)(u_register_t max_off_pwrlvl);
|
||||
void (*svc_on_finish)(u_register_t __unused);
|
||||
void (*svc_suspend_finish)(u_register_t max_off_pwrlvl);
|
||||
int32_t (*svc_migrate)(u_register_t from_cpu, u_register_t to_cpu);
|
||||
int32_t (*svc_migrate_info)(u_register_t *resident_cpu);
|
||||
void (*svc_system_off)(void);
|
||||
void (*svc_system_reset)(void);
|
||||
} spd_pm_ops_t;
|
||||
```
|
||||
A brief description of each callback is given below:
|
||||
|
||||
* svc_on, svc_off, svc_on_finish
|
||||
|
||||
The `svc_on`, `svc_off` callbacks are called during PSCI_CPU_ON,
|
||||
PSCI_CPU_OFF APIs respectively. The `svc_on_finish` is called when the
|
||||
target CPU of PSCI_CPU_ON API powers up and executes the
|
||||
`psci_warmboot_entrypoint()` PSCI library interface.
|
||||
|
||||
* svc_suspend, svc_suspend_finish
|
||||
|
||||
The `svc_suspend` callback is called during power down bu either
|
||||
PSCI_SUSPEND or PSCI_SYSTEM_SUSPEND APIs. The `svc_suspend_finish` is
|
||||
called when the CPU wakes up from suspend and executes the
|
||||
`psci_warmboot_entrypoint()` PSCI library interface. The `max_off_pwrlvl`
|
||||
(first parameter) denotes the highest power domain level being powered down
|
||||
to or woken up from suspend.
|
||||
|
||||
* svc_system_off, svc_system_reset
|
||||
|
||||
These callbacks are called during PSCI_SYSTEM_OFF and PSCI_SYSTEM_RESET
|
||||
PSCI APIs respectively.
|
||||
|
||||
* svc_migrate_info
|
||||
|
||||
This callback is called in response to PSCI_MIGRATE_INFO_TYPE or
|
||||
PSCI_MIGRATE_INFO_UP_CPU APIs. The return value of this callback must
|
||||
correspond to the return value of PSCI_MIGRATE_INFO_TYPE API as described
|
||||
in [PSCI spec]. If the secure payload is a Uniprocessor (UP)
|
||||
implementation, then it must update the mpidr of the CPU it is resident in
|
||||
via `resident_cpu` (first argument). The updates to `resident_cpu` is
|
||||
ignored if the secure payload is a multiprocessor (MP) implementation.
|
||||
|
||||
* svc_migrate
|
||||
|
||||
This callback is only relevant if the secure payload in EL3 Runtime
|
||||
Software is a Uniprocessor (UP) implementation and supports migration from
|
||||
the current CPU `from_cpu` (first argument) to another CPU `to_cpu`
|
||||
(second argument). This callback is called in response to PSCI_MIGRATE
|
||||
API. This callback is never called if the secure payload is a
|
||||
Multiprocessor (MP) implementation.
|
||||
|
||||
### 5.5 CPU operations
|
||||
|
||||
The CPU operations (cpu_ops) framework implement power down sequence specific
|
||||
to the CPU and the details of which can be found in the `CPU specific
|
||||
operations framework` section of [Firmware Design]. The ARM Trusted Firmware
|
||||
tree implements the `cpu_ops` for various supported CPUs and the EL3 Runtime
|
||||
Software needs to include the required `cpu_ops` in its build. The start and
|
||||
end of the `cpu_ops` descriptors must be exported by the EL3 Runtime Software
|
||||
via the `__CPU_OPS_START__` and `__CPU_OPS_END__` linker symbols.
|
||||
|
||||
The `cpu_ops` descriptors also include reset sequences and may include errata
|
||||
workarounds for the CPU. The EL3 Runtime Software can choose to call this
|
||||
during cold/warm reset if it does not implement its own reset sequence/errata
|
||||
workarounds.
|
||||
|
||||
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
_Copyright (c) 2016, ARM Limited and Contributors. All rights reserved._
|
||||
|
||||
[PSCI spec]: http://infocenter.arm.com/help/topic/com.arm.doc.den0022c/DEN0022C_Power_State_Coordination_Interface.pdf "Power State Coordination Interface PDD (ARM DEN 0022C)"
|
||||
[SMCCC]: https://silver.arm.com/download/ARM_and_AMBA_Architecture/AR570-DA-80002-r0p0-00rel0/ARM_DEN0028A_SMC_Calling_Convention.pdf "SMC Calling Convention"
|
||||
[Porting Guide]: porting-guide.md
|
||||
[Firmware Design]: ./firmware-design.md
|
|
@ -1,308 +0,0 @@
|
|||
PSCI Library Integration guide for ARMv8-A AArch32 systems
|
||||
==========================================================
|
||||
|
||||
Contents
|
||||
--------
|
||||
|
||||
1. [Requirements](#requirements)
|
||||
2. [Design](#design)
|
||||
|
||||
------------
|
||||
Requirements
|
||||
------------
|
||||
|
||||
1. A platform must export the `plat_get_aff_count()` and
|
||||
`plat_get_aff_state()` APIs to enable the generic PSCI code to
|
||||
populate a tree that describes the hierarchy of power domains in the
|
||||
system. This approach is inflexible because a change to the topology
|
||||
requires a change in the code.
|
||||
|
||||
It would be much simpler for the platform to describe its power domain tree
|
||||
in a data structure.
|
||||
|
||||
2. The generic PSCI code generates MPIDRs in order to populate the power domain
|
||||
tree. It also uses an MPIDR to find a node in the tree. The assumption that
|
||||
a platform will use exactly the same MPIDRs as generated by the generic PSCI
|
||||
code is not scalable. The use of an MPIDR also restricts the number of
|
||||
levels in the power domain tree to four.
|
||||
|
||||
Therefore, there is a need to decouple allocation of MPIDRs from the
|
||||
mechanism used to populate the power domain topology tree.
|
||||
|
||||
3. The current arrangement of the power domain tree requires a binary search
|
||||
over the sibling nodes at a particular level to find a specified power
|
||||
domain node. During a power management operation, the tree is traversed from
|
||||
a 'start' to an 'end' power level. The binary search is required to find the
|
||||
node at each level. The natural way to perform this traversal is to
|
||||
start from a leaf node and follow the parent node pointer to reach the end
|
||||
level.
|
||||
|
||||
Therefore, there is a need to define data structures that implement the tree in
|
||||
a way which facilitates such a traversal.
|
||||
|
||||
4. The attributes of a core power domain differ from the attributes of power
|
||||
domains at higher levels. For example, only a core power domain can be identified
|
||||
using an MPIDR. There is no requirement to perform state coordination while
|
||||
performing a power management operation on the core power domain.
|
||||
|
||||
Therefore, there is a need to implement the tree in a way which facilitates this
|
||||
distinction between a leaf and non-leaf node and any associated
|
||||
optimizations.
|
||||
|
||||
|
||||
------
|
||||
Design
|
||||
------
|
||||
|
||||
### Describing a power domain tree
|
||||
|
||||
To fulfill requirement 1., the existing platform APIs
|
||||
`plat_get_aff_count()` and `plat_get_aff_state()` have been
|
||||
removed. A platform must define an array of unsigned chars such that:
|
||||
|
||||
1. The first entry in the array specifies the number of power domains at the
|
||||
highest power level implemented in the platform. This caters for platforms
|
||||
where the power domain tree does not have a single root node, for example,
|
||||
the FVP has two cluster power domains at the highest level (1).
|
||||
|
||||
2. Each subsequent entry corresponds to a power domain and contains the number
|
||||
of power domains that are its direct children.
|
||||
|
||||
3. The size of the array minus the first entry will be equal to the number of
|
||||
non-leaf power domains.
|
||||
|
||||
4. The value in each entry in the array is used to find the number of entries
|
||||
to consider at the next level. The sum of the values (number of children) of
|
||||
all the entries at a level specifies the number of entries in the array for
|
||||
the next level.
|
||||
|
||||
The following example power domain topology tree will be used to describe the
|
||||
above text further. The leaf and non-leaf nodes in this tree have been numbered
|
||||
separately.
|
||||
|
||||
```
|
||||
+-+
|
||||
|0|
|
||||
+-+
|
||||
/ \
|
||||
/ \
|
||||
/ \
|
||||
/ \
|
||||
/ \
|
||||
/ \
|
||||
/ \
|
||||
/ \
|
||||
/ \
|
||||
/ \
|
||||
+-+ +-+
|
||||
|1| |2|
|
||||
+-+ +-+
|
||||
/ \ / \
|
||||
/ \ / \
|
||||
/ \ / \
|
||||
/ \ / \
|
||||
+-+ +-+ +-+ +-+
|
||||
|3| |4| |5| |6|
|
||||
+-+ +-+ +-+ +-+
|
||||
+---+-----+ +----+----| +----+----+ +----+-----+-----+
|
||||
| | | | | | | | | | | | |
|
||||
| | | | | | | | | | | | |
|
||||
v v v v v v v v v v v v v
|
||||
+-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +--+ +--+ +--+
|
||||
|0| |1| |2| |3| |4| |5| |6| |7| |8| |9| |10| |11| |12|
|
||||
+-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +--+ +--+ +--+
|
||||
```
|
||||
|
||||
|
||||
This tree is defined by the platform as the array described above as follows:
|
||||
|
||||
```
|
||||
#define PLAT_NUM_POWER_DOMAINS 20
|
||||
#define PLATFORM_CORE_COUNT 13
|
||||
#define PSCI_NUM_NON_CPU_PWR_DOMAINS \
|
||||
(PLAT_NUM_POWER_DOMAINS - PLATFORM_CORE_COUNT)
|
||||
|
||||
unsigned char plat_power_domain_tree_desc[] = { 1, 2, 2, 2, 3, 3, 3, 4};
|
||||
```
|
||||
|
||||
### Removing assumptions about MPIDRs used in a platform
|
||||
|
||||
To fulfill requirement 2., it is assumed that the platform assigns a
|
||||
unique number (core index) between `0` and `PLAT_CORE_COUNT - 1` to each core
|
||||
power domain. MPIDRs could be allocated in any manner and will not be used to
|
||||
populate the tree.
|
||||
|
||||
`plat_core_pos_by_mpidr(mpidr)` will return the core index for the core
|
||||
corresponding to the MPIDR. It will return an error (-1) if an MPIDR is passed
|
||||
which is not allocated or corresponds to an absent core. The semantics of this
|
||||
platform API have changed since it is required to validate the passed MPIDR. It
|
||||
has been made a mandatory API as a result.
|
||||
|
||||
Another mandatory API, `plat_my_core_pos()` has been added to return the core
|
||||
index for the calling core. This API provides a more lightweight mechanism to get
|
||||
the index since there is no need to validate the MPIDR of the calling core.
|
||||
|
||||
The platform should assign the core indices (as illustrated in the diagram above)
|
||||
such that, if the core nodes are numbered from left to right, then the index
|
||||
for a core domain will be the same as the index returned by
|
||||
`plat_core_pos_by_mpidr()` or `plat_my_core_pos()` for that core. This
|
||||
relationship allows the core nodes to be allocated in a separate array
|
||||
(requirement 4.) during `psci_setup()` in such an order that the index of the
|
||||
core in the array is the same as the return value from these APIs.
|
||||
|
||||
#### Dealing with holes in MPIDR allocation
|
||||
|
||||
For platforms where the number of allocated MPIDRs is equal to the number of
|
||||
core power domains, for example, Juno and FVPs, the logic to convert an MPIDR to
|
||||
a core index should remain unchanged. Both Juno and FVP use a simple collision
|
||||
proof hash function to do this.
|
||||
|
||||
It is possible that on some platforms, the allocation of MPIDRs is not
|
||||
contiguous or certain cores have been disabled. This essentially means that the
|
||||
MPIDRs have been sparsely allocated, that is, the size of the range of MPIDRs
|
||||
used by the platform is not equal to the number of core power domains.
|
||||
|
||||
The platform could adopt one of the following approaches to deal with this
|
||||
scenario:
|
||||
|
||||
1. Implement more complex logic to convert a valid MPIDR to a core index while
|
||||
maintaining the relationship described earlier. This means that the power
|
||||
domain tree descriptor will not describe any core power domains which are
|
||||
disabled or absent. Entries will not be allocated in the tree for these
|
||||
domains.
|
||||
|
||||
2. Treat unallocated MPIDRs and disabled cores as absent but still describe them
|
||||
in the power domain descriptor, that is, the number of core nodes described
|
||||
is equal to the size of the range of MPIDRs allocated. This approach will
|
||||
lead to memory wastage since entries will be allocated in the tree but will
|
||||
allow use of a simpler logic to convert an MPIDR to a core index.
|
||||
|
||||
|
||||
### Traversing through and distinguishing between core and non-core power domains
|
||||
|
||||
To fulfill requirement 3 and 4, separate data structures have been defined
|
||||
to represent leaf and non-leaf power domain nodes in the tree.
|
||||
|
||||
```
|
||||
/*******************************************************************************
|
||||
* The following two data structures implement the power domain tree. The tree
|
||||
* is used to track the state of all the nodes i.e. power domain instances
|
||||
* described by the platform. The tree consists of nodes that describe CPU power
|
||||
* domains i.e. leaf nodes and all other power domains which are parents of a
|
||||
* CPU power domain i.e. non-leaf nodes.
|
||||
******************************************************************************/
|
||||
typedef struct non_cpu_pwr_domain_node {
|
||||
/*
|
||||
* Index of the first CPU power domain node level 0 which has this node
|
||||
* as its parent.
|
||||
*/
|
||||
unsigned int cpu_start_idx;
|
||||
|
||||
/*
|
||||
* Number of CPU power domains which are siblings of the domain indexed
|
||||
* by 'cpu_start_idx' i.e. all the domains in the range 'cpu_start_idx
|
||||
* -> cpu_start_idx + ncpus' have this node as their parent.
|
||||
*/
|
||||
unsigned int ncpus;
|
||||
|
||||
/* Index of the parent power domain node */
|
||||
unsigned int parent_node;
|
||||
|
||||
-----
|
||||
} non_cpu_pd_node_t;
|
||||
|
||||
typedef struct cpu_pwr_domain_node {
|
||||
u_register_t mpidr;
|
||||
|
||||
/* Index of the parent power domain node */
|
||||
unsigned int parent_node;
|
||||
|
||||
-----
|
||||
} cpu_pd_node_t;
|
||||
```
|
||||
|
||||
The power domain tree is implemented as a combination of the following data
|
||||
structures.
|
||||
|
||||
```
|
||||
non_cpu_pd_node_t psci_non_cpu_pd_nodes[PSCI_NUM_NON_CPU_PWR_DOMAINS];
|
||||
cpu_pd_node_t psci_cpu_pd_nodes[PLATFORM_CORE_COUNT];
|
||||
```
|
||||
|
||||
### Populating the power domain tree
|
||||
|
||||
The `populate_power_domain_tree()` function in `psci_setup.c` implements the
|
||||
algorithm to parse the power domain descriptor exported by the platform to
|
||||
populate the two arrays. It is essentially a breadth-first-search. The nodes for
|
||||
each level starting from the root are laid out one after another in the
|
||||
`psci_non_cpu_pd_nodes` and `psci_cpu_pd_nodes` arrays as follows:
|
||||
|
||||
```
|
||||
psci_non_cpu_pd_nodes -> [[Level 3 nodes][Level 2 nodes][Level 1 nodes]]
|
||||
psci_cpu_pd_nodes -> [Level 0 nodes]
|
||||
```
|
||||
|
||||
For the example power domain tree illustrated above, the `psci_cpu_pd_nodes`
|
||||
will be populated as follows. The value in each entry is the index of the parent
|
||||
node. Other fields have been ignored for simplicity.
|
||||
|
||||
```
|
||||
+-------------+ ^
|
||||
CPU0 | 3 | |
|
||||
+-------------+ |
|
||||
CPU1 | 3 | |
|
||||
+-------------+ |
|
||||
CPU2 | 3 | |
|
||||
+-------------+ |
|
||||
CPU3 | 4 | |
|
||||
+-------------+ |
|
||||
CPU4 | 4 | |
|
||||
+-------------+ |
|
||||
CPU5 | 4 | | PLATFORM_CORE_COUNT
|
||||
+-------------+ |
|
||||
CPU6 | 5 | |
|
||||
+-------------+ |
|
||||
CPU7 | 5 | |
|
||||
+-------------+ |
|
||||
CPU8 | 5 | |
|
||||
+-------------+ |
|
||||
CPU9 | 6 | |
|
||||
+-------------+ |
|
||||
CPU10 | 6 | |
|
||||
+-------------+ |
|
||||
CPU11 | 6 | |
|
||||
+-------------+ |
|
||||
CPU12 | 6 | v
|
||||
+-------------+
|
||||
```
|
||||
|
||||
The `psci_non_cpu_pd_nodes` array will be populated as follows. The value in
|
||||
each entry is the index of the parent node.
|
||||
|
||||
```
|
||||
+-------------+ ^
|
||||
PD0 | -1 | |
|
||||
+-------------+ |
|
||||
PD1 | 0 | |
|
||||
+-------------+ |
|
||||
PD2 | 0 | |
|
||||
+-------------+ |
|
||||
PD3 | 1 | | PLAT_NUM_POWER_DOMAINS -
|
||||
+-------------+ | PLATFORM_CORE_COUNT
|
||||
PD4 | 1 | |
|
||||
+-------------+ |
|
||||
PD5 | 2 | |
|
||||
+-------------+ |
|
||||
PD6 | 2 | |
|
||||
+-------------+ v
|
||||
```
|
||||
|
||||
Each core can find its node in the `psci_cpu_pd_nodes` array using the
|
||||
`plat_my_core_pos()` function. When a core is turned on, the normal world
|
||||
provides an MPIDR. The `plat_core_pos_by_mpidr()` function is used to validate
|
||||
the MPIDR before using it to find the corresponding core node. The non-core power
|
||||
domain nodes do not need to be identified.
|
||||
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
_Copyright (c) 2017, ARM Limited and Contributors. All rights reserved._
|
|
@ -1,172 +0,0 @@
|
|||
ARM Trusted Firmware Reset Design
|
||||
=================================
|
||||
|
||||
1. [Introduction](#1--introduction)
|
||||
2. [General reset code flow](#2--general-reset-code-flow)
|
||||
3. [Programmable CPU reset address](#3--programmable-cpu-reset-address)
|
||||
4. [Cold boot on a single CPU](#4--cold-boot-on-a-single-cpu)
|
||||
5. [Programmable CPU reset address, Cold boot on a single CPU](#5--programmable-cpu-reset-address-cold-boot-on-a-single-cpu)
|
||||
6. [Using BL31 entrypoint as the reset address](#6--using-bl31-entrypoint-as-the-reset-address)
|
||||
|
||||
|
||||
1. Introduction
|
||||
----------------
|
||||
|
||||
This document describes the high-level design of the framework to handle CPU
|
||||
resets in ARM Trusted Firmware. It also describes how the platform integrator
|
||||
can tailor this code to the system configuration to some extent, resulting in a
|
||||
simplified and more optimised boot flow.
|
||||
|
||||
This document should be used in conjunction with the [Firmware Design], which
|
||||
provides greater implementation details around the reset code, specifically
|
||||
for the cold boot path.
|
||||
|
||||
|
||||
2. General reset code flow
|
||||
---------------------------
|
||||
|
||||
The ARM Trusted Firmware (TF) reset code is implemented in BL1 by default. The
|
||||
following high-level diagram illustrates this:
|
||||
|
||||

|
||||
|
||||
This diagram shows the default, unoptimised reset flow. Depending on the system
|
||||
configuration, some of these steps might be unnecessary. The following sections
|
||||
guide the platform integrator by indicating which build options exclude which
|
||||
steps, depending on the capability of the platform.
|
||||
|
||||
Note: If BL31 is used as the Trusted Firmware entry point instead of BL1, the
|
||||
diagram above is still relevant, as all these operations will occur in BL31 in
|
||||
this case. Please refer to section 6 "Using BL31 entrypoint as the reset
|
||||
address" for more information.
|
||||
|
||||
|
||||
3. Programmable CPU reset address
|
||||
----------------------------------
|
||||
|
||||
By default, the TF assumes that the CPU reset address is not programmable.
|
||||
Therefore, all CPUs start at the same address (typically address 0) whenever
|
||||
they reset. Further logic is then required to identify whether it is a cold or
|
||||
warm boot to direct CPUs to the right execution path.
|
||||
|
||||
If the reset vector address (reflected in the reset vector base address register
|
||||
`RVBAR_EL3`) is programmable then it is possible to make each CPU start directly
|
||||
at the right address, both on a cold and warm reset. Therefore, the boot type
|
||||
detection can be skipped, resulting in the following boot flow:
|
||||
|
||||

|
||||
|
||||
To enable this boot flow, compile the TF with `PROGRAMMABLE_RESET_ADDRESS=1`.
|
||||
This option only affects the TF reset image, which is BL1 by default or BL31 if
|
||||
`RESET_TO_BL31=1`.
|
||||
|
||||
On both the FVP and Juno platforms, the reset vector address is not programmable
|
||||
so both ports use `PROGRAMMABLE_RESET_ADDRESS=0`.
|
||||
|
||||
|
||||
4. Cold boot on a single CPU
|
||||
-----------------------------
|
||||
|
||||
By default, the TF assumes that several CPUs may be released out of reset.
|
||||
Therefore, the cold boot code has to arbitrate access to hardware resources
|
||||
shared amongst CPUs. This is done by nominating one of the CPUs as the primary,
|
||||
which is responsible for initialising shared hardware and coordinating the boot
|
||||
flow with the other CPUs.
|
||||
|
||||
If the platform guarantees that only a single CPU will ever be brought up then
|
||||
no arbitration is required. The notion of primary/secondary CPU itself no longer
|
||||
applies. This results in the following boot flow:
|
||||
|
||||

|
||||
|
||||
To enable this boot flow, compile the TF with `COLD_BOOT_SINGLE_CPU=1`. This
|
||||
option only affects the TF reset image, which is BL1 by default or BL31 if
|
||||
`RESET_TO_BL31=1`.
|
||||
|
||||
On both the FVP and Juno platforms, although only one core is powered up by
|
||||
default, there are platform-specific ways to release any number of cores out of
|
||||
reset. Therefore, both platform ports use `COLD_BOOT_SINGLE_CPU=0`.
|
||||
|
||||
|
||||
5. Programmable CPU reset address, Cold boot on a single CPU
|
||||
-------------------------------------------------------------
|
||||
|
||||
It is obviously possible to combine both optimisations on platforms that have
|
||||
a programmable CPU reset address and which release a single CPU out of reset.
|
||||
This results in the following boot flow:
|
||||
|
||||

|
||||
|
||||
To enable this boot flow, compile the TF with both `COLD_BOOT_SINGLE_CPU=1`
|
||||
and `PROGRAMMABLE_RESET_ADDRESS=1`. These options only affect the TF reset
|
||||
image, which is BL1 by default or BL31 if `RESET_TO_BL31=1`.
|
||||
|
||||
|
||||
6. Using BL31 entrypoint as the reset address
|
||||
----------------------------------------------
|
||||
|
||||
On some platforms the runtime firmware (BL3x images) for the application
|
||||
processors are loaded by some firmware running on a secure system processor
|
||||
on the SoC, rather than by BL1 and BL2 running on the primary application
|
||||
processor. For this type of SoC it is desirable for the application processor
|
||||
to always reset to BL31 which eliminates the need for BL1 and BL2.
|
||||
|
||||
TF provides a build-time option `RESET_TO_BL31` that includes some additional
|
||||
logic in the BL31 entry point to support this use case.
|
||||
|
||||
In this configuration, the platform's Trusted Boot Firmware must ensure that
|
||||
BL31 is loaded to its runtime address, which must match the CPU's `RVBAR_EL3`
|
||||
reset vector base address, before the application processor is powered on.
|
||||
Additionally, platform software is responsible for loading the other BL3x images
|
||||
required and providing entry point information for them to BL31. Loading these
|
||||
images might be done by the Trusted Boot Firmware or by platform code in BL31.
|
||||
|
||||
Although the ARM FVP platform does not support programming the reset base
|
||||
address dynamically at run-time, it is possible to set the initial value of the
|
||||
`RVBAR_EL3` register at start-up. This feature is provided on the Base FVP only.
|
||||
It allows the ARM FVP port to support the `RESET_TO_BL31` configuration, in
|
||||
which case the `bl31.bin` image must be loaded to its run address in Trusted
|
||||
SRAM and all CPU reset vectors be changed from the default `0x0` to this run
|
||||
address. See the [User Guide] for details of running the FVP models in this way.
|
||||
|
||||
Although technically it would be possible to program the reset base address with
|
||||
the right support in the SCP firmware, this is currently not implemented so the
|
||||
Juno port doesn't support the `RESET_TO_BL31` configuration.
|
||||
|
||||
The `RESET_TO_BL31` configuration requires some additions and changes in the
|
||||
BL31 functionality:
|
||||
|
||||
#### Determination of boot path
|
||||
|
||||
In this configuration, BL31 uses the same reset framework and code as the one
|
||||
described for BL1 above. Therefore, it is affected by the
|
||||
`PROGRAMMABLE_RESET_ADDRESS` and `COLD_BOOT_SINGLE_CPU` build options in the
|
||||
same way.
|
||||
|
||||
In the default, unoptimised BL31 reset flow, on a warm boot a CPU is directed
|
||||
to the PSCI implementation via a platform defined mechanism. On a cold boot,
|
||||
the platform must place any secondary CPUs into a safe state while the primary
|
||||
CPU executes a modified BL31 initialization, as described below.
|
||||
|
||||
#### Platform initialization
|
||||
|
||||
In this configuration, when the CPU resets to BL31 there are no parameters that
|
||||
can be passed in registers by previous boot stages. Instead, the platform code
|
||||
in BL31 needs to know, or be able to determine, the location of the BL32 (if
|
||||
required) and BL33 images and provide this information in response to the
|
||||
`bl31_plat_get_next_image_ep_info()` function.
|
||||
|
||||
Additionally, platform software is responsible for carrying out any security
|
||||
initialisation, for example programming a TrustZone address space controller.
|
||||
This might be done by the Trusted Boot Firmware or by platform code in BL31.
|
||||
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
_Copyright (c) 2015, ARM Limited and Contributors. All rights reserved._
|
||||
|
||||
|
||||
[User Guide]: user-guide.md
|
||||
[Firmware Design]: firmware-design.md
|
|
@ -1,307 +0,0 @@
|
|||
EL3 Runtime Service Writers Guide for ARM Trusted Firmware
|
||||
==========================================================
|
||||
|
||||
Contents
|
||||
--------
|
||||
|
||||
1. [Introduction](#1--introduction)
|
||||
2. [Owning Entities, Call Types and Function IDs](#2--owning-entities-call-types-and-function-ids)
|
||||
3. [Getting started](#3--getting-started)
|
||||
4. [Registering a runtime service](#4--registering-a-runtime-service)
|
||||
5. [Initializing a runtime service](#5-initializing-a-runtime-service)
|
||||
6. [Handling runtime service requests](#6--handling-runtime-service-requests)
|
||||
7. [Services that contain multiple sub-services](#7--services-that-contain-multiple-sub-services)
|
||||
8. [Secure-EL1 Payload Dispatcher service (SPD)](#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 (BL31).
|
||||
|
||||
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 BL31 enables the
|
||||
independent implementation of services for each group, which are then compiled
|
||||
into the BL31 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 _Yielding_. Fast calls are
|
||||
uninterruptible whereas Yielding calls can be pre-empted. The majority of
|
||||
Owning Entities only have allocated ranges for Fast calls: Yielding 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
|
||||
|
||||
Yielding 0- 1 Reserved for existing ARMv7 calls
|
||||
Yielding 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 [`lib/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
|
||||
[`smcc.h`]
|
||||
|
||||
* `_type` must be one of `SMC_TYPE_FAST` or `SMC_TYPE_YIELD`
|
||||
|
||||
* `_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 uintptr_t (*rt_svc_handle_t)(uint32_t smc_fid,
|
||||
u_register_t x1, u_register_t x2,
|
||||
u_register_t x3, u_register_t x4,
|
||||
void *cookie,
|
||||
void *handle,
|
||||
u_register_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_YIELD`
|
||||
4. `_setup` and `_smch` routines have been specified
|
||||
|
||||
[`std_svc_setup.c`] provides an example of registering a runtime service:
|
||||
|
||||
/* Register Standard Service Calls as runtime service */
|
||||
DECLARE_RT_SVC(
|
||||
std_svc,
|
||||
OEN_STD_START,
|
||||
OEN_STD_END,
|
||||
SMC_TYPE_FAST,
|
||||
std_svc_setup,
|
||||
std_svc_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 uintptr_t (*rt_svc_handle_t)(uint32_t smc_fid,
|
||||
u_register_t x1, u_register_t x2,
|
||||
u_register_t x3, u_register_t x4,
|
||||
void *cookie,
|
||||
void *handle,
|
||||
u_register_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 `cookie` parameter to the handler is reserved for future use and can be
|
||||
ignored. The `handle` is returned by the SMC handler - 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 BL31 support for these services. Or a reference to the document that will
|
||||
provide this information....
|
||||
|
||||
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
_Copyright (c) 2014-2015, ARM Limited and Contributors. All rights reserved._
|
||||
|
||||
|
||||
[Firmware Design]: ./firmware-design.md
|
||||
[`services`]: ../services
|
||||
[`lib/psci`]: ../lib/psci
|
||||
[`std_svc_setup.c`]: ../services/std_svc/std_svc_setup.c
|
||||
[`runtime_svc.h`]: ../include/common/runtime_svc.h
|
||||
[`smcc.h`]: ../include/lib/smcc.h
|
||||
[PSCI]: http://infocenter.arm.com/help/topic/com.arm.doc.den0022c/DEN0022C_Power_State_Coordination_Interface.pdf "Power State Coordination Interface PDD (ARM DEN 0022C)"
|
||||
[SMCCC]: http://infocenter.arm.com/help/topic/com.arm.doc.den0028a/index.html "SMC Calling Convention PDD (ARM DEN 0028A)"
|
|
@ -1,13 +0,0 @@
|
|||
OP-TEE Dispatcher
|
||||
=================
|
||||
|
||||
[OP-TEE OS] is a Trusted OS running as Secure EL1.
|
||||
|
||||
To build and execute OP-TEE follow the instructions at
|
||||
[OP-TEE build.git][OP-TEE OS]
|
||||
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
_Copyright (c) 2014-2017, ARM Limited and Contributors. All rights reserved._
|
||||
|
||||
[OP-TEE OS]: https://github.com/OP-TEE/build
|
|
@ -1,70 +0,0 @@
|
|||
Trusted Little Kernel (TLK) Dispatcher
|
||||
=======================================
|
||||
TLK dispatcher adds support for NVIDIA's Trusted Little Kernel (TLK) to work
|
||||
with the Trusted Firmware. TLK-D can be compiled by including it in the
|
||||
platform's makefile. TLK is primarily meant to work with Tegra SoCs, so until
|
||||
Trusted Firmware starts supporting Tegra, the dispatcher code can only be
|
||||
compiled for other platforms.
|
||||
|
||||
In order to compile TLK-D, we need a BL32 image to be present. Since, TLKD
|
||||
just needs to compile, any BL32 image would do. To use TLK as the BL32, please
|
||||
refer to the "Build TLK" section.
|
||||
|
||||
Once a BL32 is ready, TLKD can be included in the image by adding "SPD=tlkd"
|
||||
to the build command.
|
||||
|
||||
Trusted Little Kernel (TLK)
|
||||
===========================
|
||||
TLK is a Trusted OS running as Secure EL1. It is a Free Open Source Software
|
||||
(FOSS) release of the NVIDIA® Trusted Little Kernel (TLK) technology, which
|
||||
extends technology made available with the development of the Little Kernel (LK).
|
||||
You can download the LK modular embedded preemptive kernel for use on ARM,
|
||||
x86, and AVR32 systems from https://github.com/travisg/lk
|
||||
|
||||
NVIDIA implemented its Trusted Little Kernel (TLK) technology, designed as a
|
||||
free and open-source trusted execution environment (OTE).
|
||||
|
||||
TLK features include:
|
||||
|
||||
• Small, pre-emptive kernel
|
||||
• Supports multi-threading, IPCs, and thread scheduling
|
||||
• Added TrustZone features
|
||||
• Added Secure Storage
|
||||
• Under MIT/FreeBSD license
|
||||
|
||||
NVIDIA extensions to Little Kernel (LK) include:
|
||||
|
||||
• User mode
|
||||
• Address-space separation for TAs
|
||||
• TLK Client Application (CA) library
|
||||
• TLK TA library
|
||||
• Crypto library (encrypt/decrypt, key handling) via OpenSSL
|
||||
• Linux kernel driver
|
||||
• Cortex A9/A15 support
|
||||
• Power Management
|
||||
• TrustZone memory carve-out (reconfigurable)
|
||||
• Page table management
|
||||
• Debugging support over UART (USB planned)
|
||||
|
||||
TLK is hosted by NVIDIA on http://nv-tegra.nvidia.com under the
|
||||
3rdparty/ote_partner/tlk.git repository. Detailed information about
|
||||
TLK and OTE can be found in the Tegra_BSP_for_Android_TLK_FOSS_Reference.pdf
|
||||
manual located under the "documentation" directory_.
|
||||
|
||||
Build TLK
|
||||
=========
|
||||
To build and execute TLK, follow the instructions from "Building a TLK Device"
|
||||
section from Tegra_BSP_for_Android_TLK_FOSS_Reference.pdf manual.
|
||||
|
||||
Input parameters to TLK
|
||||
=======================
|
||||
TLK expects the TZDRAM size and a structure containing the boot arguments. BL2
|
||||
passes this information to the EL3 software as members of the bl32_ep_info
|
||||
struct, where bl32_ep_info is part of bl31_params_t (passed by BL2 in X0)
|
||||
|
||||
Example:
|
||||
--------
|
||||
bl32_ep_info->args.arg0 = TZDRAM size available for BL32
|
||||
bl32_ep_info->args.arg1 = unused (used only on ARMv7)
|
||||
bl32_ep_info->args.arg2 = pointer to boot args
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
Trusty Dispatcher
|
||||
=================
|
||||
Trusty is a a set of software components, supporting a Trusted Execution
|
||||
Environment (TEE) on mobile devices, published and maintained by Google.
|
||||
|
||||
Detailed information and build instructions can be found on the Android
|
||||
Open Source Project (AOSP) webpage for Trusty hosted at
|
||||
https://source.android.com/security/trusty
|
||||
|
||||
Supported platforms
|
||||
===================
|
||||
Out of all the platforms supported by the ARM Trusted Firmware, Trusty is
|
||||
verified and supported by NVIDIA's Tegra SoCs.
|
||||
|
||||
|
|
@ -1,251 +0,0 @@
|
|||
Trusted Board Boot Design Guide
|
||||
===============================
|
||||
|
||||
Contents :
|
||||
|
||||
1. [Introduction](#1--introduction)
|
||||
2. [Chain of Trust](#2--chain-of-trust)
|
||||
3. [Trusted Board Boot Sequence](#3--trusted-board-boot-sequence)
|
||||
4. [Authentication Framework](#4--authentication-framework)
|
||||
5. [Certificate Generation Tool](#5--certificate-generation-tool)
|
||||
|
||||
|
||||
1. Introduction
|
||||
----------------
|
||||
|
||||
The Trusted Board Boot (TBB) feature prevents malicious firmware from running on
|
||||
the platform by authenticating all firmware images up to and including the
|
||||
normal world bootloader. It does this by establishing a Chain of Trust using
|
||||
Public-Key-Cryptography Standards (PKCS).
|
||||
|
||||
This document describes the design of ARM Trusted Firmware TBB, which is an
|
||||
implementation of the Trusted Board Boot Requirements (TBBR) specification,
|
||||
ARM DEN0006C-1. It should be used in conjunction with the [Firmware Update]
|
||||
design document, which implements a specific aspect of the TBBR.
|
||||
|
||||
|
||||
2. Chain of Trust
|
||||
------------------
|
||||
|
||||
A Chain of Trust (CoT) starts with a set of implicitly trusted components. On
|
||||
the ARM development platforms, these components are:
|
||||
|
||||
* A SHA-256 hash of the Root of Trust Public Key (ROTPK). It is stored in the
|
||||
trusted root-key storage registers.
|
||||
|
||||
* The BL1 image, on the assumption that it resides in ROM so cannot be
|
||||
tampered with.
|
||||
|
||||
The remaining components in the CoT are either certificates or boot loader
|
||||
images. The certificates follow the [X.509 v3] standard. This standard
|
||||
enables adding custom extensions to the certificates, which are used to store
|
||||
essential information to establish the CoT.
|
||||
|
||||
In the TBB CoT all certificates are self-signed. There is no need for a
|
||||
Certificate Authority (CA) because the CoT is not established by verifying the
|
||||
validity of a certificate's issuer but by the content of the certificate
|
||||
extensions. To sign the certificates, the PKCS#1 SHA-256 with RSA Encryption
|
||||
signature scheme is used with a RSA key length of 2048 bits. Future version of
|
||||
Trusted Firmware will support additional cryptographic algorithms.
|
||||
|
||||
The certificates are categorised as "Key" and "Content" certificates. Key
|
||||
certificates are used to verify public keys which have been used to sign content
|
||||
certificates. Content certificates are used to store the hash of a boot loader
|
||||
image. An image can be authenticated by calculating its hash and matching it
|
||||
with the hash extracted from the content certificate. The SHA-256 function is
|
||||
used to calculate all hashes. The public keys and hashes are included as
|
||||
non-standard extension fields in the [X.509 v3] certificates.
|
||||
|
||||
The keys used to establish the CoT are:
|
||||
|
||||
* **Root of trust key**
|
||||
|
||||
The private part of this key is used to sign the BL2 content certificate and
|
||||
the trusted key certificate. The public part is the ROTPK.
|
||||
|
||||
* **Trusted world key**
|
||||
|
||||
The private part is used to sign the key certificates corresponding to the
|
||||
secure world images (SCP_BL2, BL31 and BL32). The public part is stored in
|
||||
one of the extension fields in the trusted world certificate.
|
||||
|
||||
* **Non-trusted world key**
|
||||
|
||||
The private part is used to sign the key certificate corresponding to the
|
||||
non secure world image (BL33). The public part is stored in one of the
|
||||
extension fields in the trusted world certificate.
|
||||
|
||||
* **BL3-X keys**
|
||||
|
||||
For each of SCP_BL2, BL31, BL32 and BL33, the private part is used to
|
||||
sign the content certificate for the BL3-X image. The public part is stored
|
||||
in one of the extension fields in the corresponding key certificate.
|
||||
|
||||
The following images are included in the CoT:
|
||||
|
||||
* BL1
|
||||
* BL2
|
||||
* SCP_BL2 (optional)
|
||||
* BL31
|
||||
* BL33
|
||||
* BL32 (optional)
|
||||
|
||||
The following certificates are used to authenticate the images.
|
||||
|
||||
* **BL2 content certificate**
|
||||
|
||||
It is self-signed with the private part of the ROT key. It contains a hash
|
||||
of the BL2 image.
|
||||
|
||||
* **Trusted key certificate**
|
||||
|
||||
It is self-signed with the private part of the ROT key. It contains the
|
||||
public part of the trusted world key and the public part of the non-trusted
|
||||
world key.
|
||||
|
||||
* **SCP_BL2 key certificate**
|
||||
|
||||
It is self-signed with the trusted world key. It contains the public part of
|
||||
the SCP_BL2 key.
|
||||
|
||||
* **SCP_BL2 content certificate**
|
||||
|
||||
It is self-signed with the SCP_BL2 key. It contains a hash of the SCP_BL2
|
||||
image.
|
||||
|
||||
* **BL31 key certificate**
|
||||
|
||||
It is self-signed with the trusted world key. It contains the public part of
|
||||
the BL31 key.
|
||||
|
||||
* **BL31 content certificate**
|
||||
|
||||
It is self-signed with the BL31 key. It contains a hash of the BL31 image.
|
||||
|
||||
* **BL32 key certificate**
|
||||
|
||||
It is self-signed with the trusted world key. It contains the public part of
|
||||
the BL32 key.
|
||||
|
||||
* **BL32 content certificate**
|
||||
|
||||
It is self-signed with the BL32 key. It contains a hash of the BL32 image.
|
||||
|
||||
* **BL33 key certificate**
|
||||
|
||||
It is self-signed with the non-trusted world key. It contains the public
|
||||
part of the BL33 key.
|
||||
|
||||
* **BL33 content certificate**
|
||||
|
||||
It is self-signed with the BL33 key. It contains a hash of the BL33 image.
|
||||
|
||||
The SCP_BL2 and BL32 certificates are optional, but they must be present if the
|
||||
corresponding SCP_BL2 or BL32 images are present.
|
||||
|
||||
|
||||
3. Trusted Board Boot Sequence
|
||||
-------------------------------
|
||||
|
||||
The CoT is verified through the following sequence of steps. The system panics
|
||||
if any of the steps fail.
|
||||
|
||||
* BL1 loads and verifies the BL2 content certificate. The issuer public key is
|
||||
read from the verified certificate. A hash of that key is calculated and
|
||||
compared with the hash of the ROTPK read from the trusted root-key storage
|
||||
registers. If they match, the BL2 hash is read from the certificate.
|
||||
|
||||
Note: the matching operation is platform specific and is currently
|
||||
unimplemented on the ARM development platforms.
|
||||
|
||||
* BL1 loads the BL2 image. Its hash is calculated and compared with the hash
|
||||
read from the certificate. Control is transferred to the BL2 image if all
|
||||
the comparisons succeed.
|
||||
|
||||
* BL2 loads and verifies the trusted key certificate. The issuer public key is
|
||||
read from the verified certificate. A hash of that key is calculated and
|
||||
compared with the hash of the ROTPK read from the trusted root-key storage
|
||||
registers. If the comparison succeeds, BL2 reads and saves the trusted and
|
||||
non-trusted world public keys from the verified certificate.
|
||||
|
||||
The next two steps are executed for each of the SCP_BL2, BL31 & BL32 images.
|
||||
The steps for the optional SCP_BL2 and BL32 images are skipped if these images
|
||||
are not present.
|
||||
|
||||
* BL2 loads and verifies the BL3x key certificate. The certificate signature
|
||||
is verified using the trusted world public key. If the signature
|
||||
verification succeeds, BL2 reads and saves the BL3x public key from the
|
||||
certificate.
|
||||
|
||||
* BL2 loads and verifies the BL3x content certificate. The signature is
|
||||
verified using the BL3x public key. If the signature verification succeeds,
|
||||
BL2 reads and saves the BL3x image hash from the certificate.
|
||||
|
||||
The next two steps are executed only for the BL33 image.
|
||||
|
||||
* BL2 loads and verifies the BL33 key certificate. If the signature
|
||||
verification succeeds, BL2 reads and saves the BL33 public key from the
|
||||
certificate.
|
||||
|
||||
* BL2 loads and verifies the BL33 content certificate. If the signature
|
||||
verification succeeds, BL2 reads and saves the BL33 image hash from the
|
||||
certificate.
|
||||
|
||||
The next step is executed for all the boot loader images.
|
||||
|
||||
* BL2 calculates the hash of each image. It compares it with the hash obtained
|
||||
from the corresponding content certificate. The image authentication succeeds
|
||||
if the hashes match.
|
||||
|
||||
The Trusted Board Boot implementation spans both generic and platform-specific
|
||||
BL1 and BL2 code, and in tool code on the host build machine. The feature is
|
||||
enabled through use of specific build flags as described in the [User Guide].
|
||||
|
||||
On the host machine, a tool generates the certificates, which are included in
|
||||
the FIP along with the boot loader images. These certificates are loaded in
|
||||
Trusted SRAM using the IO storage framework. They are then verified by an
|
||||
Authentication module included in the Trusted Firmware.
|
||||
|
||||
The mechanism used for generating the FIP and the Authentication module are
|
||||
described in the following sections.
|
||||
|
||||
|
||||
4. Authentication Framework
|
||||
----------------------------
|
||||
|
||||
The authentication framework included in the Trusted Firmware provides support
|
||||
to implement the desired trusted boot sequence. ARM platforms use this framework
|
||||
to implement the boot requirements specified in the TBBR-client document.
|
||||
|
||||
More information about the authentication framework can be found in the
|
||||
[Auth Framework] document.
|
||||
|
||||
|
||||
5. Certificate Generation Tool
|
||||
-------------------------------
|
||||
|
||||
The `cert_create` tool is built and runs on the host machine as part of the
|
||||
Trusted Firmware build process when `GENERATE_COT=1`. It takes the boot loader
|
||||
images and keys as inputs (keys must be in PEM format) and generates the
|
||||
certificates (in DER format) required to establish the CoT. New keys can be
|
||||
generated by the tool in case they are not provided. The certificates are then
|
||||
passed as inputs to the `fiptool` utility for creating the FIP.
|
||||
|
||||
The certificates are also stored individually in the in the output build
|
||||
directory.
|
||||
|
||||
The tool resides in the `tools/cert_create` directory. It uses OpenSSL SSL
|
||||
library version 1.0.1 or later to generate the X.509 certificates. Instructions
|
||||
for building and using the tool can be found in the [User Guide].
|
||||
|
||||
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
_Copyright (c) 2015, ARM Limited and Contributors. All rights reserved._
|
||||
|
||||
|
||||
[X.509 v3]: http://www.ietf.org/rfc/rfc5280.txt
|
||||
[X.690]: http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf
|
||||
[Auth Framework]: auth-framework.md
|
||||
[User Guide]: user-guide.md
|
||||
[Firmware Update]: firmware-update.md
|
1600
docs/user-guide.md
1600
docs/user-guide.md
File diff suppressed because it is too large
Load diff
35
license.md
35
license.md
|
@ -1,35 +0,0 @@
|
|||
Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
* Neither the name of ARM nor the names of its contributors may be used to
|
||||
endorse or promote products derived from this software without specific prior
|
||||
written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
Note:
|
||||
Individual files contain the following tag instead of the full license text.
|
||||
|
||||
SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
This enables machine processing of license information based on the SPDX
|
||||
License Identifiers that are here available: http://spdx.org/licenses/
|
|
@ -1,84 +0,0 @@
|
|||
ARM Trusted Firmware Maintainers
|
||||
================================
|
||||
|
||||
ARM Trusted Firmware is an ARM maintained project. All contributions are
|
||||
ultimately merged by the maintainers listed below. Technical ownership of some
|
||||
parts of the codebase is delegated to the sub-maintainers listed below. An
|
||||
acknowledgement from these sub-maintainers may be required before the
|
||||
maintainers merge a contribution.
|
||||
|
||||
|
||||
## Maintainers
|
||||
|
||||
Dan Handley (dan.handley@arm.com, [danh-arm](https://github.com/danh-arm))
|
||||
|
||||
David Cunado (david.cunado@arm.com, [davidcunado-arm](https://github.com/davidcunado-arm))
|
||||
|
||||
|
||||
## OPTEE and QEMU platform sub-maintainer
|
||||
|
||||
Jens Wiklander (jens.wiklander@linaro.org, [jenswi-linaro](https://github.com/jenswi-linaro))
|
||||
|
||||
Files:
|
||||
* docs/spd/optee-dispatcher.md
|
||||
* docs/plat/qemu.md
|
||||
* services/spd/opteed/*
|
||||
* plat/qemu/*
|
||||
|
||||
|
||||
## TLK/Trusty SPDs and NVidia platforms sub-maintainer
|
||||
|
||||
Varun Wadekar (vwadekar@nvidia.com, [vwadekar](https://github.com/vwadekar))
|
||||
|
||||
Files:
|
||||
* docs/spd/tlk-dispatcher.md
|
||||
* docs/spd/trusty-dispatcher.md
|
||||
* include/bl32/payloads/tlk.h
|
||||
* include/lib/cpus/aarch64/denver.h
|
||||
* lib/cpus/aarch64/denver.S
|
||||
* services/spd/tlkd/*
|
||||
* services/spd/trusty/*
|
||||
* plat/nvidia/*
|
||||
|
||||
|
||||
## eMMC/UFS drivers and HiSilicon platform sub-maintainer
|
||||
|
||||
Haojian Zhuang (haojian.zhuang@linaro.org, [hzhuang1](https://github.com/hzhuang1))
|
||||
|
||||
Files:
|
||||
* docs/plat/hikey.md
|
||||
* docs/plat/hikey960.md
|
||||
* drivers/emmc/*
|
||||
* drivers/partition/*
|
||||
* drivers/synopsys/emmc/*
|
||||
* drivers/synopsys/ufs/*
|
||||
* drivers/ufs/*
|
||||
* include/drivers/dw_ufs.h
|
||||
* include/drivers/emmc.h
|
||||
* include/drivers/ufs.h
|
||||
* include/drivers/synopsys/dw_mmc.h
|
||||
* plat/hisilicon/*
|
||||
|
||||
|
||||
## MediaTek platform sub-maintainer
|
||||
|
||||
Yidi Lin (林以廸 yidi.lin@mediatek.com, [mtk09422](https://github.com/mtk09422))
|
||||
|
||||
Files:
|
||||
* plat/mediatek/*
|
||||
|
||||
|
||||
## RockChip platform sub-maintainer
|
||||
Tony Xie (tony.xie@rock-chips.com, [TonyXie06](https://github.com/TonyXie06)
|
||||
or [rkchrome](https://github.com/rkchrome))
|
||||
|
||||
Files:
|
||||
* plat/rockchip/*
|
||||
|
||||
|
||||
## Xilinx platform sub-maintainer
|
||||
Sören Brinkmann (soren.brinkmann@xilinx.com, [sorenb-xlnx](https://github.com/sorenb-xlnx))
|
||||
|
||||
Files:
|
||||
* docs/plat/xilinx-zynqmp.md
|
||||
* plat/xilinx/*
|
197
readme.md
197
readme.md
|
@ -1,197 +0,0 @@
|
|||
ARM Trusted Firmware - version 1.3
|
||||
==================================
|
||||
|
||||
ARM Trusted Firmware provides a reference implementation of secure world
|
||||
software for [ARMv8-A], including a [Secure Monitor] [TEE-SMC] executing at
|
||||
Exception Level 3 (EL3). It implements various ARM interface standards, such as
|
||||
the Power State Coordination Interface ([PSCI]), Trusted Board Boot Requirements
|
||||
(TBBR, ARM DEN0006C-1) and [SMC Calling Convention][SMCCC]. As far as possible
|
||||
the code is designed for reuse or porting to other ARMv8-A model and hardware
|
||||
platforms.
|
||||
|
||||
ARM will continue development in collaboration with interested parties to
|
||||
provide a full reference implementation of PSCI, TBBR and Secure Monitor code
|
||||
to the benefit of all developers working with ARMv8-A TrustZone technology.
|
||||
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
The software is provided under a BSD-3-Clause [license]. Contributions to this
|
||||
project are accepted under the same license with developer sign-off as
|
||||
described in the [Contributing Guidelines].
|
||||
|
||||
This project contains code from other projects as listed below. The original
|
||||
license text is included in those source files.
|
||||
|
||||
* The stdlib source code is derived from FreeBSD code.
|
||||
|
||||
* The libfdt source code is dual licensed. It is used by this project under
|
||||
the terms of the BSD-2-Clause license.
|
||||
|
||||
|
||||
This Release
|
||||
------------
|
||||
|
||||
This release provides a suitable starting point for productization of secure
|
||||
world boot and runtime firmware, executing in either the AArch32 or AArch64
|
||||
execution state.
|
||||
|
||||
Users are encouraged to do their own security validation, including penetration
|
||||
testing, on any secure world code derived from ARM Trusted Firmware.
|
||||
|
||||
### Functionality
|
||||
|
||||
* Initialization of the secure world (for example, exception vectors, control
|
||||
registers, interrupt controller and interrupts for the platform), before
|
||||
transitioning into the normal world at the Exception Level and Register
|
||||
Width specified by the platform.
|
||||
|
||||
* Library support for CPU specific reset and power down sequences. This
|
||||
includes support for errata workarounds.
|
||||
|
||||
* Drivers for both versions 2.0 and 3.0 of the ARM Generic Interrupt
|
||||
Controller specifications (GICv2 and GICv3). The latter also enables GICv3
|
||||
hardware systems that do not contain legacy GICv2 support.
|
||||
|
||||
* Drivers to enable standard initialization of ARM System IP, for example
|
||||
Cache Coherent Interconnect (CCI), Cache Coherent Network (CCN), Network
|
||||
Interconnect (NIC) and TrustZone Controller (TZC).
|
||||
|
||||
* SMC (Secure Monitor Call) handling, conforming to the [SMC Calling
|
||||
Convention][SMCCC] using an EL3 runtime services framework.
|
||||
|
||||
* [PSCI] library support for the Secondary CPU Boot, CPU Hotplug, CPU Idle
|
||||
and System Shutdown/Reset/Suspend use-cases.
|
||||
This library is pre-integrated with the provided AArch64 EL3 Runtime
|
||||
Software, and is also suitable for integration into other EL3 Runtime
|
||||
Software.
|
||||
|
||||
* A minimal AArch32 Secure Payload to demonstrate [PSCI] library integration
|
||||
on platforms with AArch32 EL3 Runtime Software.
|
||||
|
||||
* Secure Monitor library code such as world switching, EL1 context management
|
||||
and interrupt routing.
|
||||
When using the provided AArch64 EL3 Runtime Software, this must be
|
||||
integrated with a Secure-EL1 Payload Dispatcher (SPD) component to
|
||||
customize the interaction with a Secure-EL1 Payload (SP), for example a
|
||||
Secure OS.
|
||||
|
||||
* A Test Secure-EL1 Payload and Dispatcher to demonstrate AArch64 Secure
|
||||
Monitor functionality and Secure-EL1 interaction with PSCI.
|
||||
|
||||
* AArch64 SPDs for the [OP-TEE Secure OS] and [NVidia Trusted Little Kernel]
|
||||
[NVidia TLK].
|
||||
|
||||
* A Trusted Board Boot implementation, conforming to all mandatory TBBR
|
||||
requirements. This includes image authentication using certificates, a
|
||||
Firmware Update (or recovery mode) boot flow, and packaging of the various
|
||||
firmware images into a Firmware Image Package (FIP) to be loaded from
|
||||
non-volatile storage.
|
||||
The TBBR implementation is currently only supported in the AArch64 build.
|
||||
|
||||
* Support for alternative boot flows. Some platforms have their own boot
|
||||
firmware and only require the AArch64 EL3 Runtime Software provided by this
|
||||
project. Other platforms require minimal initialization before booting
|
||||
into an arbitrary EL3 payload.
|
||||
|
||||
For a full description of functionality and implementation details, please
|
||||
see the [Firmware Design] and supporting documentation. The [Change Log]
|
||||
provides details of changes made since the last release.
|
||||
|
||||
### Platforms
|
||||
|
||||
The AArch64 build of this release has been tested on variants r0, r1 and r2
|
||||
of the [Juno ARM Development Platform] [Juno] with [Linaro Release 16.06].
|
||||
|
||||
The AArch64 build of this release has been tested on the following ARM
|
||||
[FVP]s (64-bit host machine only, with [Linaro Release 16.06]):
|
||||
|
||||
* `Foundation_Platform` (Version 10.1, Build 10.1.32)
|
||||
* `FVP_Base_AEMv8A-AEMv8A` (Version 7.7, Build 0.8.7701)
|
||||
* `FVP_Base_Cortex-A57x4-A53x4` (Version 7.7, Build 0.8.7701)
|
||||
* `FVP_Base_Cortex-A57x1-A53x1` (Version 7.7, Build 0.8.7701)
|
||||
* `FVP_Base_Cortex-A57x2-A53x4` (Version 7.7, Build 0.8.7701)
|
||||
|
||||
The AArch32 build of this release has been tested on the following ARM
|
||||
[FVP]s (64-bit host machine only, with [Linaro Release 16.06]):
|
||||
|
||||
* `FVP_Base_AEMv8A-AEMv8A` (Version 7.7, Build 0.8.7701)
|
||||
* `FVP_Base_Cortex-A32x4` (Version 10.1, Build 10.1.32)
|
||||
|
||||
The Foundation FVP can be downloaded free of charge. The Base FVPs can be
|
||||
licensed from ARM: see [www.arm.com/fvp] [FVP].
|
||||
|
||||
This release also contains the following platform support:
|
||||
|
||||
* MediaTek MT6795 and MT8173 SoCs
|
||||
* NVidia T210 and T132 SoCs
|
||||
* QEMU emulator
|
||||
* RockChip RK3368 and RK3399 SoCs
|
||||
* Xilinx Zynq UltraScale + MPSoC
|
||||
|
||||
### Still to Come
|
||||
|
||||
* AArch32 TBBR support and ongoing TBBR alignment.
|
||||
|
||||
* More platform support.
|
||||
|
||||
* Ongoing support for new architectural features, CPUs and System IP.
|
||||
|
||||
* Ongoing [PSCI] alignment and feature support.
|
||||
|
||||
* Ongoing security hardening, optimization and quality improvements.
|
||||
|
||||
For a full list of detailed issues in the current code, please see the [Change
|
||||
Log] and the [GitHub issue tracker].
|
||||
|
||||
|
||||
Getting Started
|
||||
---------------
|
||||
|
||||
Get the Trusted Firmware source code from
|
||||
[GitHub](https://www.github.com/ARM-software/arm-trusted-firmware).
|
||||
|
||||
See the [User Guide] for instructions on how to install, build and use
|
||||
the Trusted Firmware with the ARM [FVP]s.
|
||||
|
||||
See the [Firmware Design] for information on how the ARM Trusted Firmware works.
|
||||
|
||||
See the [Porting Guide] as well for information about how to use this
|
||||
software on another ARMv8-A platform.
|
||||
|
||||
See the [Contributing Guidelines] for information on how to contribute to this
|
||||
project and the [Acknowledgments] file for a list of contributors to the
|
||||
project.
|
||||
|
||||
### Feedback and support
|
||||
|
||||
ARM welcomes any feedback on the Trusted Firmware. Please send feedback using
|
||||
the [GitHub issue tracker].
|
||||
|
||||
ARM licensees may contact ARM directly via their partner managers.
|
||||
|
||||
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
_Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved._
|
||||
|
||||
|
||||
[License]: ./license.md "BSD license for ARM Trusted Firmware"
|
||||
[Contributing Guidelines]: ./contributing.md "Guidelines for contributors"
|
||||
[Acknowledgments]: ./acknowledgements.md "Contributor acknowledgments"
|
||||
[Change Log]: ./docs/change-log.md
|
||||
[User Guide]: ./docs/user-guide.md
|
||||
[Firmware Design]: ./docs/firmware-design.md
|
||||
[Porting Guide]: ./docs/porting-guide.md
|
||||
|
||||
[ARMv8-A]: http://www.arm.com/products/processors/armv8-architecture.php "ARMv8-A Architecture"
|
||||
[FVP]: http://www.arm.com/fvp "ARM's Fixed Virtual Platforms"
|
||||
[Juno]: http://www.arm.com/products/tools/development-boards/versatile-express/juno-arm-development-platform.php "Juno ARM Development Platform"
|
||||
[PSCI]: http://infocenter.arm.com/help/topic/com.arm.doc.den0022c/DEN0022C_Power_State_Coordination_Interface.pdf "Power State Coordination Interface PDD (ARM DEN 0022C)"
|
||||
[SMCCC]: http://infocenter.arm.com/help/topic/com.arm.doc.den0028a/index.html "SMC Calling Convention PDD (ARM DEN 0028A)"
|
||||
[TEE-SMC]: http://www.arm.com/products/processors/technologies/trustzone/tee-smc.php "Secure Monitor and TEEs"
|
||||
[GitHub issue tracker]: https://github.com/ARM-software/tf-issues/issues
|
||||
[OP-TEE Secure OS]: https://github.com/OP-TEE/optee_os
|
||||
[NVidia TLK]: http://nv-tegra.nvidia.com/gitweb/?p=3rdparty/ote_partner/tlk.git;a=summary
|
||||
[Linaro Release 16.06]: https://community.arm.com/docs/DOC-10952#jive_content_id_Linaro_Release_1606
|
Loading…
Add table
Reference in a new issue