diff options
author | Ferass El Hafidi <vitali64pmemail@protonmail.com> | 2023-05-08 19:03:10 +0200 |
---|---|---|
committer | Ferass El Hafidi <vitali64pmemail@protonmail.com> | 2023-05-08 19:03:10 +0200 |
commit | f9ed707f171c8069e99e24e24c3da73d8b6f5716 (patch) | |
tree | 4da9838d387c8bc260e83f3f51f5dfa83e0b48ae /docs | |
download | amlogic-bl2-master.tar.gz |
Diffstat (limited to 'docs')
-rw-r--r-- | docs/change-log.md | 361 | ||||
-rw-r--r-- | docs/diagrams/non-sec-int-handling.png | bin | 0 -> 249672 bytes | |||
-rw-r--r-- | docs/diagrams/rt-svc-descs-layout.png | bin | 0 -> 77894 bytes | |||
-rw-r--r-- | docs/diagrams/sec-int-handling.png | bin | 0 -> 191026 bytes | |||
-rw-r--r-- | docs/firmware-design.md | 1313 | ||||
-rw-r--r-- | docs/interrupt-framework-design.md | 848 | ||||
-rw-r--r-- | docs/porting-guide.md | 1372 | ||||
-rw-r--r-- | docs/rt-svc-writers-guide.md | 309 | ||||
-rw-r--r-- | docs/user-guide.md | 841 |
9 files changed, 5044 insertions, 0 deletions
diff --git a/docs/change-log.md b/docs/change-log.md new file mode 100644 index 0000000..c7ad084 --- /dev/null +++ b/docs/change-log.md @@ -0,0 +1,361 @@ +ARM Trusted Firmware - version 0.4 +================================== + +New features +------------ + +* Makefile improvements: + + * Improved dependency checking when building. + + * Removed `dump` target (build now always produces dump files). + + * Enabled platform ports to optionally make use of parts of the Trusted + Firmware (e.g. BL3-1 only), rather than being forced to use all parts. + Also made the `fip` target optional. + + * Specified the full path to source files and removed use of the `vpath` + keyword. + +* Provided translation table library code for potential re-use by platforms + other than the FVPs. + +* Moved architectural timer setup to platform-specific code. + +* Added standby state support to PSCI cpu_suspend implementation. + +* SRAM usage improvements: + + * Started using the `-ffunction-sections`, `-fdata-sections` and + `--gc-sections` compiler/linker options to remove unused code and data + from the images. Previously, all common functions were being built into + all binary images, whether or not they were actually used. + + * Placed all assembler functions in their own section to allow more unused + functions to be removed from images. + + * Updated BL1 and BL2 to use a single coherent stack each, rather than one + per CPU. + + * Changed variables that were unnecessarily declared and initialized as + non-const (i.e. in the .data section) so they are either uninitialized + (zero init) or const. + +* Moved the Test Secure-EL1 Payload (BL3-2) to execute in Trusted SRAM by + default. The option for it to run in Trusted DRAM remains. + +* Implemented a TrustZone Address Space Controller (TZC-400) driver. A + default configuration is provided for the Base FVPs. This means the model + parameter `-C bp.secure_memory=1` is now supported. + +* Started saving the PSCI cpu_suspend 'power_state' parameter prior to + suspending a CPU. This allows platforms that implement multiple power-down + states at the same affinity level to identify a specific state. + +* Refactored the entire codebase to reduce the amount of nesting in header + files and to make the use of system/user includes more consistent. Also + split platform.h to separate out the platform porting declarations from the + required platform porting definitions and the definitions/declarations + specific to the platform port. + +* Optimized the data cache clean/invalidate operations. + +* Improved the BL3-1 unhandled exception handling and reporting. Unhandled + exceptions now result in a dump of registers to the console. + +* Major rework to the handover interface between BL stages, in particular the + interface to BL3-1. The interface now conforms to a specification and is + more future proof. + +* Added support for optionally making the BL3-1 entrypoint a reset handler + (instead of BL1). This allows platforms with an alternative image loading + architecture to re-use BL3-1 with fewer modifications to generic code. + +* Reserved some DDR DRAM for secure use on FVP platforms to avoid future + compatibility problems with non-secure software. + +* Added support for secure interrupts targeting the Secure-EL1 Payload (SP) + (using GICv2 routing only). Demonstrated this working by adding an interrupt + target and supporting test code to the TSP. Also demonstrated non-secure + interrupt handling during TSP processing. + + +Issues resolved since last release +---------------------------------- + +* Now support use of the model parameter `-C bp.secure_memory=1` in the Base + FVPs (see **New features**). + +* Support for secure world interrupt handling now available (see **New + features**). + +* Made enough SRAM savings (see **New features**) to enable the Test Secure-EL1 + Payload (BL3-2) to execute in Trusted SRAM by default. + +* The tested filesystem used for this release (Linaro AArch64 OpenEmbedded + 14.04) now correctly reports progress in the console. + +* Improved the Makefile structure to make it easier to separate out parts of + the Trusted Firmware for re-use in platform ports. Also, improved target + dependency checking. + + +Known issues +------------ + +* GICv3 support is experimental. The Linux kernel patches to support this are + not widely available. There are known issues with GICv3 initialization in + the ARM Trusted Firmware. + +* Dynamic image loading is not available yet. The current image loader + implementation (used to load BL2 and all subsequent images) has some + limitations. Changing BL2 or BL3-1 load addresses in certain ways can lead + to loading errors, even if the images should theoretically fit in memory. + +* The ARM Trusted Firmware still uses too much on-chip Trusted SRAM. A number + of RAM usage enhancements have been identified to rectify this situation. + +* CPU idle does not work on the advertised version of the Foundation FVP. + Some FVP fixes are required that are not available externally at the time + of writing. This can be worked around by disabling CPU idle in the Linux + kernel. + +* Various bugs in ARM Trusted Firmware, UEFI and the Linux kernel have been + observed when using Linaro toolchain versions later than 13.11. Although + most of these have been fixed, some remain at the time of writing. These + mainly seem to relate to a subtle change in the way the compiler converts + between 64-bit and 32-bit values (e.g. during casting operations), which + reveals previously hidden bugs in client code. + +* The firmware design documentation for the Test Secure-EL1 Payload (TSP) and + its dispatcher (TSPD) is incomplete. Similarly for the PSCI section. + + +ARM Trusted Firmware - version 0.3 +================================== + +New features +------------ + +* Support for Foundation FVP Version 2.0 added. + The documented UEFI configuration disables some devices that are unavailable + in the Foundation FVP, including MMC and CLCD. The resultant UEFI binary can + be used on the AEMv8 and Cortex-A57-A53 Base FVPs, as well as the Foundation + FVP. + + NOTE: The software will not work on Version 1.0 of the Foundation FVP. + +* Enabled third party contributions. Added a new contributing.md containing + instructions for how to contribute and updated copyright text in all files + to acknowledge contributors. + +* The PSCI CPU_SUSPEND API has been stabilised to the extent where it can be + used for entry into power down states with the following restrictions: + - Entry into standby states is not supported. + - The API is only supported on the AEMv8 and Cortex-A57-A53 Base FVPs. + +* The PSCI AFFINITY_INFO api has undergone limited testing on the Base FVPs to + allow experimental use. + +* Required C library and runtime header files are now included locally in ARM + Trusted Firmware instead of depending on the toolchain standard include + paths. The local implementation has been cleaned up and reduced in scope. + +* Added I/O abstraction framework, primarily to allow generic code to load + images in a platform-independent way. The existing image loading code has + been reworked to use the new framework. Semi-hosting and NOR flash I/O + drivers are provided. + +* Introduced Firmware Image Package (FIP) handling code and tools. A FIP + combines multiple firmware images with a Table of Contents (ToC) into a + single binary image. The new FIP driver is another type of I/O driver. The + Makefile builds a FIP by default and the FVP platform code expect to load a + FIP from NOR flash, although some support for image loading using semi- + hosting is retained. + + NOTE: Building a FIP by default is a non-backwards-compatible change. + + NOTE: Generic BL2 code now loads a BL3-3 (non-trusted firmware) image into + DRAM instead of expecting this to be pre-loaded at known location. This is + also a non-backwards-compatible change. + + NOTE: Some non-trusted firmware (e.g. UEFI) will need to be rebuilt so that + it knows the new location to execute from and no longer needs to copy + particular code modules to DRAM itself. + +* Reworked BL2 to BL3-1 handover interface. A new composite structure + (bl31_args) holds the superset of information that needs to be passed from + BL2 to BL3-1, including information on how handover execution control to + BL3-2 (if present) and BL3-3 (non-trusted firmware). + +* Added library support for CPU context management, allowing the saving and + restoring of + - Shared system registers between Secure-EL1 and EL1. + - VFP registers. + - Essential EL3 system registers. + +* Added a framework for implementing EL3 runtime services. Reworked the PSCI + implementation to be one such runtime service. + +* Reworked the exception handling logic, making use of both SP_EL0 and SP_EL3 + stack pointers for determining the type of exception, managing general + purpose and system register context on exception entry/exit, and handling + SMCs. SMCs are directed to the correct EL3 runtime service. + +* Added support for a Test Secure-EL1 Payload (TSP) and a corresponding + Dispatcher (TSPD), which is loaded as an EL3 runtime service. The TSPD + implements Secure Monitor functionality such as world switching and + EL1 context management, and is responsible for communication with the TSP. + NOTE: The TSPD does not yet contain support for secure world interrupts. + NOTE: The TSP/TSPD is not built by default. + + +Issues resolved since last release +---------------------------------- + +* Support has been added for switching context between secure and normal + worlds in EL3. + +* PSCI API calls `AFFINITY_INFO` & `PSCI_VERSION` have now been tested (to + a limited extent). + +* The ARM Trusted Firmware build artifacts are now placed in the `./build` + directory and sub-directories instead of being placed in the root of the + project. + +* The ARM Trusted Firmware is now free from build warnings. Build warnings + are now treated as errors. + +* The ARM Trusted Firmware now provides C library support locally within the + project to maintain compatibility between toolchains/systems. + +* The PSCI locking code has been reworked so it no longer takes locks in an + incorrect sequence. + +* The RAM-disk method of loading a Linux file-system has been confirmed to + work with the ARM Trusted Firmware and Linux kernel version (based on + version 3.13) used in this release, for both Foundation and Base FVPs. + + +Known issues +------------ + +The following is a list of issues which are expected to be fixed in the future +releases of the ARM Trusted Firmware. + +* The TrustZone Address Space Controller (TZC-400) is not being programmed + yet. Use of model parameter `-C bp.secure_memory=1` is not supported. + +* No support yet for secure world interrupt handling. + +* GICv3 support is experimental. The Linux kernel patches to support this are + not widely available. There are known issues with GICv3 initialization in + the ARM Trusted Firmware. + +* Dynamic image loading is not available yet. The current image loader + implementation (used to load BL2 and all subsequent images) has some + limitations. Changing BL2 or BL3-1 load addresses in certain ways can lead + to loading errors, even if the images should theoretically fit in memory. + +* The ARM Trusted Firmware uses too much on-chip Trusted SRAM. Currently the + Test Secure-EL1 Payload (BL3-2) executes in Trusted DRAM since there is not + enough SRAM. A number of RAM usage enhancements have been identified to + rectify this situation. + +* CPU idle does not work on the advertised version of the Foundation FVP. + Some FVP fixes are required that are not available externally at the time + of writing. + +* Various bugs in ARM Trusted Firmware, UEFI and the Linux kernel have been + observed when using Linaro toolchain versions later than 13.11. Although + most of these have been fixed, some remain at the time of writing. These + mainly seem to relate to a subtle change in the way the compiler converts + between 64-bit and 32-bit values (e.g. during casting operations), which + reveals previously hidden bugs in client code. + +* The tested filesystem used for this release (Linaro AArch64 OpenEmbedded + 14.01) does not report progress correctly in the console. It only seems to + produce error output, not standard output. It otherwise appears to function + correctly. Other filesystem versions on the same software stack do not + exhibit the problem. + +* The Makefile structure doesn't make it easy to separate out parts of the + Trusted Firmware for re-use in platform ports, for example if only BL3-1 is + required in a platform port. Also, dependency checking in the Makefile is + flawed. + +* The firmware design documentation for the Test Secure-EL1 Payload (TSP) and + its dispatcher (TSPD) is incomplete. Similarly for the PSCI section. + + +ARM Trusted Firmware - version 0.2 +================================== + +New features +------------ + +* First source release. + +* Code for the PSCI suspend feature is supplied, although this is not enabled + by default since there are known issues (see below). + + +Issues resolved since last release +---------------------------------- + +* The "psci" nodes in the FDTs provided in this release now fully comply + with the recommendations made in the PSCI specification. + + +Known issues +------------ + +The following is a list of issues which are expected to be fixed in the future +releases of the ARM Trusted Firmware. + +* The TrustZone Address Space Controller (TZC-400) is not being programmed + yet. Use of model parameter `-C bp.secure_memory=1` is not supported. + +* No support yet for secure world interrupt handling or for switching context + between secure and normal worlds in EL3. + +* GICv3 support is experimental. The Linux kernel patches to support this are + not widely available. There are known issues with GICv3 initialization in + the ARM Trusted Firmware. + +* Dynamic image loading is not available yet. The current image loader + implementation (used to load BL2 and all subsequent images) has some + limitations. Changing BL2 or BL3-1 load addresses in certain ways can lead + to loading errors, even if the images should theoretically fit in memory. + +* Although support for PSCI `CPU_SUSPEND` is present, it is not yet stable + and ready for use. + +* PSCI API calls `AFFINITY_INFO` & `PSCI_VERSION` are implemented but have not + been tested. + +* The ARM Trusted Firmware make files result in all build artifacts being + placed in the root of the project. These should be placed in appropriate + sub-directories. + +* The compilation of ARM Trusted Firmware is not free from compilation + warnings. Some of these warnings have not been investigated yet so they + could mask real bugs. + +* The ARM Trusted Firmware currently uses toolchain/system include files like + stdio.h. It should provide versions of these within the project to maintain + compatibility between toolchains/systems. + +* The PSCI code takes some locks in an incorrect sequence. This may cause + problems with suspend and hotplug in certain conditions. + +* The Linux kernel used in this release is based on version 3.12-rc4. Using + this kernel with the ARM Trusted Firmware fails to start the file-system as + a RAM-disk. It fails to execute user-space `init` from the RAM-disk. As an + alternative, the VirtioBlock mechanism can be used to provide a file-system + to the kernel. + + +- - - - - - - - - - - - - - - - - - - - - - - - - - + +_Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved._ diff --git a/docs/diagrams/non-sec-int-handling.png b/docs/diagrams/non-sec-int-handling.png Binary files differnew file mode 100644 index 0000000..1a5f629 --- /dev/null +++ b/docs/diagrams/non-sec-int-handling.png diff --git a/docs/diagrams/rt-svc-descs-layout.png b/docs/diagrams/rt-svc-descs-layout.png Binary files differnew file mode 100644 index 0000000..1a9fa5b --- /dev/null +++ b/docs/diagrams/rt-svc-descs-layout.png diff --git a/docs/diagrams/sec-int-handling.png b/docs/diagrams/sec-int-handling.png Binary files differnew file mode 100644 index 0000000..2ebbca4 --- /dev/null +++ b/docs/diagrams/sec-int-handling.png diff --git a/docs/firmware-design.md b/docs/firmware-design.md new file mode 100644 index 0000000..1700007 --- /dev/null +++ b/docs/firmware-design.md @@ -0,0 +1,1313 @@ +ARM Trusted Firmware Design +=========================== + +Contents : + +1. Introduction +2. Cold boot +3. EL3 runtime services framework +4. Power State Coordination Interface +5. Secure-EL1 Payloads and Dispatchers +6. Crash Reporting in BL3-1 +7. Memory layout on FVP platforms +8. Firmware Image Package (FIP) +9. Code Structure +10. References + + +1. Introduction +---------------- + +The ARM Trusted Firmware implements a subset of the Trusted Board Boot +Requirements (TBBR) Platform Design Document (PDD) [1] for ARM reference +platforms. The TBB sequence starts when the platform is powered on and runs up +to the stage where it hands-off control to firmware running in the normal +world in DRAM. This is the cold boot path. + +The ARM Trusted Firmware also implements the Power State Coordination Interface +([PSCI]) PDD [2] as a runtime service. PSCI is the interface from normal world +software to firmware implementing power management use-cases (for example, +secondary CPU boot, hotplug and idle). Normal world software can access ARM +Trusted Firmware runtime services via the ARM SMC (Secure Monitor Call) +instruction. The SMC instruction must be used as mandated by the [SMC Calling +Convention PDD][SMCCC] [3]. + +The ARM Trusted Firmware implements a framework for configuring and managing +interrupts generated in either security state. The details of the interrupt +management framework and its design can be found in [ARM Trusted +Firmware Interrupt Management Design guide][INTRG] [4]. + +2. Cold boot +------------- + +The cold boot path starts when the platform is physically turned on. One of +the CPUs released from reset is chosen as the primary CPU, and the remaining +CPUs are considered secondary CPUs. The primary CPU is chosen through +platform-specific means. The cold boot path is mainly executed by the primary +CPU, other than essential CPU initialization executed by all CPUs. The +secondary CPUs are kept in a safe platform-specific state until the primary +CPU has performed enough initialization to boot them. + +The cold boot path in this implementation of the ARM Trusted Firmware is divided +into five steps (in order of execution): + +* Boot Loader stage 1 (BL1) _AP Trusted ROM_ +* Boot Loader stage 2 (BL2) _Trusted Boot Firmware_ +* Boot Loader stage 3-1 (BL3-1) _EL3 Runtime Firmware_ +* Boot Loader stage 3-2 (BL3-2) _Secure-EL1 Payload_ (optional) +* Boot Loader stage 3-3 (BL3-3) _Non-trusted Firmware_ + +The ARM Fixed Virtual Platforms (FVPs) provide trusted ROM, trusted SRAM and +trusted DRAM regions. Each boot loader stage uses one or more of these +memories for its code and data. + +The sections below provide the following details: + +* initialization and execution of the first three stages during cold boot +* specification of the BL3-1 entrypoint requirements for use by alternative + Trusted Boot Firmware in place of the provided BL1 and BL2 +* changes in BL3-1 behavior when using the `RESET_TO_BL31` option which + allows BL3-1 to run without BL1 and BL2 + + +### BL1 + +This stage begins execution from the platform's reset vector in trusted ROM at +EL3. BL1 code starts at `0x00000000` (trusted ROM) in the FVP memory map. The +BL1 data section is placed at the start of trusted SRAM, `0x04000000`. The +functionality implemented by this stage is as follows. + +#### Determination of boot path + +Whenever a CPU is released from reset, BL1 needs to distinguish between a warm +boot and a cold boot. This is done using a platform-specific mechanism. The +ARM FVPs implement a simple power controller at `0x1c100000`. The `PSYS` +register (`0x10`) is used to distinguish between a cold and warm boot. This +information is contained in the `PSYS.WK[25:24]` field. Additionally, a +per-CPU mailbox is maintained in trusted DRAM (`0x00600000`), to which BL1 +writes an entrypoint. Each CPU jumps to this entrypoint upon warm boot. During +cold boot, BL1 places the secondary CPUs in a safe platform-specific state while +the primary CPU executes the remaining cold boot path as described in the +following sections. + +#### Architectural initialization + +BL1 performs minimal architectural initialization as follows. + +* Exception vectors + + BL1 sets up simple exception vectors for both synchronous and asynchronous + exceptions. The default behavior upon receiving an exception is to set a + status code. In the case of the FVP this code is written to the Versatile + Express System LED register in the following format: + + SYS_LED[0] - Security state (Secure=0/Non-Secure=1) + SYS_LED[2:1] - Exception Level (EL3=0x3, EL2=0x2, EL1=0x1, EL0=0x0) + SYS_LED[7:3] - Exception Class (Sync/Async & origin). The values for + each exception class are: + + 0x0 : Synchronous exception from Current EL with SP_EL0 + 0x1 : IRQ exception from Current EL with SP_EL0 + 0x2 : FIQ exception from Current EL with SP_EL0 + 0x3 : System Error exception from Current EL with SP_EL0 + 0x4 : Synchronous exception from Current EL with SP_ELx + 0x5 : IRQ exception from Current EL with SP_ELx + 0x6 : FIQ exception from Current EL with SP_ELx + 0x7 : System Error exception from Current EL with SP_ELx + 0x8 : Synchronous exception from Lower EL using aarch64 + 0x9 : IRQ exception from Lower EL using aarch64 + 0xa : FIQ exception from Lower EL using aarch64 + 0xb : System Error exception from Lower EL using aarch64 + 0xc : Synchronous exception from Lower EL using aarch32 + 0xd : IRQ exception from Lower EL using aarch32 + 0xe : FIQ exception from Lower EL using aarch32 + 0xf : System Error exception from Lower EL using aarch32 + + A write to the LED register reflects in the System LEDs (S6LED0..7) in the + CLCD window of the FVP. This behavior is because this boot loader stage + does not expect to receive any exceptions other than the SMC exception. + For the latter, BL1 installs a simple stub. The stub expects to receive + only a single type of SMC (determined by its function ID in the general + purpose register `X0`). This SMC is raised by BL2 to make BL1 pass control + to BL3-1 (loaded by BL2) at EL3. Any other SMC leads to an assertion + failure. + +* MMU setup + + BL1 sets up EL3 memory translation by creating page tables to cover the + first 4GB of physical address space. This covers all the memories and + peripherals needed by BL1. + +* Control register setup + - `SCTLR_EL3`. Instruction cache is enabled by setting the `SCTLR_EL3.I` + bit. Alignment and stack alignment checking is enabled by setting the + `SCTLR_EL3.A` and `SCTLR_EL3.SA` bits. Exception endianness is set to + little-endian by clearing the `SCTLR_EL3.EE` bit. + + - `CPUECTLR`. When the FVP includes a model of a specific ARM processor + implementation (for example A57 or A53), then intra-cluster coherency is + enabled by setting the `CPUECTLR.SMPEN` bit. The AEMv8 Base FVP is + inherently coherent so does not implement `CPUECTLR`. + + - `SCR`. Use of the HVC instruction from EL1 is enabled by setting the + `SCR.HCE` bit. FIQ exceptions are configured to be taken in EL3 by + setting the `SCR.FIQ` bit. The register width of the next lower + exception level is set to AArch64 by setting the `SCR.RW` bit. + + - `CPTR_EL3`. Accesses to the `CPACR_EL1` register from EL1 or EL2, or the + `CPTR_EL2` register from EL2 are configured to not trap to EL3 by + clearing the `CPTR_EL3.TCPAC` bit. Access to the trace functionality is + configured not to trap to EL3 by clearing the `CPTR_EL3.TTA` bit. + Instructions that access the registers associated with Floating Point + and Advanced SIMD execution are configured to not trap to EL3 by + clearing the `CPTR_EL3.TFP` bit. + +#### Platform initialization + +BL1 enables issuing of snoop and DVM (Distributed Virtual Memory) requests from +the CCI-400 slave interface corresponding to the cluster that includes the +primary CPU. BL1 also initializes UART0 (PL011 console), which enables access to +the `printf` family of functions in BL1. + +#### BL2 image load and execution + +BL1 execution continues as follows: + +1. BL1 determines the amount of free trusted SRAM memory available by + calculating the extent of its own data section, which also resides in + trusted SRAM. BL1 loads a BL2 raw binary image from platform storage, at a + platform-specific base address. If the BL2 image file is not present or if + there is not enough free trusted SRAM the following error message is + printed: + + "Failed to load boot loader stage 2 (BL2) firmware." + + If the load is successful, BL1 updates the limits of the remaining free + trusted SRAM. It also populates information about the amount of trusted + SRAM used by the BL2 image. The exact load location of the image is + provided as a base address in the platform header. Further description of + the memory layout can be found later in this document. + +2. BL1 prints the following string from the primary CPU to indicate successful + execution of the BL1 stage: + + "Booting trusted firmware boot loader stage 1" + +3. BL1 passes control to the BL2 image at Secure EL1, starting from its load + address. + +4. BL1 also passes information about the amount of trusted SRAM used and + available for use. This information is populated at a platform-specific + memory address. + + +### BL2 + +BL1 loads and passes control to BL2 at Secure-EL1. BL2 is linked against and +loaded at a platform-specific base address (more information can be found later +in this document). The functionality implemented by BL2 is as follows. + +#### Architectural initialization + +BL2 performs minimal architectural initialization required for subsequent +stages of the ARM Trusted Firmware and normal world software. It sets up +Secure EL1 memory translation by creating page tables to address the first 4GB +of the physical address space in a similar way to BL1. EL1 and EL0 are given +access to Floating Point & Advanced SIMD registers by clearing the `CPACR.FPEN` +bits. + +#### Platform initialization + +BL2 copies the information regarding the trusted SRAM populated by BL1 using a +platform-specific mechanism. It calculates the limits of DRAM (main memory) +to determine whether there is enough space to load the BL3-3 image. A platform +defined base address is used to specify the load address for the BL3-1 image. +It also defines the extents of memory available for use by the BL3-2 image. +BL2 also initializes UART0 (PL011 console), which enables access to the +`printf` family of functions in BL2. Platform security is initialized to allow +access to access controlled components. On the Base FVP a TrustZone controller +(TZC-400) is configured to give full access to the platform DRAM. The storage +abstraction layer is initialized which is used to load further bootloader +images. + +#### BL3-0 (System Control Processor Firmware) image load + +Some systems have a separate System Control Processor (SCP) for power, clock, +reset and system control. BL2 loads the optional BL3-0 image from platform +storage into a platform-specific region of secure memory. The subsequent +handling of BL3-0 is platform specific. Typically the image is transferred into +SCP memory using a platform-specific protocol. The SCP executes BL3-0 and +signals to the Application Processor (AP) for BL2 execution to continue. + +#### BL3-1 (EL3 Runtime Firmware) image load + +BL2 loads the BL3-1 image from platform storage into a platform-specific address +in trusted SRAM. If there is not enough memory to load the image or image is +missing it leads to an assertion failure. If the BL3-1 image loads successfully, +BL2 updates the amount of trusted SRAM used and available for use by BL3-1. +This information is populated at a platform-specific memory address. + +#### BL3-2 (Secure-EL1 Payload) image load + +BL2 loads the optional BL3-2 image from platform storage into a platform- +specific region of secure memory. The image executes in the secure world. BL2 +relies on BL3-1 to pass control to the BL3-2 image, if present. Hence, BL2 +populates a platform-specific area of memory with the entrypoint/load-address +of the BL3-2 image. The value of the Saved Processor Status Register (`SPSR`) +for entry into BL3-2 is not determined by BL2, it is initialized by the +Secure-EL1 Payload Dispatcher (see later) within BL3-1, which is responsible for +managing interaction with BL3-2. This information is passed to BL3-1. + +#### BL3-3 (Non-trusted Firmware) image load + +BL2 loads the BL3-3 image (e.g. UEFI or other test or boot software) from +platform storage into non-secure memory as defined by the platform +(`0x88000000` for FVPs). + +BL2 relies on BL3-1 to pass control to BL3-3 once secure state initialization is +complete. Hence, BL2 populates a platform-specific area of memory with the +entrypoint and Saved Program Status Register (`SPSR`) of the normal world +software image. The entrypoint is the load address of the BL3-3 image. The +`SPSR` is determined as specified in Section 5.13 of the [PSCI PDD] [PSCI]. This +information is passed to BL3-1. + +#### BL3-1 (EL3 Runtime Firmware) execution + +BL2 execution continues as follows: + +1. BL2 passes control back to BL1 by raising an SMC, providing BL1 with the + BL3-1 entrypoint. The exception is handled by the SMC exception handler + installed by BL1. + +2. BL1 turns off the MMU and flushes the caches. It clears the + `SCTLR_EL3.M/I/C` bits, flushes the data cache to the point of coherency + and invalidates the TLBs. + +3. BL1 passes control to BL3-1 at the specified entrypoint at EL3. + + +### BL3-1 + +The image for this stage is loaded by BL2 and BL1 passes control to BL3-1 at +EL3. BL3-1 executes solely in trusted SRAM. BL3-1 is linked against and +loaded at a platform-specific base address (more information can be found later +in this document). The functionality implemented by BL3-1 is as follows. + +#### Architectural initialization + +Currently, BL3-1 performs a similar architectural initialization to BL1 as +far as system register settings are concerned. Since BL1 code resides in ROM, +architectural initialization in BL3-1 allows override of any previous +initialization done by BL1. BL3-1 creates page tables to address the first +4GB of physical address space and initializes the MMU accordingly. It initializes +a buffer of frequently used pointers, called per-cpu pointer cache, in memory for +faster access. Currently the per-cpu pointer cache contains only the pointer +to crash stack. It then replaces the exception vectors populated by BL1 with its +own. BL3-1 exception vectors implement more elaborate support for +handling SMCs since this is the only mechanism to access the runtime services +implemented by BL3-1 (PSCI for example). BL3-1 checks each SMC for validity as +specified by the [SMC calling convention PDD][SMCCC] before passing control to +the required SMC handler routine. BL3-1 programs the `CNTFRQ_EL0` register with +the clock frequency of the system counter, which is provided by the platform. + +#### Platform initialization + +BL3-1 performs detailed platform initialization, which enables normal world +software to function correctly. It also retrieves entrypoint information for +the BL3-3 image loaded by BL2 from the platform defined memory address populated +by BL2. BL3-1 also initializes UART0 (PL011 console), which enables +access to the `printf` family of functions in BL3-1. It enables the system +level implementation of the generic timer through the memory mapped interface. + +* GICv2 initialization: + + - Enable group0 interrupts in the GIC CPU interface. + - Configure group0 interrupts to be asserted as FIQs. + - Disable the legacy interrupt bypass mechanism. + - Configure the priority mask register to allow interrupts of all + priorities to be signaled to the CPU interface. + - Mark SGIs 8-15, the secure physical timer interrupt (#29) and the + trusted watchdog interrupt (#56) as group0 (secure). + - Target the trusted watchdog interrupt to CPU0. + - Enable these group0 interrupts in the GIC distributor. + - Configure all other interrupts as group1 (non-secure). + - Enable signaling of group0 interrupts in the GIC distributor. + +* GICv3 initialization: + + If a GICv3 implementation is available in the platform, BL3-1 initializes + the GICv3 in GICv2 emulation mode with settings as described for GICv2 + above. + +* Power management initialization: + + BL3-1 implements a state machine to track CPU and cluster state. The state + can be one of `OFF`, `ON_PENDING`, `SUSPEND` or `ON`. All secondary CPUs are + initially in the `OFF` state. The cluster that the primary CPU belongs to is + `ON`; any other cluster is `OFF`. BL3-1 initializes the data structures that + implement the state machine, including the locks that protect them. BL3-1 + accesses the state of a CPU or cluster immediately after reset and before + the MMU is enabled in the warm boot path. It is not currently possible to + use 'exclusive' based spinlocks, therefore BL3-1 uses locks based on + Lamport's Bakery algorithm instead. BL3-1 allocates these locks in device + memory. They are accessible irrespective of MMU state. + +* Runtime services initialization: + + The runtime service framework and its initialization is described in the + "EL3 runtime services framework" section below. + + Details about the PSCI service are provided in the "Power State Coordination + Interface" section below. + +* BL3-2 (Secure-EL1 Payload) image initialization + + If a BL3-2 image is present then there must be a matching Secure-EL1 Payload + Dispatcher (SPD) service (see later for details). During initialization + that service must register a function to carry out initialization of BL3-2 + once the runtime services are fully initialized. BL3-1 invokes such a + registered function to initialize BL3-2 before running BL3-3. + + Details on BL3-2 initialization and the SPD's role are described in the + "Secure-EL1 Payloads and Dispatchers" section below. + +* BL3-3 (Non-trusted Firmware) execution + + BL3-1 initializes the EL2 or EL1 processor context for normal-world cold + boot, ensuring that no secure state information finds its way into the + non-secure execution state. BL3-1 uses the entrypoint information provided + by BL2 to jump to the Non-trusted firmware image (BL3-3) at the highest + available Exception Level (EL2 if available, otherwise EL1). + + +### Using alternative Trusted Boot Firmware in place of BL1 and BL2 + +Some platforms have existing implementations of Trusted Boot Firmware that +would like to use ARM Trusted Firmware BL3-1 for the EL3 Runtime Firmware. To +enable this firmware architecture it is important to provide a fully documented +and stable interface between the Trusted Boot Firmware and BL3-1. + +Future changes to the BL3-1 interface will be done in a backwards compatible +way, and this enables these firmware components to be independently enhanced/ +updated to develop and exploit new functionality. + +#### Required CPU state when calling `bl31_entrypoint()` during cold boot + +This function must only be called by the primary CPU, if this is called by any +other CPU the firmware will abort. + +On entry to this function the calling primary CPU must be executing in AArch64 +EL3, little-endian data access, and all interrupt sources masked: + + PSTATE.EL = 3 + PSTATE.RW = 1 + PSTATE.DAIF = 0xf + CTLR_EL3.EE = 0 + +X0 and X1 can be used to pass information from the Trusted Boot Firmware to the +platform code in BL3-1: + + X0 : Reserved for common Trusted Firmware information + X1 : Platform specific information + +BL3-1 zero-init sections (e.g. `.bss`) should not contain valid data on entry, +these will be zero filled prior to invoking platform setup code. + +##### Use of the X0 and X1 parameters + +The parameters are platform specific and passed from `bl31_entrypoint()` to +`bl31_early_platform_setup()`. The value of these parameters is never directly +used by the common BL3-1 code. + +The convention is that `X0` conveys information regarding the BL3-1, BL3-2 and +BL3-3 images from the Trusted Boot firmware and `X1` can be used for other +platform specific purpose. This convention allows platforms which use ARM +Trusted Firmware's BL1 and BL2 images to transfer additional platform specific +information from Secure Boot without conflicting with future evolution of the +Trusted Firmware using `X0` to pass a `bl31_params` structure. + +BL3-1 common and SPD initialization code depends on image and entrypoint +information about BL3-3 and BL3-2, which is provided via BL3-1 platform APIs. +This information is required until the start of execution of BL3-3. This +information can be provided in a platform defined manner, e.g. compiled into +the platform code in BL3-1, or provided in a platform defined memory location +by the Trusted Boot firmware, or passed from the Trusted Boot Firmware via the +Cold boot Initialization parameters. This data may need to be cleaned out of +the CPU caches if it is provided by an earlier boot stage and then accessed by +BL3-1 platform code before the caches are enabled. + +ARM Trusted Firmware's BL2 implementation passes a `bl31_params` structure in +`X0` and the FVP port interprets this in the BL3-1 platform code. + +##### MMU, Data caches & Coherency + +BL3-1 does not depend on the enabled state of the MMU, data caches or +interconnect coherency on entry to `bl31_entrypoint()`. If these are disabled +on entry, these should be enabled during `bl31_plat_arch_setup()`. + +##### Data structures used in the BL3-1 cold boot interface + +These structures are designed to support compatibility and independent +evolution of the structures and the firmware images. For example, a version of +BL3-1 that can interpret the BL3-x image information from different versions of +BL2, a platform that uses an extended entry_point_info structure to convey +additional register information to BL3-1, or a ELF image loader that can convey +more details about the firmware images. + +To support these scenarios the structures are versioned and sized, which enables +BL3-1 to detect which information is present and respond appropriately. The +`param_header` is defined to capture this information: + + typedef struct param_header { + uint8_t type; /* type of the structure */ + uint8_t version; /* version of this structure */ + uint16_t size; /* size of this structure in bytes */ + uint32_t attr; /* attributes: unused bits SBZ */ + } param_header_t; + +The structures using this format are `entry_point_info`, `image_info` and +`bl31_params`. The code that allocates and populates these structures must set +the header fields appropriately, and the `SET_PARA_HEAD()` a macro is defined +to simplify this action. + +#### Required CPU state for BL3-1 Warm boot initialization + +When requesting a CPU power-on, or suspending a running CPU, ARM Trusted +Firmware provides the platform power management code with a Warm boot +initialization entry-point, to be invoked by the CPU immediately after the +reset handler. On entry to the Warm boot initialization function the calling +CPU must be in AArch64 EL3, little-endian data access and all interrupt sources +masked: + + PSTATE.EL = 3 + PSTATE.RW = 1 + PSTATE.DAIF = 0xf + SCTLR_EL3.EE = 0 + +The PSCI implementation will initialize the processor state and ensure that the +platform power management code is then invoked as required to initialize all +necessary system, cluster and CPU resources. + + +### Using BL3-1 as the CPU reset vector + +On some platforms the runtime firmware (BL3-x images) for the application +processors are loaded by trusted 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 BL3-1 which eliminates the need for BL1 and BL2. + +ARM Trusted Firmware provides a build-time option `RESET_TO_BL31` that includes +some additional logic in the BL3-1 entrypoint to support this use case. + +In this configuration, the platform's Trusted Boot Firmware must ensure that +BL3-1 is loaded to its runtime address, which must match the CPU's RVBAR reset +vector address, before the application processor is powered on. Additionally, +platform software is responsible for loading the other BL3-x images required and +providing entry point information for them to BL3-1. Loading these images might +be done by the Trusted Boot Firmware or by platform code in BL3-1. + +The ARM FVP port supports 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. + +This configuration requires some additions and changes in the BL3-1 +functionality: + +#### Determination of boot path + +In this configuration, BL3-1 uses the same reset framework and code as the one +described for BL1 above. 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 BL3-1 initialization, as described below. + +#### Architectural initialization + +As the first image to execute in this configuration BL3-1 must ensure that +interconnect coherency is enabled (if required) before enabling the MMU. + +#### Platform initialization + +In this configuration, when the CPU resets to BL3-1 there are no parameters +that can be passed in registers by previous boot stages. Instead, the platform +code in BL3-1 needs to know, or be able to determine, the location of the BL3-2 +(if required) and BL3-3 images and provide this information in response to the +`bl31_plat_get_next_image_ep_info()` function. + +As the first image to execute in this configuration BL3-1 must also ensure that +any security initialisation, for example programming a TrustZone address space +controller, is carried out during early platform initialisation. + + +3. EL3 runtime services framework +---------------------------------- + +Software executing in the non-secure state and in the secure state at exception +levels lower than EL3 will request runtime services using the Secure Monitor +Call (SMC) instruction. These requests will follow the convention described in +the SMC Calling Convention PDD ([SMCCC]). The [SMCCC] assigns function +identifiers to each SMC request and describes how arguments are passed and +returned. + +The EL3 runtime services framework enables the development of services by +different providers that can be easily integrated into final product firmware. +The following sections describe the framework which facilitates the +registration, initialization and use of runtime services in EL3 Runtime +Firmware (BL3-1). + +The design of the runtime services depends heavily on the concepts and +definitions described in the [SMCCC], in particular SMC Function IDs, Owning +Entity Numbers (OEN), Fast and Standard calls, and the SMC32 and SMC64 calling +conventions. Please refer to that document for more detailed explanation of +these terms. + +The following runtime services are expected to be implemented first. They have +not all been instantiated in the current implementation. + +1. Standard service calls + + This service is for management of the entire system. The Power State + Coordination Interface ([PSCI]) is the first set of standard service calls + defined by ARM (see PSCI section later). + + NOTE: Currently this service is called PSCI since there are no other + defined standard service calls. + +2. Secure-EL1 Payload Dispatcher service + + If a system runs a Trusted OS or other Secure-EL1 Payload (SP) then + it also requires a _Secure Monitor_ at EL3 to switch the EL1 processor + context between the normal world (EL1/EL2) and trusted world (Secure-EL1). + The Secure Monitor will make these world switches in response to SMCs. The + [SMCCC] provides for such SMCs with the Trusted OS Call and Trusted + Application Call OEN ranges. + + The interface between the EL3 Runtime Firmware and the Secure-EL1 Payload is + not defined by the [SMCCC] or any other standard. As a result, each + Secure-EL1 Payload requires a specific Secure Monitor that runs as a runtime + service - within ARM Trusted Firmware this service is referred to as the + Secure-EL1 Payload Dispatcher (SPD). + + ARM Trusted Firmware provides a Test Secure-EL1 Payload (TSP) and its + associated Dispatcher (TSPD). Details of SPD design and TSP/TSPD operation + are described in the "Secure-EL1 Payloads and Dispatchers" section below. + +3. CPU implementation service + + This service will provide an interface to CPU implementation specific + services for a given platform e.g. access to processor errata workarounds. + This service is currently unimplemented. + +Additional services for ARM Architecture, SiP and OEM calls can be implemented. +Each implemented service handles a range of SMC function identifiers as +described in the [SMCCC]. + + +### Registration + +A runtime service is registered using the `DECLARE_RT_SVC()` macro, specifying +the name of the service, the range of OENs covered, the type of service and +initialization and call handler functions. This macro instantiates a `const +struct rt_svc_desc` for the service with these details (see `runtime_svc.h`). +This structure is allocated in a special ELF section `rt_svc_descs`, enabling +the framework to find all service descriptors included into BL3-1. + +The specific service for a SMC Function is selected based on the OEN and call +type of the Function ID, and the framework uses that information in the service +descriptor to identify the handler for the SMC Call. + +The service descriptors do not include information to identify the precise set +of SMC function identifiers supported by this service implementation, the +security state from which such calls are valid nor the capability to support +64-bit and/or 32-bit callers (using SMC32 or SMC64). Responding appropriately +to these aspects of a SMC call is the responsibility of the service +implementation, the framework is focused on integration of services from +different providers and minimizing the time taken by the framework before the +service handler is invoked. + +Details of the parameters, requirements and behavior of the initialization and +call handling functions are provided in the following sections. + + +### Initialization + +`runtime_svc_init()` in `runtime_svc.c` initializes the runtime services +framework running on the primary CPU during cold boot as part of the BL3-1 +initialization. This happens prior to initializing a Trusted OS and running +Normal world boot firmware that might in turn use these services. +Initialization involves validating each of the declared runtime service +descriptors, calling the service initialization function and populating the +index used for runtime lookup of the service. + +The BL3-1 linker script collects all of the declared service descriptors into a +single array and defines symbols that allow the framework to locate and traverse +the array, and determine its size. + +The framework does basic validation of each descriptor to halt firmware +initialization if service declaration errors are detected. The framework does +not check descriptors for the following error conditions, and may behave in an +unpredictable manner under such scenarios: + +1. Overlapping OEN ranges +2. Multiple descriptors for the same range of OENs and `call_type` +3. Incorrect range of owning entity numbers for a given `call_type` + +Once validated, the service `init()` callback is invoked. This function carries +out any essential EL3 initialization before servicing requests. The `init()` +function is only invoked on the primary CPU during cold boot. If the service +uses per-CPU data this must either be initialized for all CPUs during this call, +or be done lazily when a CPU first issues an SMC call to that service. If +`init()` returns anything other than `0`, this is treated as an initialization +error and the service is ignored: this does not cause the firmware to halt. + +The OEN and call type fields present in the SMC Function ID cover a total of +128 distinct services, but in practice a single descriptor can cover a range of +OENs, e.g. SMCs to call a Trusted OS function. To optimize the lookup of a +service handler, the framework uses an array of 128 indices that map every +distinct OEN/call-type combination either to one of the declared services or to +indicate the service is not handled. This `rt_svc_descs_indices[]` array is +populated for all of the OENs covered by a service after the service `init()` +function has reported success. So a service that fails to initialize will never +have it's `handle()` function invoked. + +The following figure shows how the `rt_svc_descs_indices[]` index maps the SMC +Function ID call type and OEN onto a specific service handler in the +`rt_svc_descs[]` array. + +![Image 1](diagrams/rt-svc-descs-layout.png?raw=true) + + +### Handling an SMC + +When the EL3 runtime services framework receives a Secure Monitor Call, the SMC +Function ID is passed in W0 from the lower exception level (as per the +[SMCCC]). If the calling register width is AArch32, it is invalid to invoke an +SMC Function which indicates the SMC64 calling convention: such calls are +ignored and return the Unknown SMC Function Identifier result code `0xFFFFFFFF` +in R0/X0. + +Bit[31] (fast/standard call) and bits[29:24] (owning entity number) of the SMC +Function ID are combined to index into the `rt_svc_descs_indices[]` array. The +resulting value might indicate a service that has no handler, in this case the +framework will also report an Unknown SMC Function ID. Otherwise, the value is +used as a further index into the `rt_svc_descs[]` array to locate the required +service and handler. + +The service's `handle()` callback is provided with five of the SMC parameters +directly, the others are saved into memory for retrieval (if needed) by the +handler. The handler is also provided with an opaque `handle` for use with the +supporting library for parameter retrieval, setting return values and context +manipulation; and with `flags` indicating the security state of the caller. The +framework finally sets up the execution stack for the handler, and invokes the +services `handle()` function. + +On return from the handler the result registers are populated in X0-X3 before +restoring the stack and CPU state and returning from the original SMC. + + +4. Power State Coordination Interface +-------------------------------------- + +TODO: Provide design walkthrough of PSCI implementation. + +The complete PSCI API is not yet implemented. The following functions are +currently implemented: + +- `PSCI_VERSION` +- `CPU_OFF` +- `CPU_ON` +- `CPU_SUSPEND` +- `AFFINITY_INFO` + +The `CPU_ON`, `CPU_OFF` and `CPU_SUSPEND` functions implement the warm boot +path in ARM Trusted Firmware. `CPU_ON` and `CPU_OFF` have undergone testing +on all the supported FVPs. `CPU_SUSPEND` & `AFFINITY_INFO` have undergone +testing only on the AEM v8 Base FVP. Support for `AFFINITY_INFO` is still +experimental. Support for `CPU_SUSPEND` is stable for entry into power down +states. Standby states are currently not supported. `PSCI_VERSION` is +present but completely untested in this version of the software. + +Unsupported PSCI functions can be divided into ones that can return +execution to the caller and ones that cannot. The following functions +return with a error code as documented in the [Power State Coordination +Interface PDD] [PSCI]. + +- `MIGRATE` : -1 (NOT_SUPPORTED) +- `MIGRATE_INFO_TYPE` : 2 (Trusted OS is either not present or does not + require migration) +- `MIGRATE_INFO_UP_CPU` : 0 (Return value is UNDEFINED) + +The following unsupported functions do not return and signal an assertion +failure if invoked. + +- `SYSTEM_OFF` +- `SYSTEM_RESET` + + +5. Secure-EL1 Payloads and Dispatchers +--------------------------------------- + +On a production system that includes a Trusted OS running in Secure-EL1/EL0, +the Trusted OS is coupled with a companion runtime service in the BL3-1 +firmware. This service is responsible for the initialisation of the Trusted +OS and all communications with it. The Trusted OS is the BL3-2 stage of the +boot flow in ARM Trusted Firmware. The firmware will attempt to locate, load +and execute a BL3-2 image. + +ARM Trusted Firmware uses a more general term for the BL3-2 software that runs +at Secure-EL1 - the _Secure-EL1 Payload_ - as it is not always a Trusted OS. + +The ARM Trusted Firmware provides a Test Secure-EL1 Payload (TSP) and a Test +Secure-EL1 Payload Dispatcher (TSPD) service as an example of how a Trusted OS +is supported on a production system using the Runtime Services Framework. On +such a system, the Test BL3-2 image and service are replaced by the Trusted OS +and its dispatcher service. + +The TSP runs in Secure-EL1. It is designed to demonstrate synchronous +communication with the normal-world software running in EL1/EL2. Communication +is initiated by the normal-world software + +* either directly through a Fast SMC (as defined in the [SMCCC]) + +* or indirectly through a [PSCI] SMC. The [PSCI] implementation in turn + informs the TSPD about the requested power management operation. This allows + the TSP to prepare for or respond to the power state change + +The TSPD service is responsible for. + +* Initializing the TSP + +* Routing requests and responses between the secure and the non-secure + states during the two types of communications just described + +### Initializing a BL3-2 Image + +The Secure-EL1 Payload Dispatcher (SPD) service is responsible for initializing +the BL3-2 image. It needs access to the information passed by BL2 to BL3-1 to do +so. This is provided by: + + entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t); + +which returns a reference to the `entry_point_info` structure corresponding to +the image which will be run in the specified security state. The SPD uses this +API to get entry point information for the SECURE image, BL3-2. + +In the absence of a BL3-2 image, BL3-1 passes control to the normal world +bootloader image (BL3-3). When the BL3-2 image is present, it is typical +that the SPD wants control to be passed to BL3-2 first and then later to BL3-3. + +To do this the SPD has to register a BL3-2 initialization function during +initialization of the SPD service. The BL3-2 initialization function has this +prototype: + + int32_t init(); + +and is registered using the `bl31_register_bl32_init()` function. + +Trusted Firmware supports two approaches for the SPD to pass control to BL3-2 +before returning through EL3 and running the non-trusted firmware (BL3-3): + +1. In the BL3-2 initialization function, set up a secure context (see below + for more details of CPU context support) for this CPU and use + `bl31_set_next_image_type()` to request that the exit from `bl31_main()` is + to the BL3-2 entrypoint in Secure-EL1. + + When the BL3-2 has completed initialization at Secure-EL1, it returns to + BL3-1 by issuing an SMC, using a Function ID allocated to the SPD. On + receipt of this SMC, the SPD service handler should switch the CPU context + from trusted to normal world and use the `bl31_set_next_image_type()` and + `bl31_prepare_next_image_entry()` functions to set up the initial return to + the normal world firmware BL3-3. On return from the handler the framework + will exit to EL2 and run BL3-3. + +2. In the BL3-2 initialization function, use an SPD-defined mechanism to + invoke a 'world-switch synchronous call' to Secure-EL1 to run the BL3-2 + entrypoint. + NOTE: The Test SPD service included with the Trusted Firmware provides one + implementation of such a mechanism. + + On completion BL3-2 returns control to BL3-1 via a SMC, and on receipt the + SPD service handler invokes the synchronous call return mechanism to return + to the BL3-2 initialization function. On return from this function, + `bl31_main()` will set up the return to the normal world firmware BL3-3 and + continue the boot process in the normal world. + +6. Crash Reporting in BL3-1 +---------------------------------- + +The BL3-1 implements a scheme for reporting the processor state when an unhandled +exception is encountered. The reporting mechanism attempts to preserve all the +register contents and report it via the default serial output. The general purpose +registers, EL3, Secure EL1 and some EL2 state registers are reported. + +A dedicated per-cpu crash stack is maintained by BL3-1 and this is retrieved via +the per-cpu pointer cache. The implementation attempts to minimise the memory +required for this feature. The file `crash_reporting.S` contains the +implementation for crash reporting. + +The sample crash output is shown below. + + x0 :0x000000004F00007C + x1 :0x0000000007FFFFFF + x2 :0x0000000004014D50 + x3 :0x0000000000000000 + x4 :0x0000000088007998 + x5 :0x00000000001343AC + x6 :0x0000000000000016 + x7 :0x00000000000B8A38 + x8 :0x00000000001343AC + x9 :0x00000000000101A8 + x10 :0x0000000000000002 + x11 :0x000000000000011C + x12 :0x00000000FEFDC644 + x13 :0x00000000FED93FFC + x14 :0x0000000000247950 + x15 :0x00000000000007A2 + x16 :0x00000000000007A4 + x17 :0x0000000000247950 + x18 :0x0000000000000000 + x19 :0x00000000FFFFFFFF + x20 :0x0000000004014D50 + x21 :0x000000000400A38C + x22 :0x0000000000247950 + x23 :0x0000000000000010 + x24 :0x0000000000000024 + x25 :0x00000000FEFDC868 + x26 :0x00000000FEFDC86A + x27 :0x00000000019EDEDC + x28 :0x000000000A7CFDAA + x29 :0x0000000004010780 + x30 :0x000000000400F004 + scr_el3 :0x0000000000000D3D + sctlr_el3 :0x0000000000C8181F + cptr_el3 :0x0000000000000000 + tcr_el3 :0x0000000080803520 + daif :0x00000000000003C0 + mair_el3 :0x00000000000004FF + spsr_el3 :0x00000000800003CC + elr_el3 :0x000000000400C0CC + ttbr0_el3 :0x00000000040172A0 + esr_el3 :0x0000000096000210 + sp_el3 :0x0000000004014D50 + far_el3 :0x000000004F00007C + spsr_el1 :0x0000000000000000 + elr_el1 :0x0000000000000000 + spsr_abt :0x0000000000000000 + spsr_und :0x0000000000000000 + spsr_irq :0x0000000000000000 + spsr_fiq :0x0000000000000000 + sctlr_el1 :0x0000000030C81807 + actlr_el1 :0x0000000000000000 + cpacr_el1 :0x0000000000300000 + csselr_el1 :0x0000000000000002 + sp_el1 :0x0000000004028800 + esr_el1 :0x0000000000000000 + ttbr0_el1 :0x000000000402C200 + ttbr1_el1 :0x0000000000000000 + mair_el1 :0x00000000000004FF + amair_el1 :0x0000000000000000 + tcr_el1 :0x0000000000003520 + tpidr_el1 :0x0000000000000000 + tpidr_el0 :0x0000000000000000 + tpidrro_el0 :0x0000000000000000 + dacr32_el2 :0x0000000000000000 + ifsr32_el2 :0x0000000000000000 + par_el1 :0x0000000000000000 + far_el1 :0x0000000000000000 + afsr0_el1 :0x0000000000000000 + afsr1_el1 :0x0000000000000000 + contextidr_el1 :0x0000000000000000 + vbar_el1 :0x0000000004027000 + cntp_ctl_el0 :0x0000000000000000 + cntp_cval_el0 :0x0000000000000000 + cntv_ctl_el0 :0x0000000000000000 + cntv_cval_el0 :0x0000000000000000 + cntkctl_el1 :0x0000000000000000 + fpexc32_el2 :0x0000000004000700 + sp_el0 :0x0000000004010780 + + +7. Memory layout on FVP platforms +---------------------------------- + +On FVP platforms, we use the Trusted ROM and Trusted SRAM to store the trusted +firmware binaries. BL1 is originally sitting in the Trusted ROM at address +`0x0`. Its read-write data are relocated at the base of the Trusted SRAM at +runtime. BL1 loads BL2 image near the top of the trusted SRAM. BL2 loads BL3-1 +image between BL1 and BL2. Optionally, BL2 then loads the TSP as the BL3-2 +image. By default it is loaded in Trusted SRAM, in this case it sits between +BL3-1 and BL2. This memory layout is illustrated by the following diagram. + + Trusted SRAM + +----------+ 0x04040000 + | | + |----------| + | BL2 | + |----------| + | | + |----------| + | BL32 | (optional) + |----------| + | | + |----------| + | BL31 | + |----------| + | | + |----------| + | BL1 (rw) | + +----------+ 0x04000000 + + Trusted ROM + +----------+ 0x04000000 + | BL1 (ro) | + +----------+ 0x00000000 + +The TSP image may be loaded in Trusted DRAM instead. This doesn't change the +memory layout of the other boot loader images in Trusted SRAM. + +Although the goal at long term is to give complete flexibility over the memory +layout, all platforms should conform to this layout at the moment. This is +because of some limitations in the implementation of the image loader in the +Trusted Firmware. Refer to the "Limitations of the image loader" section below. + +Each bootloader stage image layout is described by its own linker script. The +linker scripts export some symbols into the program symbol table. Their values +correspond to particular addresses. The trusted firmware code can refer to these +symbols to figure out the image memory layout. + +Linker symbols follow the following naming convention in the trusted firmware. + +* `__<SECTION>_START__` + + Start address of a given section named `<SECTION>`. + +* `__<SECTION>_END__` + + End address of a given section named `<SECTION>`. If there is an alignment + constraint on the section's end address then `__<SECTION>_END__` corresponds + to the end address of the section's actual contents, rounded up to the right + boundary. Refer to the value of `__<SECTION>_UNALIGNED_END__` to know the + actual end address of the section's contents. + +* `__<SECTION>_UNALIGNED_END__` + + End address of a given section named `<SECTION>` without any padding or + rounding up due to some alignment constraint. + +* `__<SECTION>_SIZE__` + + Size (in bytes) of a given section named `<SECTION>`. If there is an + alignment constraint on the section's end address then `__<SECTION>_SIZE__` + corresponds to the size of the section's actual contents, rounded up to the + right boundary. In other words, `__<SECTION>_SIZE__ = __<SECTION>_END__ - + _<SECTION>_START__`. Refer to the value of `__<SECTION>_UNALIGNED_SIZE__` + to know the actual size of the section's contents. + +* `__<SECTION>_UNALIGNED_SIZE__` + + Size (in bytes) of a given section named `<SECTION>` without any padding or + rounding up due to some alignment constraint. In other words, + `__<SECTION>_UNALIGNED_SIZE__ = __<SECTION>_UNALIGNED_END__ - + __<SECTION>_START__`. + +Some of the linker symbols are mandatory as the trusted firmware code relies on +them to be defined. They are listed in the following subsections. Some of them +must be provided for each bootloader stage and some are specific to a given +bootloader stage. + +The linker scripts define some extra, optional symbols. They are not actually +used by any code but they help in understanding the bootloader images' memory +layout as they are easy to spot in the link map files. + +### Common linker symbols + +Early setup code needs to know the extents of the BSS section to zero-initialise +it before executing any C code. The following linker symbols are defined for +this purpose: + +* `__BSS_START__` This address must be aligned on a 16-byte boundary. +* `__BSS_SIZE__` + +Similarly, the coherent memory section must be zero-initialised. Also, the MMU +setup code needs to know the extents of this section to set the right memory +attributes for it. The following linker symbols are defined for this purpose: + +* `__COHERENT_RAM_START__` This address must be aligned on a page-size boundary. +* `__COHERENT_RAM_END__` This address must be aligned on a page-size boundary. +* `__COHERENT_RAM_UNALIGNED_SIZE__` + +### BL1's linker symbols + +BL1's early setup code needs to know the extents of the .data section to +relocate it from ROM to RAM before executing any C code. The following linker +symbols are defined for this purpose: + +* `__DATA_ROM_START__` This address must be aligned on a 16-byte boundary. +* `__DATA_RAM_START__` This address must be aligned on a 16-byte boundary. +* `__DATA_SIZE__` + +BL1's platform setup code needs to know the extents of its read-write data +region to figure out its memory layout. The following linker symbols are defined +for this purpose: + +* `__BL1_RAM_START__` This is the start address of BL1 RW data. +* `__BL1_RAM_END__` This is the end address of BL1 RW data. + +### BL2's, BL3-1's and TSP's linker symbols + +BL2, BL3-1 and TSP need to know the extents of their read-only section to set +the right memory attributes for this memory region in their MMU setup code. The +following linker symbols are defined for this purpose: + +* `__RO_START__` +* `__RO_END__` + +### How to choose the right base addresses for each bootloader stage image + +There is currently no support for dynamic image loading in the Trusted Firmware. +This means that all bootloader images need to be linked against their ultimate +runtime locations and the base addresses of each image must be chosen carefully +such that images don't overlap each other in an undesired way. As the code +grows, the base addresses might need adjustments to cope with the new memory +layout. + +The memory layout is completely specific to the platform and so there is no +general recipe for choosing the right base addresses for each bootloader image. +However, there are tools to aid in understanding the memory layout. These are +the link map files: `build/<platform>/<build-type>/bl<x>/bl<x>.map`, with `<x>` +being the stage bootloader. They provide a detailed view of the memory usage of +each image. Among other useful information, they provide the end address of +each image. + +* `bl1.map` link map file provides `__BL1_RAM_END__` address. +* `bl2.map` link map file provides `__BL2_END__` address. +* `bl31.map` link map file provides `__BL31_END__` address. +* `bl32.map` link map file provides `__BL32_END__` address. + +For each bootloader image, the platform code must provide its start address +as well as a limit address that it must not overstep. The latter is used in the +linker scripts to check that the image doesn't grow past that address. If that +happens, the linker will issue a message similar to the following: + + aarch64-none-elf-ld: BLx has exceeded its limit. + +On FVP platforms, the base addresses have been chosen such that all images can +reside concurrently in Trusted RAM without overlapping each other. Note that +this is not a requirement, as not all images live in memory at the same time. +For example, when the BL3-1 image takes over execution, BL1 and BL2 images are +not needed anymore. + +### Limitations of the image loader + +The current implementation of the image loader can result in wasted space +because of the simplified data structure used to represent the extents of free +memory. For example, to load BL2 at address `0x0402D000`, the resulting memory +layout should be as follows: + + ------------ 0x04040000 + | | <- Free space (1) + |----------| + | BL2 | + |----------| BL2_BASE (0x0402D000) + | | <- Free space (2) + |----------| + | BL1 | + ------------ 0x04000000 + +In the current implementation, we need to specify whether BL2 is loaded at the +top or bottom of the free memory. BL2 is top-loaded so in the example above, +the free space (1) above BL2 is hidden, resulting in the following view of +memory: + + ------------ 0x04040000 + | | + | | + | BL2 | + |----------| BL2_BASE (0x0402D000) + | | <- Free space (2) + |----------| + | BL1 | + ------------ 0x04000000 + +BL3-1 is bottom-loaded above BL1. For example, if BL3-1 is bottom-loaded at +`0x0400E000`, the memory layout should look like this: + + ------------ 0x04040000 + | | + | | + | BL2 | + |----------| BL2_BASE (0x0402D000) + | | <- Free space (2) + | | + |----------| + | | + | BL31 | + |----------| BL31_BASE (0x0400E000) + | | <- Free space (3) + |----------| + | BL1 | + ------------ 0x04000000 + +But the free space (3) between BL1 and BL3-1 is wasted, resulting in the +following view: + + ------------ 0x04040000 + | | + | | + | BL2 | + |----------| BL2_BASE (0x0402D000) + | | <- Free space (2) + | | + |----------| + | | + | | + | BL31 | BL31_BASE (0x0400E000) + | | + |----------| + | BL1 | + ------------ 0x04000000 + + +8. Firmware Image Package (FIP) +-------------------------------- + +Using a Firmware Image Package (FIP) allows for packing bootloader images (and +potentially other payloads) into a single archive that can be loaded by the ARM +Trusted Firmware from non-volatile platform storage. A driver to load images +from a FIP has been added to the storage layer and allows a package to be read +from supported platform storage. A tool to create Firmware Image Packages is +also provided and described below. + +### Firmware Image Package layout + +The FIP layout consists of a table of contents (ToC) followed by payload data. +The ToC itself has a header followed by one or more table entries. The ToC is +terminated by an end marker entry. All ToC entries describe some payload data +that has been appended to the end of the binary package. With the information +provided in the ToC entry the corresponding payload data can be retrieved. + + ------------------ + | ToC Header | + |----------------| + | ToC Entry 0 | + |----------------| + | ToC Entry 1 | + |----------------| + | ToC End Marker | + |----------------| + | | + | Data 0 | + | | + |----------------| + | | + | Data 1 | + | | + ------------------ + +The ToC header and entry formats are described in the header file +`include/firmware_image_package.h`. This file is used by both the tool and the +ARM Trusted firmware. + +The ToC header has the following fields: + `name`: The name of the ToC. This is currently used to validate the header. + `serial_number`: A non-zero number provided by the creation tool + `flags`: Flags associated with this data. None are yet defined. + +A ToC entry has the following fields: + `uuid`: All files are referred to by a pre-defined Universally Unique + IDentifier [UUID] . The UUIDs are defined in + `include/firmware_image_package`. The platform translates the requested + image name into the corresponding UUID when accessing the package. + `offset_address`: The offset address at which the corresponding payload data + can be found. The offset is calculated from the ToC base address. + `size`: The size of the corresponding payload data in bytes. + `flags`: Flags associated with this entry. Non are yet defined. + +### Firmware Image Package creation tool + +The FIP creation tool can be used to pack specified images into a binary package +that can be loaded by the ARM Trusted Firmware from platform storage. The tool +currently only supports packing bootloader images. Additional image definitions +can be added to the tool as required. + +The tool can be found in `tools/fip_create`. + +### Loading from a Firmware Image Package (FIP) + +The Firmware Image Package (FIP) driver can load images from a binary package on +non-volatile platform storage. For the FVPs this is currently NOR FLASH. + +Bootloader images are loaded according to the platform policy as specified in +`plat/<platform>/plat_io_storage.c`. For the FVPs this means the platform will +attempt to load images from a Firmware Image Package located at the start of NOR +FLASH0. + +Currently the FVP's policy only allows loading of a known set of images. The +platform policy can be modified to allow additional images. + + +9. Code Structure +------------------ + +Trusted Firmware code is logically divided between the three boot loader +stages mentioned in the previous sections. The code is also divided into the +following categories (present as directories in the source code): + +* **Architecture specific.** This could be AArch32 or AArch64. +* **Platform specific.** Choice of architecture specific code depends upon + the platform. +* **Common code.** This is platform and architecture agnostic code. +* **Library code.** This code comprises of functionality commonly used by all + other code. +* **Stage specific.** Code specific to a boot stage. +* **Drivers.** +* **Services.** EL3 runtime services, e.g. PSCI or SPD. Specific SPD services + reside in the `services/spd` directory (e.g. `services/spd/tspd`). + +Each boot loader stage uses code from one or more of the above mentioned +categories. Based upon the above, the code layout looks like this: + + Directory Used by BL1? Used by BL2? Used by BL3-1? + bl1 Yes No No + bl2 No Yes No + bl31 No No Yes + arch Yes Yes Yes + plat Yes Yes Yes + drivers Yes No Yes + common Yes Yes Yes + lib Yes Yes Yes + services No No Yes + +All assembler files have the `.S` extension. The linker source files for each +boot stage have the extension `.ld.S`. These are processed by GCC to create the +linker scripts which have the extension `.ld`. + +FDTs provide a description of the hardware platform and are used by the Linux +kernel at boot time. These can be found in the `fdts` directory. + + +10. References +-------------- + +1. Trusted Board Boot Requirements CLIENT PDD (ARM DEN 0006B-5). Available + under NDA through your ARM account representative. + +2. [Power State Coordination Interface PDD (ARM DEN 0022B.b)][PSCI]. + +3. [SMC Calling Convention PDD (ARM DEN 0028A)][SMCCC]. + +4. [ARM Trusted Firmware Interrupt Management Design guide][INTRG]. + + +- - - - - - - - - - - - - - - - - - - - - - - - - - + +_Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved._ + + +[PSCI]: http://infocenter.arm.com/help/topic/com.arm.doc.den0022b/index.html "Power State Coordination Interface PDD (ARM DEN 0022B.b)" +[SMCCC]: http://infocenter.arm.com/help/topic/com.arm.doc.den0028a/index.html "SMC Calling Convention PDD (ARM DEN 0028A)" +[UUID]: https://tools.ietf.org/rfc/rfc4122.txt "A Universally Unique IDentifier (UUID) URN Namespace" +[User Guide]: ./user-guide.md +[INTRG]: ./interrupt-framework-design.md diff --git a/docs/interrupt-framework-design.md b/docs/interrupt-framework-design.md new file mode 100644 index 0000000..f96f764 --- /dev/null +++ b/docs/interrupt-framework-design.md @@ -0,0 +1,848 @@ +ARM Trusted Firmware Interrupt Management Design guide +====================================================== + +Contents : + +1. Introduction + * Assumptions + * Concepts + - Interrupt Types + - Routing Model + - Valid Routing Models + + Secure-EL1 Interrupts + + Non-secure Interrupts + - Mapping of Interrupt Type to Signal + +2. Interrupt Management + * Software Components + * Interrupt Registration + - EL3 Runtime Firmware + - Secure Payload Dispatcher + + Test Secure Payload Dispatcher behavior + - Secure Payload + + Secure Payload IHF design w.r.t Secure-EL1 interrupts + + Secure Payload IHF design w.r.t Non-secure interrupts + + Test Secure Payload behavior + * Interrupt Handling + - EL3 Runtime Firmware + - Secure Payload Dispatcher + + Interrupt Entry + + Interrupt Exit + + Test Secure Payload Dispatcher behavior + - Secure Payload + + Test Secure Payload behavior + + +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 Assumptions +The framework makes the following assumptions to simplify its implementation. + +1. All secure interrupts are handled in Secure-EL1. They can be delivered to + Secure-EL1 via EL3 but they cannot be handled in EL3. It will be possible + to extend the framework to handle secure interrupts in EL3 in the future. + +2. Interrupt exceptions (`PSTATE.I` and `F` bits) are masked during execution + in EL3. + +### 1.2 Concepts + +#### 1.2.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. + +In the current implementation of the framework, all secure interrupts are +treated as Secure EL1 interrupts. It will be possible for EL3 software to +configure a secure interrupt as an EL3 interrupt in future implementations. 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.2.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.2.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. Only the Secure-EL1 and Non-secure interrupt +types are considered as EL3 interrupts are currently unsupported (See 1.1). 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.2.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 secure + state. This is a valid routing model as secure software in EL3 can + handover the interrupt to Secure-EL1 for handling. + + +##### 1.2.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 bookeeping 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 pre-empted 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.2.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 signalled through the FIQ signal +while Non-secure interrupts are signalled through the IRQ signal. This applies +when execution is in either security state. + + +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 the [Porting Guide][PRTG] to enable +handling of interrupts. + +In the remainder of this document, for the sake of simplicity 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.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 exception levels lower than EL3 + i.e. Secure-EL1/Secure-EL0. It is responsible for switching execution + between software running in secure and non-secure states at exception + levels lower than EL3. A switch is triggered by a Secure Monitor Call from + either state. 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 value of the `id` parameter depends upon the definition of the +`IMF_READ_INTERRUPT_ID` build time flag. When the flag is defined, `id` contains +the number of the highest priority pending interrupt of the type that this +handler was registered for. When the flag is not defined `id` 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 should return a pointer to +`cpu_context` structure of the current CPU for the the target security state. It +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` (currently unimplemented). +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`. It will return `-ENOTSUP` if the specified +`type` is not supported by the framework i.e. `INTR_TYPE_EL3`. + +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 + +* The default routing model is used for non-secure interrupts i.e they are + routed to the FEL in either security state i.e __CSS=0, TEL3=0__ & + __CSS=1, TEL3=0__ for Non-secure interrupts + +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 `fiq_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_fiq_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. It + registers it 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); + assert(rc == 0); + +#### 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 model 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, 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 + trigerred 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 seperate 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 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 + trigerred 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 pre-empted 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_fiq_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 signalled + at the FIQ vector. Non-secure interrupts will be signalled 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 firmware also determines the interrupt id if the IMF_READ_INTERRUPT_ID + build time flag is set. The id is set to `INTR_ID_UNAVAILABLE` if the flag + is not set. 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 interrupt id and 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. The following text describes further error scenarios keeping + this in mind: + + 1. __SPD service has registered a handler for Non-secure interrupts__: + When an interrupt is received by the handler, it could check its id + to ensure it has been configured as a non-secure interrupt at the + interrupt controller. A secure interrupt should never be handed to + the non-secure interrupt handler. A non-secure interrupt should + never be routed to EL3 when execution is in non-secure state. The + handler could check the security state flag to ensure this. + + 2. __SPD service has registered a handler for Secure-EL1 interrupts__: + When an interrupt is received by the handler, it could check its id + to ensure it has been configured as a secure interrupt at the + interrupt controller. A non-secure interrupt should never be handed + to the secure interrupt handler. If the routing model chosen is such + that Secure-EL1 interrupts are not routed to EL3 when execution is + in non-secure state, then a Secure-EL1 interrupt generated in the + secure state would be invalid. The handler could use the security + state flag to check this. + + The SPD service should use the platform API: + `plat_ic_get_interrupt_type()` to determine the type of interrupt for the + specified id. + +2. Determining whether the security state of the exception level for handling + the interrupt is the same as the security state of the exception level + where the interrupt was generated. This depends upon the routing model and + type of the interrupt. The SPD should use this information to determine if + a context switch is required. The following two cases would 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 in the + future). The SPD service should manage secure interrupt priorities before + handing control to the SP to prevent this type of preemption which can + leave the system in an inconsistent state. + +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 be taken to Secure-EL1 when in +secure state. 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.1 Test secure payload dispatcher behavior +The example TSPD service registers a handler for Secure-EL1 interrupts taken +from the non-secure state. Its handler `tspd_secure_el1_interrupt_handler()` +takes the following actions upon being invoked. + +1. It uses the `id` parameter to query the interrupt controller to ensure + that the interrupt is a Secure-EL1 interrupt. It asserts if this is not + the case. + +2. 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. + +3. It saves the system register context for the non-secure state by calling + `cm_el1_sysregs_context_save(NON_SECURE);`. + +4. It sets the `ELR_EL3` system register to `tsp_fiq_entry` and sets the + `SPSR_EL3.DAIF` bits in the secure CPU context. It sets `x0` to + `TSP_HANDLE_FIQ_AND_RETURN`. If the TSP was in the middle of handling a + standard SMC, then the `ELR_EL3` and `SPSR_EL3` registers in the secure CPU + context are saved first. + +5. It restores the system register context for the secure state by calling + `cm_el1_sysregs_context_restore(SECURE);`. + +6. 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);`. + +7. 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. + +![Image 1](diagrams/sec-int-handling.png?raw=true) + +The TSP issues an SMC with `TSP_HANDLED_S_EL1_FIQ` as the function identifier to +signal completion of interrupt handling. + +The TSP issues an SMC with `TSP_PREEMPTED` as the function identifier to signal +generation of a non-secure interrupt in Secure-EL1. + +The TSPD service takes the following actions in `tspd_smc_handler()` function +upon receiving an SMC with `TSP_HANDLED_S_EL1_FIQ` and `TSP_PREEMPTED` as the +function identifiers: + +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. If the function identifier is `TSP_HANDLED_S_EL1_FIQ`, it restores the + saved `ELR_EL3` and `SPSR_EL3` system registers back to the secure CPU + context (see step 4 above) in case the TSP had been preempted by a non + secure interrupt earlier. It does not save the secure context since the + TSP is expected to preserve it (see Section 2.2.2.1) + +3. If the function identifier is `TSP_PREEMPTED`, it saves the system + register context for the secure state by calling + `cm_el1_sysregs_context_save(SECURE)`. + +4. It restores the system register context for the non-secure state by + calling `cm_el1_sysregs_context_restore(NON_SECURE)`. It sets `x0` to + `SMC_PREEMPTED` if the incoming function identifier is + `TSP_PREEMPTED`. The Normal World is expected to resume the TSP after the + non-secure interrupt handling by issuing an SMC with `TSP_FID_RESUME` as + the function identifier. + +5. 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)`. + +6. `tspd_smc_handler()` returns a reference to the non-secure `cpu_context` + as the return value. + +As mentioned in 4. above, if a non-secure interrupt preempts the TSP execution +then the non-secure software issues an SMC with `TSP_FID_RESUME` as the function +identifier to resume TSP execution. 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 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. + +![Image 2](diagrams/non-sec-int-handling.png?raw=true) + + +#### 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_fiq_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_fiq_stats()`. It then calls +`tsp_fiq_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. + +2. Handles the 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_FIQ` as the function identifier. + +The TSP handles interrupts under the asynchronous model as follows. + +1. Secure-EL1 interrupts are handled by calling the `tsp_fiq_handler()` + function. The function has been described above. + +2. Non-secure interrupts are handled by 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.1). + +- - - - - - - - - - - - - - - - - - - - - - - - - - + +_Copyright (c) 2014, ARM Limited and Contributors. All rights reserved._ + +[Porting Guide]: ./porting-guide.md diff --git a/docs/porting-guide.md b/docs/porting-guide.md new file mode 100644 index 0000000..d970190 --- /dev/null +++ b/docs/porting-guide.md @@ -0,0 +1,1372 @@ +ARM Trusted Firmware Porting Guide +================================== + +Contents +-------- + +1. Introduction +2. Common Modifications + * Common mandatory modifications + * Handling reset + * Common optional modifications +3. Boot Loader stage specific modifications + * Boot Loader stage 1 (BL1) + * Boot Loader stage 2 (BL2) + * Boot Loader stage 3-1 (BL3-1) + * PSCI implementation (in BL3-1) + * Interrupt Management framework (in BL3-1) +4. C Library +5. Storage abstraction layer + +- - - - - - - - - - - - - - - - - - + +1. Introduction +---------------- + +Porting the ARM Trusted Firmware to a new platform involves making some +mandatory and optional modifications for both the cold and warm boot paths. +Modifications consist of: + +* Implementing a platform-specific function or variable, +* Setting up the execution context in a certain way, or +* Defining certain constants (for example #defines). + +The platform-specific functions and variables are all declared in +[include/plat/common/platform.h]. The firmware provides a default implementation +of variables and functions to fulfill the optional requirements. These +implementations are all weakly defined; they are provided to ease the porting +effort. Each platform port can override them with its own implementation if the +default implementation is inadequate. + +Some modifications are common to all Boot Loader (BL) stages. Section 2 +discusses these in detail. The subsequent sections discuss the remaining +modifications for each BL stage in detail. + +This document should be read in conjunction with the ARM Trusted Firmware +[User Guide]. + + +2. Common modifications +------------------------ + +This section covers the modifications that should be made by the platform for +each BL stage to correctly port the firmware stack. They are categorized as +either mandatory or optional. + + +2.1 Common mandatory modifications +---------------------------------- +A platform port must enable the Memory Management Unit (MMU) with identity +mapped page tables, and enable both the instruction and data caches for each BL +stage. In the ARM FVP port, each BL stage configures the MMU in its platform- +specific architecture setup function, for example `blX_plat_arch_setup()`. + +Each platform must allocate a block of identity mapped secure memory with +Device-nGnRE attributes aligned to page boundary (4K) for each BL stage. This +memory is identified by the section name `tzfw_coherent_mem` so that its +possible for the firmware to place variables in it using the following C code +directive: + + __attribute__ ((section("tzfw_coherent_mem"))) + +Or alternatively the following assembler code directive: + + .section tzfw_coherent_mem + +The `tzfw_coherent_mem` section is used to allocate any data structures that are +accessed both when a CPU is executing with its MMU and caches enabled, and when +it's running with its MMU and caches disabled. Examples are given below. + +The following variables, functions and constants must be defined by the platform +for the firmware to work correctly. + + +### File : platform_def.h [mandatory] + +Each platform must ensure that a header file of this name is in the system +include path with the following constants defined. This may require updating the +list of `PLAT_INCLUDES` in the `platform.mk` file. In the ARM FVP port, this +file is found in [plat/fvp/include/platform_def.h]. + +* **#define : PLATFORM_LINKER_FORMAT** + + Defines the linker format used by the platform, for example + `elf64-littleaarch64` used by the FVP. + +* **#define : PLATFORM_LINKER_ARCH** + + Defines the processor architecture for the linker by the platform, for + example `aarch64` used by the FVP. + +* **#define : PLATFORM_STACK_SIZE** + + Defines the normal stack memory available to each CPU. This constant is used + by [plat/common/aarch64/platform_mp_stack.S] and + [plat/common/aarch64/platform_up_stack.S]. + +* **#define : PCPU_DV_MEM_STACK_SIZE** + + Defines the coherent stack memory available to each CPU. This constant is used + by [plat/common/aarch64/platform_mp_stack.S] and + [plat/common/aarch64/platform_up_stack.S]. + +* **#define : FIRMWARE_WELCOME_STR** + + Defines the character string printed by BL1 upon entry into the `bl1_main()` + function. + +* **#define : BL2_IMAGE_NAME** + + Name of the BL2 binary image on the host file-system. This name is used by + BL1 to load BL2 into secure memory from non-volatile storage. + +* **#define : BL31_IMAGE_NAME** + + Name of the BL3-1 binary image on the host file-system. This name is used by + BL2 to load BL3-1 into secure memory from platform storage. + +* **#define : BL33_IMAGE_NAME** + + Name of the BL3-3 binary image on the host file-system. This name is used by + BL2 to load BL3-3 into non-secure memory from platform storage. + +* **#define : PLATFORM_CACHE_LINE_SIZE** + + Defines the size (in bytes) of the largest cache line across all the cache + levels in the platform. + +* **#define : PLATFORM_CLUSTER_COUNT** + + Defines the total number of clusters implemented by the platform in the + system. + +* **#define : PLATFORM_CORE_COUNT** + + Defines the total number of CPUs implemented by the platform across all + clusters in the system. + +* **#define : PLATFORM_MAX_CPUS_PER_CLUSTER** + + Defines the maximum number of CPUs that can be implemented within a cluster + on the platform. + +* **#define : PRIMARY_CPU** + + Defines the `MPIDR` of the primary CPU on the platform. This value is used + after a cold boot to distinguish between primary and secondary CPUs. + +* **#define : TZROM_BASE** + + Defines the base address of secure ROM on the platform, where the BL1 binary + is loaded. This constant is used by the linker scripts to ensure that the + BL1 image fits into the available memory. + +* **#define : TZROM_SIZE** + + Defines the size of secure ROM on the platform. This constant is used by the + linker scripts to ensure that the BL1 image fits into the available memory. + +* **#define : TZRAM_BASE** + + Defines the base address of the secure RAM on platform, where the data + section of the BL1 binary is loaded. The BL2 and BL3-1 images are also + loaded in this secure RAM region. This constant is used by the linker + scripts to ensure that the BL1 data section and BL2/BL3-1 binary images fit + into the available memory. + +* **#define : TZRAM_SIZE** + + Defines the size of the secure RAM on the platform. This constant is used by + the linker scripts to ensure that the BL1 data section and BL2/BL3-1 binary + images fit into the available memory. + +* **#define : BL1_RO_BASE** + + Defines the base address in secure ROM where BL1 originally lives. Must be + aligned on a page-size boundary. + +* **#define : BL1_RO_LIMIT** + + Defines the maximum address in secure ROM that BL1's actual content (i.e. + excluding any data section allocated at runtime) can occupy. + +* **#define : BL1_RW_BASE** + + Defines the base address in secure RAM where BL1's read-write data will live + at runtime. Must be aligned on a page-size boundary. + +* **#define : BL1_RW_LIMIT** + + Defines the maximum address in secure RAM that BL1's read-write data can + occupy at runtime. + +* **#define : BL2_BASE** + + Defines the base address in secure RAM where BL1 loads the BL2 binary image. + Must be aligned on a page-size boundary. + +* **#define : BL2_LIMIT** + + Defines the maximum address in secure RAM that the BL2 image can occupy. + +* **#define : BL31_BASE** + + Defines the base address in secure RAM where BL2 loads the BL3-1 binary + image. Must be aligned on a page-size boundary. + +* **#define : BL31_LIMIT** + + Defines the maximum address in secure RAM that the BL3-1 image can occupy. + +* **#define : NS_IMAGE_OFFSET** + + Defines the base address in non-secure DRAM where BL2 loads the BL3-3 binary + image. Must be aligned on a page-size boundary. + +If the BL3-2 image is supported by the platform, the following constants must +be defined as well: + +* **#define : TSP_SEC_MEM_BASE** + + Defines the base address of the secure memory used by the BL3-2 image on the + platform. + +* **#define : TSP_SEC_MEM_SIZE** + + Defines the size of the secure memory used by the BL3-2 image on the + platform. + +* **#define : BL32_BASE** + + Defines the base address in secure memory where BL2 loads the BL3-2 binary + image. Must be inside the secure memory identified by `TSP_SEC_MEM_BASE` and + `TSP_SEC_MEM_SIZE` constants. Must also be aligned on a page-size boundary. + +* **#define : BL32_LIMIT** + + Defines the maximum address that the BL3-2 image can occupy. Must be inside + the secure memory identified by `TSP_SEC_MEM_BASE` and `TSP_SEC_MEM_SIZE` + constants. + + +### File : plat_macros.S [mandatory] + +Each platform must ensure a file of this name is in the system include path with +the following macro defined. In the ARM FVP port, this file is found in +[plat/fvp/include/plat_macros.S]. + +* **Macro : plat_print_gic_regs** + + This macro allows the crash reporting routine to print GIC registers + in case of an unhandled IRQ or FIQ in BL3-1. This aids in debugging and + this macro can be defined to be empty in case GIC register reporting is + not desired. + +### Other mandatory modifications + +The following mandatory modifications may be implemented in any file +the implementer chooses. In the ARM FVP port, they are implemented in +[plat/fvp/aarch64/plat_common.c]. + +* **Function : uint64_t plat_get_syscnt_freq(void)** + + This function is used by the architecture setup code to retrieve the + counter frequency for the CPU's generic timer. This value will be + programmed into the `CNTFRQ_EL0` register. + In the ARM FVP port, it returns the base frequency of the system counter, + which is retrieved from the first entry in the frequency modes table. + + +2.2 Handling Reset +------------------ + +BL1 by default implements the reset vector where execution starts from a cold +or warm boot. BL3-1 can be optionally set as a reset vector using the +RESET_TO_BL31 make variable. + +For each CPU, the reset vector code is responsible for the following tasks: + +1. Distinguishing between a cold boot and a warm boot. + +2. In the case of a cold boot and the CPU being a secondary CPU, ensuring that + the CPU is placed in a platform-specific state until the primary CPU + performs the necessary steps to remove it from this state. + +3. In the case of a warm boot, ensuring that the CPU jumps to a platform- + specific address in the BL3-1 image in the same processor mode as it was + when released from reset. + +The following functions need to be implemented by the platform port to enable +reset vector code to perform the above tasks. + + +### Function : platform_get_entrypoint() [mandatory] + + Argument : unsigned long + Return : unsigned int + +This function is called with the `SCTLR.M` and `SCTLR.C` bits disabled. The CPU +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's a warm reset then it returns the entrypoint into the +BL3-1 image that the CPU must jump to. If it's a cold reset then this function +must return zero. + +This function is also responsible for implementing a platform-specific mechanism +to handle the condition where the CPU 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. + +This function fulfills requirement 1 and 3 listed above. + + +### Function : plat_secondary_cold_boot_setup() [mandatory] + + Argument : void + Return : void + +This function is called with the MMU and data caches disabled. It is responsible +for placing the executing secondary CPU in a platform-specific state until the +primary CPU performs the necessary actions to bring it out of that state and +allow entry into the OS. + +In the ARM FVP port, each secondary CPU powers itself off. The primary CPU is +responsible for powering up the secondary CPU when normal world software +requires them. + +This function fulfills requirement 2 above. + + +### Function : platform_mem_init() [mandatory] + + Argument : void + Return : void + +This function is called before any access to data is made by the firmware, in +order to carry out any essential memory initialization. + +The ARM FVP port uses this function to initialize the mailbox memory used for +providing the warm-boot entry-point addresses. + + + +2.3 Common optional modifications +--------------------------------- + +The following are helper functions implemented by the firmware that perform +common platform-specific tasks. A platform may choose to override these +definitions. + + +### Function : platform_get_core_pos() + + Argument : unsigned long + Return : int + +A platform may need to convert the `MPIDR` of a CPU to an absolute number, which +can be used as a CPU-specific linear index into blocks of memory (for example +while allocating per-CPU stacks). This routine contains a simple mechanism +to perform this conversion, using the assumption that each cluster contains a +maximum of 4 CPUs: + + 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_coherent_stack() + + Argument : unsigned long + Return : void + +A platform may need stack memory that is coherent with main memory to perform +certain operations like: + +* Turning the MMU on, or +* Flushing caches prior to powering down a CPU or cluster. + +Each BL stage allocates this coherent stack memory for each CPU in the +`tzfw_coherent_mem` section. + +This function sets the current stack pointer to the coherent stack that +has been allocated for the CPU specified by MPIDR. For BL images that only +require a stack for the primary CPU the parameter is ignored. The size of +the stack allocated to each CPU is specified by the platform defined constant +`PCPU_DV_MEM_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_is_primary_cpu() + + Argument : unsigned long + Return : unsigned int + +This function identifies a CPU by its `MPIDR`, which is passed as the argument, +to determine whether this CPU is the primary CPU or a secondary CPU. A return +value of zero indicates that the CPU is not the primary CPU, while a non-zero +return value indicates that the CPU is the primary CPU. + + +### 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 CPU specificed by MPIDR. For BL images that only +require a stack for the primary CPU the parameter is ignored. The size of +the stack allocated to each CPU 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 CPU specificed by MPIDR. For BL images that only +require a stack for the primary CPU the parameter is ignored. The size of +the stack allocated to each CPU 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 : plat_report_exception() + + Argument : unsigned int + Return : void + +A platform may need to report various information about its status when an +exception is taken, for example the current exception level, the CPU security +state (secure/non-secure), the exception type, and so on. This function is +called in the following circumstances: + +* In BL1, whenever an exception is taken. +* In BL2, whenever an exception is taken. + +The default implementation doesn't do anything, to avoid making assumptions +about the way the platform displays its status information. + +This function receives the exception type as its argument. Possible values for +exceptions types are listed in the [include/runtime_svc.h] header file. Note +that these constants are not related to any architectural exception code; they +are just an ARM Trusted Firmware convention. + + +3. Modifications specific to a Boot Loader stage +------------------------------------------------- + +3.1 Boot Loader Stage 1 (BL1) +----------------------------- + +BL1 implements the reset vector where execution starts from after a cold or +warm boot. For each CPU, BL1 is responsible for the following tasks: + +1. Handling the reset as described in section 2.2 + +2. In the case of a cold boot and the CPU being the primary CPU, ensuring that + only this CPU executes the remaining BL1 code, including loading and passing + control to the BL2 stage. + +3. Loading the BL2 image from non-volatile storage into secure memory at the + address specified by the platform defined constant `BL2_BASE`. + +4. Populating a `meminfo` structure with the following information in memory, + accessible by BL2 immediately upon entry. + + meminfo.total_base = Base address of secure RAM visible to BL2 + meminfo.total_size = Size of secure RAM visible to BL2 + meminfo.free_base = Base address of secure RAM available for + allocation to BL2 + meminfo.free_size = Size of secure RAM available for allocation to BL2 + + BL1 places this `meminfo` structure at the beginning of the free memory + available for its use. Since BL1 cannot allocate memory dynamically at the + moment, its free memory will be available for BL2's use as-is. However, this + means that BL2 must read the `meminfo` structure before it starts using its + free memory (this is discussed in Section 3.2). + + In future releases of the ARM Trusted Firmware it will be possible for + the platform to decide where it wants to place the `meminfo` structure for + BL2. + + BL1 implements the `init_bl2_mem_layout()` function to populate the + BL2 `meminfo` structure. The platform may override this implementation, for + example if the platform wants to restrict the amount of memory visible to + BL2. Details of how to do this are given below. + +The following functions need to be implemented by the platform port to enable +BL1 to perform the above tasks. + + +### Function : bl1_plat_arch_setup() [mandatory] + + Argument : void + Return : void + +This function performs any platform-specific and architectural setup that the +platform requires. Platform-specific setup might include configuration of +memory controllers, configuration of the interconnect to allow the cluster +to service cache snoop requests from another cluster, and so on. + +In the ARM FVP port, this function enables CCI snoops into the cluster that the +primary CPU is part of. It also enables the MMU. + +This function helps fulfill requirement 2 above. + + +### Function : bl1_platform_setup() [mandatory] + + Argument : void + Return : void + +This function executes with the MMU and data caches enabled. It is responsible +for performing any remaining platform-specific setup that can occur after the +MMU and data cache have been enabled. + +This function is also responsible for initializing the storage abstraction layer +which is used to load further bootloader images. + +This function helps fulfill requirement 3 above. + + +### Function : bl1_plat_sec_mem_layout() [mandatory] + + Argument : void + Return : meminfo * + +This function should only be called on the cold boot path. It executes with the +MMU and data caches enabled. The pointer returned by this function must point to +a `meminfo` structure containing the extents and availability of secure RAM for +the BL1 stage. + + meminfo.total_base = Base address of secure RAM visible to BL1 + meminfo.total_size = Size of secure RAM visible to BL1 + meminfo.free_base = Base address of secure RAM available for allocation + to BL1 + meminfo.free_size = Size of secure RAM available for allocation to BL1 + +This information is used by BL1 to load the BL2 image in secure RAM. BL1 also +populates a similar structure to tell BL2 the extents of memory available for +its own use. + +This function helps fulfill requirement 3 above. + + +### Function : init_bl2_mem_layout() [optional] + + Argument : meminfo *, meminfo *, unsigned int, unsigned long + Return : void + +BL1 needs to tell the next stage the amount of secure RAM available +for it to use. This information is populated in a `meminfo` +structure. + +Depending upon where BL2 has been loaded in secure RAM (determined by +`BL2_BASE`), BL1 calculates the amount of free memory available for BL2 to use. +BL1 also ensures that its data sections resident in secure RAM are not visible +to BL2. An illustration of how this is done in the ARM FVP port is given in the +[User Guide], in the Section "Memory layout on Base FVP". + + +### Function : bl1_plat_set_bl2_ep_info() [mandatory] + + Argument : image_info *, entry_point_info * + Return : void + +This function is called after loading BL2 image and it can be used to overwrite +the entry point set by loader and also set the security state and SPSR which +represents the entry point system state for BL2. + +On FVP, we are setting the security state and the SPSR for the BL2 entrypoint + + +3.2 Boot Loader Stage 2 (BL2) +----------------------------- + +The BL2 stage is executed only by the primary CPU, which is determined in BL1 +using the `platform_is_primary_cpu()` function. BL1 passed control to BL2 at +`BL2_BASE`. BL2 executes in Secure EL1 and is responsible for: + +1. Loading the BL3-1 binary image into secure RAM from non-volatile storage. To + load the BL3-1 image, BL2 makes use of the `meminfo` structure passed to it + by BL1. This structure allows BL2 to calculate how much secure RAM is + available for its use. The platform also defines the address in secure RAM + where BL3-1 is loaded through the constant `BL31_BASE`. BL2 uses this + information to determine if there is enough memory to load the BL3-1 image. + +2. Loading the normal world BL3-3 binary image into non-secure DRAM from + platform storage and arranging for BL3-1 to pass control to this image. This + address is determined using the `plat_get_ns_image_entrypoint()` function + described below. + +3. BL2 populates an `entry_point_info` structure in memory provided by the + platform with information about how BL3-1 should pass control to the + other BL images. + +4. (Optional) Loading the BL3-2 binary image (if present) from platform + provided non-volatile storage. To load the BL3-2 image, BL2 makes use of + the `meminfo` returned by the `bl2_plat_get_bl32_meminfo()` function. + The platform also defines the address in memory where BL3-2 is loaded + through the optional constant `BL32_BASE`. BL2 uses this information + to determine if there is enough memory to load the BL3-2 image. + If `BL32_BASE` is not defined then this and the next step is not performed. + +5. (Optional) Arranging to pass control to the BL3-2 image (if present) that + has been pre-loaded at `BL32_BASE`. BL2 populates an `entry_point_info` + structure in memory provided by the platform with information about how + BL3-1 should pass control to the BL3-2 image. + +The following functions must be implemented by the platform port to enable BL2 +to perform the above tasks. + + +### Function : bl2_early_platform_setup() [mandatory] + + Argument : meminfo * + Return : void + +This function executes with the MMU and data caches disabled. It is only called +by the primary CPU. The arguments to this function is the address of the +`meminfo` structure populated by BL1. + +The platform must copy the contents of the `meminfo` structure into a private +variable as the original memory may be subsequently overwritten by BL2. The +copied structure is made available to all BL2 code through the +`bl2_plat_sec_mem_layout()` function. + + +### Function : bl2_plat_arch_setup() [mandatory] + + Argument : void + Return : void + +This function executes with the MMU and data caches disabled. It is only called +by the primary CPU. + +The purpose of this function is to perform any architectural initialization +that varies across platforms, for example enabling the MMU (since the memory +map differs across platforms). + + +### Function : bl2_platform_setup() [mandatory] + + Argument : void + Return : void + +This function may execute with the MMU and data caches enabled if the platform +port does the necessary initialization in `bl2_plat_arch_setup()`. It is only +called by the primary CPU. + +The purpose of this function is to perform any platform initialization +specific to BL2. Platform security components are configured if required. +For the Base FVP the TZC-400 TrustZone controller is configured to only +grant non-secure access to DRAM. This avoids aliasing between secure and +non-secure accesses in the TLB and cache - secure execution states can use +the NS attributes in the MMU translation tables to access the DRAM. + +This function is also responsible for initializing the storage abstraction layer +which is used to load further bootloader images. + + +### Function : bl2_plat_sec_mem_layout() [mandatory] + + Argument : void + Return : meminfo * + +This function should only be called on the cold boot path. It may execute with +the MMU and data caches enabled if the platform port does the necessary +initialization in `bl2_plat_arch_setup()`. It is only called by the primary CPU. + +The purpose of this function is to return a pointer to a `meminfo` structure +populated with the extents of secure RAM available for BL2 to use. See +`bl2_early_platform_setup()` above. + + +### Function : bl2_plat_get_bl31_params() [mandatory] + + Argument : void + Return : bl31_params * + +BL2 platform code needs to return a pointer to a `bl31_params` structure it +will use for passing information to BL3-1. The `bl31_params` structure carries +the following information. + - Header describing the version information for interpreting the bl31_param + structure + - Information about executing the BL3-3 image in the `bl33_ep_info` field + - Information about executing the BL3-2 image in the `bl32_ep_info` field + - Information about the type and extents of BL3-1 image in the + `bl31_image_info` field + - Information about the type and extents of BL3-2 image in the + `bl32_image_info` field + - Information about the type and extents of BL3-3 image in the + `bl33_image_info` field + +The memory pointed by this structure and its sub-structures should be +accessible from BL3-1 initialisation code. BL3-1 might choose to copy the +necessary content, or maintain the structures until BL3-3 is initialised. + + +### Funtion : bl2_plat_get_bl31_ep_info() [mandatory] + + Argument : void + Return : entry_point_info * + +BL2 platform code returns a pointer which is used to populate the entry point +information for BL3-1 entry point. The location pointed by it should be +accessible from BL1 while processing the synchronous exception to run to BL3-1. + +On FVP this is allocated inside an bl2_to_bl31_params_mem structure which +is allocated at an address pointed by PARAMS_BASE. + + +### Function : bl2_plat_set_bl31_ep_info() [mandatory] + + Argument : image_info *, entry_point_info * + Return : void + +This function is called after loading BL3-1 image and it can be used to +overwrite the entry point set by loader and also set the security state +and SPSR which represents the entry point system state for BL3-1. + +On FVP, we are setting the security state and the SPSR for the BL3-1 +entrypoint. + +### Function : bl2_plat_set_bl32_ep_info() [mandatory] + + Argument : image_info *, entry_point_info * + Return : void + +This function is called after loading BL3-2 image and it can be used to +overwrite the entry point set by loader and also set the security state +and SPSR which represents the entry point system state for BL3-2. + +On FVP, we are setting the security state and the SPSR for the BL3-2 +entrypoint + +### Function : bl2_plat_set_bl33_ep_info() [mandatory] + + Argument : image_info *, entry_point_info * + Return : void + +This function is called after loading BL3-3 image and it can be used to +overwrite the entry point set by loader and also set the security state +and SPSR which represents the entry point system state for BL3-3. + +On FVP, we are setting the security state and the SPSR for the BL3-3 +entrypoint + +### Function : bl2_plat_get_bl32_meminfo() [mandatory] + + Argument : meminfo * + Return : void + +This function is used to get the memory limits where BL2 can load the +BL3-2 image. The meminfo provided by this is used by load_image() to +validate whether the BL3-2 image can be loaded with in the given +memory from the given base. + +### Function : bl2_plat_get_bl33_meminfo() [mandatory] + + Argument : meminfo * + Return : void + +This function is used to get the memory limits where BL2 can load the +BL3-3 image. The meminfo provided by this is used by load_image() to +validate whether the BL3-3 image can be loaded with in the given +memory from the given base. + +### Function : bl2_plat_flush_bl31_params() [mandatory] + + Argument : void + Return : void + +Once BL2 has populated all the structures that needs to be read by BL1 +and BL3-1 including the bl31_params structures and its sub-structures, +the bl31_ep_info structure and any platform specific data. It flushes +all these data to the main memory so that it is available when we jump to +later Bootloader stages with MMU off + +### Function : plat_get_ns_image_entrypoint() [mandatory] + + Argument : void + Return : unsigned long + +As previously described, BL2 is responsible for arranging for control to be +passed to a normal world BL image through BL3-1. This function returns the +entrypoint of that image, which BL3-1 uses to jump to it. + +BL2 is responsible for loading the normal world BL3-3 image (e.g. UEFI). + + +3.2 Boot Loader Stage 3-1 (BL3-1) +--------------------------------- + +During cold boot, the BL3-1 stage is executed only by the primary CPU. This is +determined in BL1 using the `platform_is_primary_cpu()` function. BL1 passes +control to BL3-1 at `BL31_BASE`. During warm boot, BL3-1 is executed by all +CPUs. BL3-1 executes at EL3 and is responsible for: + +1. Re-initializing all architectural and platform state. Although BL1 performs + some of this initialization, BL3-1 remains resident in EL3 and must ensure + that EL3 architectural and platform state is completely initialized. It + should make no assumptions about the system state when it receives control. + +2. Passing control to a normal world BL image, pre-loaded at a platform- + specific address by BL2. BL3-1 uses the `entry_point_info` structure that BL2 + populated in memory to do this. + +3. Providing runtime firmware services. Currently, BL3-1 only implements a + subset of the Power State Coordination Interface (PSCI) API as a runtime + service. See Section 3.3 below for details of porting the PSCI + implementation. + +4. Optionally passing control to the BL3-2 image, pre-loaded at a platform- + specific address by BL2. BL3-1 exports a set of apis that allow runtime + services to specify the security state in which the next image should be + executed and run the corresponding image. BL3-1 uses the `entry_point_info` + structure populated by BL2 to do this. + +If BL3-1 is a reset vector, It also needs to handle the reset as specified in +section 2.2 before the tasks described above. + +The following functions must be implemented by the platform port to enable BL3-1 +to perform the above tasks. + + +### Function : bl31_early_platform_setup() [mandatory] + + Argument : bl31_params *, void * + Return : void + +This function executes with the MMU and data caches disabled. It is only called +by the primary CPU. The arguments to this function are: + +* The address of the `bl31_params` structure populated by BL2. +* An opaque pointer that the platform may use as needed. + +The platform can copy the contents of the `bl31_params` structure and its +sub-structures into private variables if the original memory may be +subsequently overwritten by BL3-1 and similarly the `void *` pointing +to the platform data also needs to be saved. + +On the ARM FVP port, BL2 passes a pointer to a `bl31_params` structure populated +in the secure DRAM at address `0x6000000` in the bl31_params * argument and it +does not use opaque pointer mentioned earlier. BL3-1 does not copy this +information to internal data structures as it guarantees that the secure +DRAM memory will not be overwritten. It maintains an internal reference to this +information in the `bl2_to_bl31_params` variable. + +### Function : bl31_plat_arch_setup() [mandatory] + + Argument : void + Return : void + +This function executes with the MMU and data caches disabled. It is only called +by the primary CPU. + +The purpose of this function is to perform any architectural initialization +that varies across platforms, for example enabling the MMU (since the memory +map differs across platforms). + + +### Function : bl31_platform_setup() [mandatory] + + Argument : void + Return : void + +This function may execute with the MMU and data caches enabled if the platform +port does the necessary initialization in `bl31_plat_arch_setup()`. It is only +called by the primary CPU. + +The purpose of this function is to complete platform initialization so that both +BL3-1 runtime services and normal world software can function correctly. + +The ARM FVP port does the following: +* Initializes the generic interrupt controller. +* Configures the CLCD controller. +* Enables system-level implementation of the generic timer counter. +* Grants access to the system counter timer module +* Initializes the FVP power controller device +* Detects the system topology. + + +### Function : bl31_get_next_image_info() [mandatory] + + Argument : unsigned int + Return : entry_point_info * + +This function may execute with the MMU and data caches enabled if the platform +port does the necessary initializations in `bl31_plat_arch_setup()`. + +This function is called by `bl31_main()` to retrieve information provided by +BL2 for the next image in the security state specified by the argument. BL3-1 +uses this information to pass control to that image in the specified security +state. This function must return a pointer to the `entry_point_info` structure +(that was copied during `bl31_early_platform_setup()`) if the image exists. It +should return NULL otherwise. + + +3.3 Power State Coordination Interface (in BL3-1) +------------------------------------------------ + +The ARM Trusted Firmware's implementation of the PSCI API is based around the +concept of an _affinity instance_. Each _affinity instance_ can be uniquely +identified in a system by a CPU ID (the processor `MPIDR` is used in the PSCI +interface) and an _affinity level_. A processing element (for example, a +CPU) is at level 0. If the CPUs in the system are described in a tree where the +node above a CPU is a logical grouping of CPUs that share some state, then +affinity level 1 is that group of CPUs (for example, a cluster), and affinity +level 2 is a group of clusters (for example, the system). The implementation +assumes that the affinity level 1 ID can be computed from the affinity level 0 +ID (for example, a unique cluster ID can be computed from the CPU ID). The +current implementation computes this on the basis of the recommended use of +`MPIDR` affinity fields in the ARM Architecture Reference Manual. + +BL3-1's platform initialization code exports a pointer to the platform-specific +power management operations required for the PSCI implementation to function +correctly. This information is populated in the `plat_pm_ops` structure. The +PSCI implementation calls members of the `plat_pm_ops` structure for performing +power management operations for each affinity instance. For example, the target +CPU is specified by its `MPIDR` in a PSCI `CPU_ON` call. The `affinst_on()` +handler (if present) is called for each affinity instance as the PSCI +implementation powers up each affinity level implemented in the `MPIDR` (for +example, CPU, cluster and system). + +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 CPU. + +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 2 CPUs and the second cluster implements 4 +CPUs, 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 CPU. + +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 4 CPUs and +another CPU implemented directly on the interconnect with the cluster. The +`MPIDR`s of the cluster would range from `0x0-0x3`. The `MPIDR` of the single +CPU would be 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 CPU in the +topology tree. Hence it is marked as `PSCI_AFF_ABSENT`. + + +### Function : plat_get_max_afflvl() [mandatory] + + Argument : void + 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 CPU. + +This function is called by the PSCI implementation both during cold and warm +boot, to determine the maximum affinity level that the power management +operations should apply to. ARMv8-A has support for 4 affinity levels. It is +likely that hardware will implement fewer affinity levels. This function 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 CPUs. It reports the maximum affinity +level as 1, resulting in PSCI power control up to the cluster level. + + +### Function : platform_setup_pm() [mandatory] + + Argument : 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 CPU. + +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 BL3-1's private `plat_pm_ops` structure. + +A description of each member of this structure is given below. Please refer to +the ARM FVP specific implementation of these handlers in [plat/fvp/plat_pm.c] +as an example. A platform port may choose not implement some of the power +management operations. For example, the ARM FVP port does not implement the +`affinst_standby()` function. + +#### plat_pm_ops.affinst_standby() + +Perform the platform-specific setup to enter the standby state indicated by the +passed argument. + +#### 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` (fourth argument). The +`state` (fifth 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 CPU, the cluster that contains this CPU 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). + +#### plat_pm_ops.affinst_off() + +Perform the platform specific setup to power off an affinity instance in the +`MPIDR` of the calling CPU. It is called by the PSCI `CPU_OFF` API +implementation. + +The `MPIDR` (first argument), `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 CPU is the last powered on CPU in the cluster, after powering down +affinity level 0 (CPU), the platform port should power down affinity level 1 +(the cluster) as well. + +This function is called with coherent stacks. This allows the PSCI +implementation to flush caches at a given affinity level without running into +stale stack state after turning off the caches. On ARMv8-A cache hits do not +occur after the cache has been turned off. + +#### plat_pm_ops.affinst_suspend() + +Perform the platform specific setup to power off an affinity instance in the +`MPIDR` of the calling CPU. It is called by the PSCI `CPU_SUSPEND` API +implementation. + +The `MPIDR` (first argument), `affinity level` (third argument) and `state` +(fifth 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 CPU is the last powered on CPU in the cluster, after powering down +affinity level 0 (CPU), the platform port should power down affinity level 1 +(the cluster) as well. + +The difference between turning an affinity instance off versus suspending it +is that in the former case, the affinity instance is expected to re-initialize +its state when its 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 its powered on (see +`affinst_suspend_finish()`). + +This function is called with coherent stacks. This allows the PSCI +implementation to flush caches at a given affinity level without running into +stale stack state after turning off the caches. On ARMv8-A cache hits do not +occur after the cache has been turned off. + +#### plat_pm_ops.affinst_on_finish() + +This function is called by the PSCI implementation after the calling CPU 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 CPU to enter the normal world and also provide secure runtime firmware +services. + +The `MPIDR` (first argument), `affinity level` (second argument) and `state` +(third argument) have a similar meaning as described in the previous operations. + +This function is called with coherent stacks. This allows the PSCI +implementation to flush caches at a given affinity level without running into +stale stack state after turning off the caches. On ARMv8-A cache hits do not +occur after the cache has been turned off. + +#### plat_pm_ops.affinst_on_suspend() + +This function is called by the PSCI implementation after the calling CPU is +powered on and released from reset in response to an asynchronous wakeup +event, for example a timer interrupt that was programmed by the CPU during the +`CPU_SUSPEND` call. It performs the platform-specific setup required to +restore the saved state for this CPU to resume execution in the normal world +and also provide secure runtime firmware services. + +The `MPIDR` (first argument), `affinity level` (second argument) and `state` +(third argument) have a similar meaning as described in the previous operations. + +This function is called with coherent stacks. This allows the PSCI +implementation to flush caches at a given affinity level without running into +stale stack state after turning off the caches. On ARMv8-A cache hits do not +occur after the cache has been turned off. + +BL3-1 platform initialization code must also detect the system topology and +the state of each affinity instance in the topology. This information is +critical for the PSCI runtime service to function correctly. More details are +provided in the description of the `plat_get_aff_count()` and +`plat_get_aff_state()` functions above. + +3.4 Interrupt Management framework (in BL3-1) +---------------------------------------------- +BL3-1 implements an Interrupt Management Framework (IMF) to manage interrupts +generated in either security state and targeted to EL1 or EL2 in the non-secure +state or EL3/S-EL1 in the secure state. The design of this framework is +described in the [IMF Design Guide] + +A platform should export the following APIs to support the IMF. The following +text briefly describes each api and its implementation on the FVP port. The API +implementation depends upon the type of interrupt controller present in the +platform. The FVP implements an ARM Generic Interrupt Controller (ARM GIC) as +per the version 2.0 of the [ARM GIC Architecture Specification] + +### Function : plat_interrupt_type_to_line() [mandatory] + + Argument : uint32_t, uint32_t + Return : uint32_t + +The ARM processor signals an interrupt exception either through the IRQ or FIQ +interrupt line. The specific line that is signaled depends on how the interrupt +controller (IC) reports different interrupt types from an execution context in +either security state. The IMF uses this API to determine which interrupt line +the platform IC uses to signal each type of interrupt supported by the framework +from a given security state. + +The first parameter will be one of the `INTR_TYPE_*` values (see [IMF Design +Guide]) indicating the target type of the interrupt, the second parameter is the +security state of the originating execution context. The return result is the +bit position in the `SCR_EL3` register of the respective interrupt trap: IRQ=1, +FIQ=2. + +The FVP port configures the ARM GIC to signal S-EL1 interrupts as FIQs and +Non-secure interrupts as IRQs from either security state. + + +### Function : plat_ic_get_pending_interrupt_type() [mandatory] + + Argument : void + Return : uint32_t + +This API returns the type of the highest priority pending interrupt at the +platform IC. The IMF uses the interrupt type to retrieve the corresponding +handler function. `INTR_TYPE_INVAL` is returned when there is no interrupt +pending. The valid interrupt types that can be returned are `INTR_TYPE_EL3`, +`INTR_TYPE_S_EL1` and `INTR_TYPE_NS`. + +The FVP port reads the _Highest Priority Pending Interrupt Register_ +(`GICC_HPPIR`) to determine the id of the pending interrupt. The type of interrupt +depends upon the id value as follows. + +1. id < 1022 is reported as a S-EL1 interrupt +2. id = 1022 is reported as a Non-secure interrupt. +3. id = 1023 is reported as an invalid interrupt type. + + +### Function : plat_ic_get_pending_interrupt_id() [mandatory] + + Argument : void + Return : uint32_t + +This API returns the id of the highest priority pending interrupt at the +platform IC. The IMF passes the id returned by this API to the registered +handler for the pending interrupt if the `IMF_READ_INTERRUPT_ID` build time flag +is set. INTR_ID_UNAVAILABLE is returned when there is no interrupt pending. + +The FVP port reads the _Highest Priority Pending Interrupt Register_ +(`GICC_HPPIR`) to determine the id of the pending interrupt. The id that is +returned by API depends upon the value of the id read from the interrupt +controller as follows. + +1. id < 1022. id is returned as is. +2. id = 1022. The _Aliased Highest Priority Pending Interrupt Register_ + (`GICC_AHPPIR`) is read to determine the id of the non-secure interrupt. This + id is returned by the API. +3. id = 1023. `INTR_ID_UNAVAILABLE` is returned. + + +### Function : plat_ic_acknowledge_interrupt() [mandatory] + + Argument : void + Return : uint32_t + +This API is used by the CPU to indicate to the platform IC that processing of +the highest pending interrupt has begun. It should return the id of the +interrupt which is being processed. + +The FVP port reads the _Interrupt Acknowledge Register_ (`GICC_IAR`). This +changes the state of the highest priority pending interrupt from pending to +active in the interrupt controller. It returns the value read from the +`GICC_IAR`. This value is the id of the interrupt whose state has been changed. + +The TSP uses this API to start processing of the secure physical timer +interrupt. + + +### Function : plat_ic_end_of_interrupt() [mandatory] + + Argument : uint32_t + Return : void + +This API is used by the CPU to indicate to the platform IC that processing of +the interrupt corresponding to the id (passed as the parameter) has +finished. The id should be the same as the id returned by the +`plat_ic_acknowledge_interrupt()` API. + +The FVP port writes the id to the _End of Interrupt Register_ +(`GICC_EOIR`). This deactivates the corresponding interrupt in the interrupt +controller. + +The TSP uses this API to finish processing of the secure physical timer +interrupt. + + +### Function : plat_ic_get_interrupt_type() [mandatory] + + Argument : uint32_t + Return : uint32_t + +This API returns the type of the interrupt id passed as the parameter. +`INTR_TYPE_INVAL` is returned if the id is invalid. If the id is valid, a valid +interrupt type (one of `INTR_TYPE_EL3`, `INTR_TYPE_S_EL1` and `INTR_TYPE_NS`) is +returned depending upon how the interrupt has been configured by the platform +IC. + +The FVP port configures S-EL1 interrupts as Group0 interrupts and Non-secure +interrupts as Group1 interrupts. It reads the group value corresponding to the +interrupt id from the relevant _Interrupt Group Register_ (`GICD_IGROUPRn`). It +uses the group value to determine the type of interrupt. + + +4. C Library +------------- + +To avoid subtle toolchain behavioral dependencies, the header files provided +by the compiler are not used. The software is built with the `-nostdinc` flag +to ensure no headers are included from the toolchain inadvertently. Instead the +required headers are included in the ARM Trusted Firmware source tree. The +library only contains those C library definitions required by the local +implementation. If more functionality is required, the needed library functions +will need to be added to the local implementation. + +Versions of [FreeBSD] headers can be found in `include/stdlib`. Some of these +headers have been cut down in order to simplify the implementation. In order to +minimize changes to the header files, the [FreeBSD] layout has been maintained. +The generic C library definitions can be found in `include/stdlib` with more +system and machine specific declarations in `include/stdlib/sys` and +`include/stdlib/machine`. + +The local C library implementations can be found in `lib/stdlib`. In order to +extend the C library these files may need to be modified. It is recommended to +use a release version of [FreeBSD] as a starting point. + +The C library header files in the [FreeBSD] source tree are located in the +`include` and `sys/sys` directories. [FreeBSD] machine specific definitions +can be found in the `sys/<machine-type>` directories. These files define things +like 'the size of a pointer' and 'the range of an integer'. Since an AArch64 +port for [FreeBSD] does not yet exist, the machine specific definitions are +based on existing machine types with similar properties (for example SPARC64). + +Where possible, C library function implementations were taken from [FreeBSD] +as found in the `lib/libc` directory. + +A copy of the [FreeBSD] sources can be downloaded with `git`. + + git clone git://github.com/freebsd/freebsd.git -b origin/release/9.2.0 + + +5. Storage abstraction layer +----------------------------- + +In order to improve platform independence and portability an storage abstraction +layer is used to load data from non-volatile platform storage. + +Each platform should register devices and their drivers via the Storage layer. +These drivers then need to be initialized by bootloader phases as +required in their respective `blx_platform_setup()` functions. Currently +storage access is only required by BL1 and BL2 phases. The `load_image()` +function uses the storage layer to access non-volatile platform storage. + +It is mandatory to implement at least one storage driver. For the FVP the +Firmware Image Package(FIP) driver is provided as the default means to load data +from storage (see the "Firmware Image Package" section in the [User Guide]). +The storage layer is described in the header file `include/io_storage.h`. The +implementation of the common library is in `lib/io_storage.c` and the driver +files are located in `drivers/io/`. + +Each IO driver must provide `io_dev_*` structures, as described in +`drivers/io/io_driver.h`. These are returned via a mandatory registration +function that is called on platform initialization. The semi-hosting driver +implementation in `io_semihosting.c` can be used as an example. + +The Storage layer provides mechanisms to initialize storage devices before +IO operations are called. The basic operations supported by the layer +include `open()`, `close()`, `read()`, `write()`, `size()` and `seek()`. +Drivers do not have to implement all operations, but each platform must +provide at least one driver for a device capable of supporting generic +operations such as loading a bootloader image. + +The current implementation only allows for known images to be loaded by the +firmware. These images are specified by using their names, as defined in +[include/plat/common/platform.h]. The platform layer (`plat_get_image_source()`) +then returns a reference to a device and a driver-specific `spec` which will be +understood by the driver to allow access to the image data. + +The layer is designed in such a way that is it possible to chain drivers with +other drivers. For example, file-system drivers may be implemented on top of +physical block devices, both represented by IO devices with corresponding +drivers. In such a case, the file-system "binding" with the block device may +be deferred until the file-system device is initialised. + +The abstraction currently depends on structures being statically allocated +by the drivers and callers, as the system does not yet provide a means of +dynamically allocating memory. This may also have the affect of limiting the +amount of open resources per driver. + + +- - - - - - - - - - - - - - - - - - - - - - - - - - + +_Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved._ + + +[ARM GIC Architecture Specification]: http://arminfo.emea.arm.com/help/topic/com.arm.doc.ihi0048b/IHI0048B_gic_architecture_specification.pdf +[IMF Design Guide]: interrupt-framework-design.md +[User Guide]: user-guide.md +[FreeBSD]: http://www.freebsd.org + +[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 +[plat/fvp/include/platform_def.h]: ../plat/fvp/include/platform_def.h +[plat/fvp/include/plat_macros.S]: ../plat/fvp/include/plat_macros.S +[plat/fvp/aarch64/plat_common.c]: ../plat/fvp/aarch64/plat_common.c +[plat/fvp/plat_pm.c]: ../plat/fvp/plat_pm.c +[include/runtime_svc.h]: ../include/runtime_svc.h +[include/plat/common/platform.h]: ../include/plat/common/platform.h diff --git a/docs/rt-svc-writers-guide.md b/docs/rt-svc-writers-guide.md new file mode 100644 index 0000000..2d13f74 --- /dev/null +++ b/docs/rt-svc-writers-guide.md @@ -0,0 +1,309 @@ +EL3 Runtime Service Writers Guide for ARM Trusted Firmware +========================================================== + +Contents +-------- + +1. Introduction +2. Owning Entities, Call Types and Function IDs +3. Getting started +4. Registering a runtime service +5. Initializing a runtime service +6. Handling runtime service requests +7. Services that contain multiple sub-services +8. Secure-EL1 Payload Dispatcher service (SPD) + +- - - - - - - - - - - - - - - - - - + +1. Introduction +---------------- + +This document describes how to add a runtime service to the EL3 Runtime +Firmware component of ARM Trusted Firmware (BL3-1). + +Software executing in the normal world and in the trusted world at exception +levels lower than EL3 will request runtime services using the Secure Monitor +Call (SMC) instruction. These requests will follow the convention described in +the SMC Calling Convention PDD ([SMCCC]). The [SMCCC] assigns function +identifiers to each SMC request and describes how arguments are passed and +results are returned. + +SMC Functions are grouped together based on the implementor of the service, for +example a subset of the Function IDs are designated as "OEM Calls" (see [SMCCC] +for full details). The EL3 runtime services framework in BL3-1 enables the +independent implementation of services for each group, which are then compiled +into the BL3-1 image. This simplifies the integration of common software from +ARM to support [PSCI], Secure Monitor for a Trusted OS and SoC specific +software. The common runtime services framework ensures that SMC Functions are +dispatched to their respective service implementation - the [Firmware Design] +provides details of how this is achieved. + +The interface and operation of the runtime services depends heavily on the +concepts and definitions described in the [SMCCC], in particular SMC Function +IDs, Owning Entity Numbers (OEN), Fast and Standard calls, and the SMC32 and +SMC64 calling conventions. Please refer to that document for a full explanation +of these terms. + + +2. Owning Entities, Call Types and Function IDs +------------------------------------------------ + +The SMC Function Identifier includes a OEN field. These values and their +meaning are described in [SMCCC] and summarized in table 1 below. Some entities +are allocated a range of of OENs. The OEN must be interpreted in conjunction +with the SMC call type, which is either _Fast_ or _Standard_. Fast calls are +uninterruptible whereas Standard calls can be pre-empted. The majority of +Owning Entities only have allocated ranges for Fast calls: Standard calls are +reserved exclusively for Trusted OS providers or for interoperability with +legacy 32-bit software that predates the [SMCCC]. + + Type OEN Service + Fast 0 ARM Architecture calls + Fast 1 CPU Service calls + Fast 2 SiP Service calls + Fast 3 OEM Service calls + Fast 4 Standard Service calls + Fast 5-47 Reserved for future use + Fast 48-49 Trusted Application calls + Fast 50-63 Trusted OS calls + + Std 0- 1 Reserved for existing ARMv7 calls + Std 2-63 Trusted OS Standard Calls + +_Table 1: Service types and their corresponding Owning Entity Numbers_ + +Each individual entity can allocate the valid identifiers within the entity +range as they need - it is not necessary to coordinate with other entities of +the same type. For example, two SoC providers can use the same Function ID +within the SiP Service calls OEN range to mean different things - as these +calls should be specific to the SoC. The Standard Runtime Calls OEN is used for +services defined by ARM standards, such as [PSCI]. + +The SMC Function ID also indicates whether the call has followed the SMC32 +calling convention, where all parameters are 32-bit, or the SMC64 calling +convention, where the parameters are 64-bit. The framework identifies and +rejects invalid calls that use the SMC64 calling convention but that originate +from an AArch32 caller. + +The EL3 runtime services framework uses the call type and OEN to identify a +specific handler for each SMC call, but it is expected that an individual +handler will be responsible for all SMC Functions within a given service type. + + +3. Getting started +------------------- + +ARM Trusted Firmware has a [`services`] directory in the source tree under which +each owning entity can place the implementation of its runtime service. The +[PSCI] implementation is located here in the [`services/std_svc/psci`] +directory. + +Runtime service sources will need to include the [`runtime_svc.h`] header file. + + +4. Registering a runtime service +--------------------------------- + +A runtime service is registered using the `DECLARE_RT_SVC()` macro, specifying +the name of the service, the range of OENs covered, the type of service and +initialization and call handler functions. + + #define DECLARE_RT_SVC(_name, _start, _end, _type, _setup, _smch) + +* `_name` is used to identify the data structure declared by this macro, and + is also used for diagnostic purposes + +* `_start` and `_end` values must be based on the `OEN_*` values defined in + [`runtime_svc.h`] + +* `_type` must be one of `SMC_TYPE_FAST` or `SMC_TYPE_STD` + +* `_setup` is the initialization function with the `rt_svc_init` signature: + + typedef int32_t (*rt_svc_init)(void); + +* `_smch` is the SMC handler function with the `rt_svc_handle` signature: + + typedef uint64_t (*rt_svc_handle)(uint32_t smc_fid, + uint64_t x1, uint64_t x2, + uint64_t x3, uint64_t x4, + void *reserved, + void *handle, + uint64_t flags); + +Details of the requirements and behavior of the two callbacks is provided in +the following sections. + +During initialization the services framework validates each declared service +to ensure that the following conditions are met: + +1. The `_start` OEN is not greater than the `_end` OEN +2. The `_end` OEN does not exceed the maximum OEN value (63) +3. The `_type` is one of `SMC_TYPE_FAST` or `SMC_TYPE_STD` +4. `_setup` and `_smch` routines have been specified + +[`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 uint64_t (*rt_svc_handle)(uint32_t smc_fid, + uint64_t x1, uint64_t x2, + uint64_t x3, uint64_t x4, + void *reserved, + void *handle, + uint64_t flags); + +The handler is responsible for: + +1. Determining that `smc_fid` is a valid and supported SMC Function ID, + otherwise completing the request with the _Unknown SMC Function ID_: + + SMC_RET1(handle, SMC_UNK); + +2. Determining if the requested function is valid for the calling security + state. SMC Calls can be made from both the normal and trusted worlds and + the framework will forward all calls to the service handler. + + The `flags` parameter to this function indicates the caller security state + in bit[0], where a value of `1` indicates a non-secure caller. The + `is_caller_secure(flags)` and `is_caller_non_secure(flags)` can be used to + test this condition. + + If invalid, the request should be completed with: + + SMC_RET1(handle, SMC_UNK); + +3. Truncating parameters for calls made using the SMC32 calling convention. + Such calls can be determined by checking the CC field in bit[30] of the + `smc_fid` parameter, for example by using: + + if (GET_SMC_CC(smc_fid) == SMC_32) ... + + For such calls, the upper bits of the parameters x1-x4 and the saved + parameters X5-X7 are UNDEFINED and must be explicitly ignored by the + handler. This can be done by truncating the values to a suitable 32-bit + integer type before use, for example by ensuring that functions defined + to handle individual SMC Functions use appropriate 32-bit parameters. + +4. Providing the service requested by the SMC Function, utilizing the + immediate parameters x1-x4 and/or the additional saved parameters X5-X7. + The latter can be retrieved using the `SMC_GET_GP(handle, ref)` function, + supplying the appropriate `CTX_GPREG_Xn` reference, e.g. + + uint64_t x6 = SMC_GET_GP(handle, CTX_GPREG_X6); + +5. Implementing the standard SMC32 Functions that provide information about + the implementation of the service. These are the Call Count, Implementor + UID and Revision Details for each service documented in section 6 of the + [SMCCC]. + + The ARM Trusted Firmware expects owning entities to follow this + recommendation. + +5. Returning the result to the caller. The [SMCCC] allows for up to 256 bits + of return value in SMC64 using X0-X3 and 128 bits in SMC32 using W0-W3. The + framework provides a family of macros to set the multi-register return + value and complete the handler: + + SMC_RET1(handle, x0); + SMC_RET2(handle, x0, x1); + SMC_RET3(handle, x0, x1, x2); + SMC_RET4(handle, x0, x1, x2, x3); + +The `reserved` parameter to the handler is reserved for future use and can be +ignored. The value returned by a SMC handler is also reserved for future use - +completion of the handler function must always be via one of the `SMC_RETn()` +macros. + +NOTE: The PSCI and Test Secure-EL1 Payload Dispatcher services do not follow +all of the above requirements yet. + + +7. Services that contain multiple sub-services +----------------------------------------------- + +It is possible that a single owning entity implements multiple sub-services. For +example, the Standard calls service handles `0x84000000`-`0x8400FFFF` and +`0xC4000000`-`0xC400FFFF` functions. Within that range, the [PSCI] service +handles the `0x84000000`-`0x8400001F` and `0xC4000000`-`0xC400001F` functions. +In that respect, [PSCI] is a 'sub-service' of the Standard calls service. In +future, there could be additional such sub-services in the Standard calls +service which perform independent functions. + +In this situation it may be valuable to introduce a second level framework to +enable independent implementation of sub-services. Such a framework might look +very similar to the current runtime services framework, but using a different +part of the SMC Function ID to identify the sub-service. Trusted Firmware does +not provide such a framework at present. + + +8. Secure-EL1 Payload Dispatcher service (SPD) +----------------------------------------------- + +Services that handle SMC Functions targeting a Trusted OS, Trusted Application, +or other Secure-EL1 Payload are special. These services need to manage the +Secure-EL1 context, provide the _Secure Monitor_ functionality of switching +between the normal and secure worlds, deliver SMC Calls through to Secure-EL1 +and generally manage the Secure-EL1 Payload through CPU power-state transitions. + +TODO: Provide details of the additional work required to implement a SPD and +the BL3-1 support for these services. Or a reference to the document that will +provide this information.... + + +- - - - - - - - - - - - - - - - - - - - - - - - - - + +_Copyright (c) 2014, ARM Limited and Contributors. All rights reserved._ + + +[Firmware Design]: ./firmware-design.md + +[`services`]: ../services +[`services/std_svc/psci`]: ../services/std_svc/psci +[`std_svc_setup.c`]: ../services/std_svc/std_svc_setup.c +[`runtime_svc.h`]: ../include/runtime_svc.h +[PSCI]: http://infocenter.arm.com/help/topic/com.arm.doc.den0022b/index.html "Power State Coordination Interface PDD (ARM DEN 0022B.b)" +[SMCCC]: http://infocenter.arm.com/help/topic/com.arm.doc.den0028a/index.html "SMC Calling Convention PDD (ARM DEN 0028A)" diff --git a/docs/user-guide.md b/docs/user-guide.md new file mode 100644 index 0000000..40a7955 --- /dev/null +++ b/docs/user-guide.md @@ -0,0 +1,841 @@ +ARM Trusted Firmware User Guide +=============================== + +Contents : + +1. Introduction +2. Host machine requirements +3. Tools +4. Building the Trusted Firmware +5. Obtaining the normal world software +6. Running the software + + +1. Introduction +---------------- +This document describes how to build ARM Trusted Firmware and run it with a +tested set of other software components using defined configurations on ARM +Fixed Virtual Platform (FVP) models. It is possible to use other software +components, configurations and platforms but that is outside the scope of this +document. + +This document should be used in conjunction with the [Firmware Design]. + + +2. Host machine requirements +----------------------------- + +The minimum recommended machine specification for building the software and +running the FVP models is a dual-core processor running at 2GHz with 12GB of +RAM. For best performance, use a machine with a quad-core processor running at +2.6GHz with 16GB of RAM. + +The software has been tested on Ubuntu 12.04.04 (64-bit). Packages used +for building the software were installed from that distribution unless +otherwise specified. + + +3. Tools +--------- + +The following tools are required to use the ARM Trusted Firmware: + +* `git` package to obtain source code + +* `ia32-libs` package + +* `build-essential` and `uuid-dev` packages for building UEFI and the Firmware + Image Package(FIP) tool + +* `bc` and `ncurses-dev` packages for building Linux + +* Baremetal GNU GCC tools. Verified packages can be downloaded from [Linaro] + [Linaro Toolchain]. The rest of this document assumes that the + `gcc-linaro-aarch64-none-elf-4.8-2013.11_linux.tar.xz` tools are used. + + wget http://releases.linaro.org/13.11/components/toolchain/binaries/gcc-linaro-aarch64-none-elf-4.8-2013.11_linux.tar.xz + tar -xf gcc-linaro-aarch64-none-elf-4.8-2013.11_linux.tar.xz + +* The Device Tree Compiler (DTC) included with Linux kernel 3.15-rc6 is used + to build the Flattened Device Tree (FDT) source files (`.dts` files) + provided with this software. + +* (Optional) For debugging, ARM [Development Studio 5 (DS-5)][DS-5] v5.18. + + +4. Building the Trusted Firmware +--------------------------------- + +To build the software for the FVPs, follow these steps: + +1. Clone the ARM Trusted Firmware repository from GitHub: + + git clone https://github.com/ARM-software/arm-trusted-firmware.git + +2. Change to the trusted firmware directory: + + cd arm-trusted-firmware + +3. Set the compiler path, specify a Non-trusted Firmware image (BL3-3) and + build: + + CROSS_COMPILE=<path-to-aarch64-gcc>/bin/aarch64-none-elf- \ + BL33=<path-to>/<bl33_image> \ + make PLAT=fvp all fip + + See the "Summary of build options" for information on available build + options. + + By default this produces a release version of the build. To produce a debug + version instead, refer to the "Debugging options" section below. UEFI can be + used as the BL3-3 image, refer to the "Obtaining the normal world software" + section below. By default this won't compile the TSP in, refer to the + "Building the Test Secure Payload" section below. + + The build process creates products in a `build` directory tree, building + the objects and binaries for each boot loader stage in separate + sub-directories. The following boot loader binary files are created from + the corresponding ELF files: + + * `build/<platform>/<build-type>/bl1.bin` + * `build/<platform>/<build-type>/bl2.bin` + * `build/<platform>/<build-type>/bl31.bin` + + ... where `<platform>` currently defaults to `fvp` and `<build-type>` is + either `debug` or `release`. A Firmare Image Package(FIP) will be created as + part of the build. It contains all boot loader images except for `bl1.bin`. + + * `build/<platform>/<build-type>/fip.bin` + + For more information on FIPs, see the "Firmware Image Package" section in + the [Firmware Design]. + +4. Copy the `bl1.bin` and `fip.bin` binary files to the directory from which + the FVP will be launched. Symbolic links of the same names may be created + instead. + +5. (Optional) Build products for a specific build variant can be removed using: + + make DEBUG=<D> PLAT=fvp clean + + ... where `<D>` is `0` or `1`, as specified when building. + + The build tree can be removed completely using: + + make realclean + +### Summary of build options + +ARM Trusted Firmware build system supports the following build options. Unless +mentioned otherwise, these options are expected to be specified at the build +command line and are not to be modified in any component makefiles. Note that +the build system doesn't track dependency for build options. Therefore, if any +of the build options are changed from a previous build, a clean build must be +performed. + +* `BL33`: Path to BL33 image in the host file system. This is mandatory for + `fip` target + +* `BL30`: Path to BL3-0 image in the host file system. This image is optional. + If a BL3-0 image is present then this option must be passed for the `fip` + target + +* `CROSS_COMPILE`: Prefix to tool chain binaries. Please refer to examples in + this document for usage + +* `DEBUG`: Chooses between a debug and release build. It can take either 0 + (release) or 1 (debug) as values. 0 is the default + +* `NS_TIMER_SWITCH`: Enable save and restore for non-secure timer register + contents upon world switch. It can take either 0 (don't save and restore) or + 1 (do save and restore). 0 is the default. An SPD could set this to 1 if it + wants the timer registers to be saved and restored + +* `PLAT`: Choose a platform to build ARM Trusted Firmware for. The chosen + platform name must be the name of one of the directories under the `plat/` + directory other than `common` + +* `SPD`: Choose a Secure Payload Dispatcher component to be built into the + Trusted Firmware. The value should be the path to the directory containing + SPD source; the directory is expected to contain `spd.mk` makefile + +* `V`: Verbose build. If assigned anything other than 0, the build commands + are printed. Default is 0 + +* `FVP_GIC_ARCH`: Choice of ARM GIC architecture version used by the FVP port + for implementing the platform GIC API. This API is used by the interrupt + management framework. Default is 2 i.e. version 2.0 + +* `IMF_READ_INTERRUPT_ID`: Boolean flag used by the interrupt management + framework to enable passing of the interrupt id to its handler. The id is + read using a platform GIC API. `INTR_ID_UNAVAILABLE` is passed instead if + this option set to 0. Default is 0. + +* `RESET_TO_BL31`: Enable BL3-1 entrypoint as the CPU reset vector in place + of the BL1 entrypoint. It can take the value 0 (CPU reset to BL1 + entrypoint) or 1 (CPU reset to BL3-1 entrypoint). + The default value is 0. + + +### Creating a Firmware Image Package + +FIPs are automatically created as part of the build instructions described in +the previous section. It is also possible to independently build the FIP +creation tool and FIPs if required. To do this, follow these steps: + +Build the tool: + + make -C tools/fip_create + +It is recommended to remove the build artifacts before rebuilding: + + make -C tools/fip_create clean + +Create a Firmware package that contains existing FVP BL2 and BL3-1 images: + + # fip_create --help to print usage information + # fip_create <fip_name> <images to add> [--dump to show result] + ./tools/fip_create/fip_create fip.bin --dump \ + --bl2 build/fvp/debug/bl2.bin --bl31 build/fvp/debug/bl31.bin + + Firmware Image Package ToC: + --------------------------- + - Trusted Boot Firmware BL2: offset=0x88, size=0x81E8 + file: 'build/fvp/debug/bl2.bin' + - EL3 Runtime Firmware BL3-1: offset=0x8270, size=0xC218 + file: 'build/fvp/debug/bl31.bin' + --------------------------- + Creating "fip.bin" + +View the contents of an existing Firmware package: + + ./tools/fip_create/fip_create fip.bin --dump + + Firmware Image Package ToC: + --------------------------- + - Trusted Boot Firmware BL2: offset=0x88, size=0x81E8 + - EL3 Runtime Firmware BL3-1: offset=0x8270, size=0xC218 + --------------------------- + +Existing package entries can be individially updated: + + # Change the BL2 from Debug to Release version + ./tools/fip_create/fip_create fip.bin --dump \ + --bl2 build/fvp/release/bl2.bin + + Firmware Image Package ToC: + --------------------------- + - Trusted Boot Firmware BL2: offset=0x88, size=0x7240 + file: 'build/fvp/release/bl2.bin' + - EL3 Runtime Firmware BL3-1: offset=0x72C8, size=0xC218 + --------------------------- + Updating "fip.bin" + + +### Debugging options + +To compile a debug version and make the build more verbose use + + CROSS_COMPILE=<path-to-aarch64-gcc>/bin/aarch64-none-elf- \ + BL33=<path-to>/<bl33_image> \ + make PLAT=fvp DEBUG=1 V=1 all fip + +AArch64 GCC uses DWARF version 4 debugging symbols by default. Some tools (for +example DS-5) might not support this and may need an older version of DWARF +symbols to be emitted by GCC. This can be achieved by using the +`-gdwarf-<version>` flag, with the version being set to 2 or 3. Setting the +version to 2 is recommended for DS-5 versions older than 5.16. + +When debugging logic problems it might also be useful to disable all compiler +optimizations by using `-O0`. + +NOTE: Using `-O0` could cause output images to be larger and base addresses +might need to be recalculated (see the later memory layout section). + +Extra debug options can be passed to the build system by setting `CFLAGS`: + + CFLAGS='-O0 -gdwarf-2' \ + CROSS_COMPILE=<path-to-aarch64-gcc>/bin/aarch64-none-elf- \ + BL33=<path-to>/<bl33_image> \ + make PLAT=fvp DEBUG=1 V=1 all fip + + +NOTE: The Foundation FVP does not provide a debugger interface. + + +### Building the Test Secure Payload + +The TSP is coupled with a companion runtime service in the BL3-1 firmware, +called the TSPD. Therefore, if you intend to use the TSP, the BL3-1 image +must be recompiled as well. For more information on SPs and SPDs, see the +"Secure-EL1 Payloads and Dispatchers" section in the [Firmware Design]. + +First clean the Trusted Firmware build directory to get rid of any previous +BL3-1 binary. Then to build the TSP image and include it into the FIP use: + + CROSS_COMPILE=<path-to-aarch64-gcc>/bin/aarch64-none-elf- \ + BL33=<path-to>/<bl33_image> \ + make PLAT=fvp SPD=tspd all fip + +An additional boot loader binary file is created in the `build` directory: + + * `build/<platform>/<build-type>/bl32.bin` + +The Firmware Package contains this new image: + + Firmware Image Package ToC: + --------------------------- + - Trusted Boot Firmware BL2: offset=0xD8, size=0x6000 + file: './build/fvp/release/bl2.bin' + - EL3 Runtime Firmware BL3-1: offset=0x60D8, size=0x9000 + file: './build/fvp/release/bl31.bin' + - Secure Payload BL3-2 (Trusted OS): offset=0xF0D8, size=0x3000 + file: './build/fvp/release/bl32.bin' + - Non-Trusted Firmware BL3-3: offset=0x120D8, size=0x280000 + file: '../FVP_AARCH64_EFI.fd' + --------------------------- + Creating "build/fvp/release/fip.bin" + +On FVP, the TSP binary runs from Trusted SRAM by default. It is also possible +to run it from Trusted DRAM. This is controlled by the build configuration +`TSP_RAM_LOCATION`: + + CROSS_COMPILE=<path-to-aarch64-gcc>/bin/aarch64-none-elf- \ + BL33=<path-to>/<bl33_image> \ + make PLAT=fvp SPD=tspd TSP_RAM_LOCATION=tdram all fip + + +### Checking source code style + +When making changes to the source for submission to the project, the source +must be in compliance with the Linux style guide, and to assist with this check +the project Makefile contains two targets, which both utilise the checkpatch.pl +script that ships with the Linux source tree. + +To check the entire source tree, you must first download a copy of checkpatch.pl +(or the full Linux source), set the CHECKPATCH environment variable to point to +the script and build the target checkcodebase: + + make CHECKPATCH=../linux/scripts/checkpatch.pl checkcodebase + +To just check the style on the files that differ between your local branch and +the remote master, use: + + make CHECKPATCH=../linux/scripts/checkpatch.pl checkpatch + +If you wish to check your patch against something other than the remote master, +set the BASE_COMMIT variable to your desired branch. By default, BASE_COMMIT +is set to 'origin/master'. + + +5. Obtaining the normal world software +--------------------------------------- + +### Obtaining EDK2 + +Potentially any kind of non-trusted firmware may be used with the ARM Trusted +Firmware but the software has only been tested with the EFI Development Kit 2 +(EDK2) open source implementation of the UEFI specification. + +Clone the [EDK2 source code][EDK2] from GitHub. This version supports the Base +and Foundation FVPs: + + git clone -n https://github.com/tianocore/edk2.git + cd edk2 + git checkout 129ff94661bd3a6c759b1e154c143d0136bedc7d + + +To build the software to be compatible with Foundation and Base FVPs, follow +these steps: + +1. Copy build config templates to local workspace + + # in edk2/ + . edksetup.sh + +2. Build the EDK2 host tools + + make -C BaseTools clean + make -C BaseTools + +3. Build the EDK2 software + + CROSS_COMPILE=<absolute-path-to-aarch64-gcc>/bin/aarch64-none-elf- \ + make -f ArmPlatformPkg/Scripts/Makefile EDK2_ARCH=AARCH64 \ + EDK2_DSC=ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-FVP-AArch64.dsc \ + EDK2_TOOLCHAIN=ARMGCC EDK2_MACROS="-n 6 -D ARM_FOUNDATION_FVP=1" + + The EDK2 binary for use with the ARM Trusted Firmware can then be found + here: + + Build/ArmVExpress-FVP-AArch64/DEBUG_ARMGCC/FV/FVP_AARCH64_EFI.fd + + This will build EDK2 for the default settings as used by the FVPs. The EDK2 + binary `FVP_AARCH64_EFI.fd` should be specified as `BL33` in in the `make` + command line when building the Trusted Firmware. See the "Building the + Trusted Firmware" section above. + +4. (Optional) To boot Linux using a VirtioBlock file-system, the command line + passed from EDK2 to the Linux kernel must be modified as described in the + "Obtaining a root file-system" section below. + +5. (Optional) If legacy GICv2 locations are used, the EDK2 platform description + must be updated. This is required as EDK2 does not support probing for the + GIC location. To do this, first clean the EDK2 build directory. + + make -f ArmPlatformPkg/Scripts/Makefile EDK2_ARCH=AARCH64 \ + EDK2_DSC=ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-FVP-AArch64.dsc \ + EDK2_TOOLCHAIN=ARMGCC clean + + Then rebuild EDK2 as described in step 3, using the following flag: + + -D ARM_FVP_LEGACY_GICV2_LOCATION=1 + + Finally rebuild the Trusted Firmware to generate a new FIP using the + instructions in the "Building the Trusted Firmware" section. + + +### Obtaining a Linux kernel + +The software has been verified using a Linux kernel based on version 3.15-rc6. +Patches have been applied in order to enable the CPU idle feature. + +Preparing a Linux kernel for use on the FVPs with CPU idle support can +be done as follows (GICv2 support only): + +1. Clone Linux: + + git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git + + Not all CPU idle features are included in the mainline kernel yet. To + use these, add the patches from Sudeep Holla's kernel: + + cd linux + git remote add -f --tags arm64_idle_v3.15-rc6 git://linux-arm.org/linux-skn.git + git checkout -b cpuidle arm64_idle_v3.15-rc6 + +2. Build with the Linaro GCC tools. + + # in linux/ + make mrproper + make ARCH=arm64 defconfig + + # Enable CPU idle + make ARCH=arm64 menuconfig + # CPU Power Management ---> CPU Idle ---> [*] CPU idle PM support + # CPU Power Management ---> CPU Idle ---> ARM64 CPU Idle Drivers ---> [*] Generic ARM64 CPU idle Driver + + CROSS_COMPILE=<path-to-aarch64-gcc>/bin/aarch64-none-elf- \ + make -j6 ARCH=arm64 + +3. Copy the Linux image `arch/arm64/boot/Image` to the working directory from + where the FVP is launched. Alternatively a symbolic link may be used. + +### Obtaining the Flattened Device Trees + +Depending on the FVP configuration and Linux configuration used, different +FDT files are required. FDTs for the Foundation and Base FVPs can be found in +the Trusted Firmware source directory under `fdts/`. The Foundation FVP has a +subset of the Base FVP components. For example, the Foundation FVP lacks CLCD +and MMC support, and has only one CPU cluster. + +* `fvp-base-gicv2-psci.dtb` + + (Default) For use with both AEMv8 and Cortex-A57-A53 Base FVPs with + Base memory map configuration. + +* `fvp-base-gicv2legacy-psci.dtb` + + For use with AEMv8 Base FVP with legacy VE GIC memory map configuration. + +* `fvp-base-gicv3-psci.dtb` + + For use with both AEMv8 and Cortex-A57-A53 Base FVPs with Base memory map + configuration and Linux GICv3 support. + +* `fvp-foundation-gicv2-psci.dtb` + + (Default) For use with Foundation FVP with Base memory map configuration. + +* `fvp-foundation-gicv2legacy-psci.dtb` + + For use with Foundation FVP with legacy VE GIC memory map configuration. + +* `fvp-foundation-gicv3-psci.dtb` + + For use with Foundation FVP with Base memory map configuration and Linux + GICv3 support. + + +Copy the chosen FDT blob as `fdt.dtb` to the directory from which the FVP +is launched. Alternatively a symbolic link may be used. + +### Obtaining a root file-system + +To prepare a Linaro LAMP based Open Embedded file-system, the following +instructions can be used as a guide. The file-system can be provided to Linux +via VirtioBlock or as a RAM-disk. Both methods are described below. + +#### Prepare VirtioBlock + +To prepare a VirtioBlock file-system, do the following: + +1. Download and unpack the disk image. + + NOTE: The unpacked disk image grows to 3 GiB in size. + + wget http://releases.linaro.org/14.04/openembedded/aarch64/vexpress64-openembedded_lamp-armv8-gcc-4.8_20140417-630.img.gz + gunzip vexpress64-openembedded_lamp-armv8-gcc-4.8_20140417-630.img.gz + +2. Make sure the Linux kernel has Virtio support enabled using + `make ARCH=arm64 menuconfig`. + + Device Drivers ---> Virtio drivers ---> <*> Platform bus driver for memory mapped virtio devices + Device Drivers ---> [*] Block devices ---> <*> Virtio block driver + File systems ---> <*> The Extended 4 (ext4) filesystem + + If some of these configurations are missing, enable them, save the kernel + configuration, then rebuild the kernel image using the instructions + provided in the section "Obtaining a Linux kernel". + +3. Change the Kernel command line to include `root=/dev/vda2`. This can either + be done in the EDK2 boot menu or in the platform file. Editing the platform + file and rebuilding EDK2 will make the change persist. To do this: + + 1. In EDK2, edit the following file: + + ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-FVP-AArch64.dsc + + 2. Add `root=/dev/vda2` to: + + gArmPlatformTokenSpaceGuid.PcdDefaultBootArgument|"<Other default options>" + + 3. Remove the entry: + + gArmPlatformTokenSpaceGuid.PcdDefaultBootInitrdPath|"" + + 4. Rebuild EDK2 (see "Obtaining UEFI" section above). + +4. The file-system image file should be provided to the model environment by + passing it the correct command line option. In the FVPs the following + option should be provided in addition to the ones described in the + "Running the software" section below. + + NOTE: A symbolic link to this file cannot be used with the FVP; the path + to the real file must be provided. + + On the Base FVPs: + + -C bp.virtioblockdevice.image_path="<path-to>/<file-system-image>" + + On the Foundation FVP: + + --block-device="<path-to>/<file-system-image>" + + +5. Ensure that the FVP doesn't output any error messages. If the following + error message is displayed: + + ERROR: BlockDevice: Failed to open "<path-to>/<file-system-image>"! + + then make sure the path to the file-system image in the model parameter is + correct and that read permission is correctly set on the file-system image + file. + +#### Prepare RAM-disk + +To prepare a RAM-disk root file-system, do the following: + +1. Download the file-system image: + + wget http://releases.linaro.org/14.04/openembedded/aarch64/linaro-image-lamp-genericarmv8-20140417-667.rootfs.tar.gz + +2. Modify the Linaro image: + + # Prepare for use as RAM-disk. Normally use MMC, NFS or VirtioBlock. + # Be careful, otherwise you could damage your host file-system. + mkdir tmp; cd tmp + sudo sh -c "zcat ../linaro-image-lamp-genericarmv8-20140417-667.rootfs.tar.gz | cpio -id" + sudo ln -s sbin/init . + sudo sh -c "echo 'devtmpfs /dev devtmpfs mode=0755,nosuid 0 0' >> etc/fstab" + sudo sh -c "find . | cpio --quiet -H newc -o | gzip -3 -n > ../filesystem.cpio.gz" + cd .. + +3. Copy the resultant `filesystem.cpio.gz` to the directory where the FVP is + launched from. Alternatively a symbolic link may be used. + + +6. Running the software +------------------------ + +This version of the ARM Trusted Firmware has been tested on the following ARM +FVPs (64-bit versions only). + +* `Foundation_v8` (Version 2.0, Build 0.8.5206) +* `FVP_Base_AEMv8A-AEMv8A` (Version 5.6, Build 0.8.5602) +* `FVP_Base_Cortex-A57x4-A53x4` (Version 5.6, Build 0.8.5602) +* `FVP_Base_Cortex-A57x1-A53x1` (Version 5.6, Build 0.8.5602) +* `FVP_Base_Cortex-A57x2-A53x4` (Version 5.6, Build 0.8.5602) + +NOTE: The software will not work on Version 1.0 of the Foundation FVP. +The commands below would report an `unhandled argument` error in this case. + +Please refer to the FVP documentation for a detailed description of the model +parameter options. A brief description of the important ones that affect the +ARM Trusted Firmware and normal world software behavior is provided below. + +The Foundation FVP is a cut down version of the AArch64 Base FVP. It can be +downloaded for free from [ARM's website][ARM FVP website]. + + +### Running on the Foundation FVP with reset to BL1 entrypoint + +The following `Foundation_v8` parameters should be used to boot Linux with +4 CPUs using the ARM Trusted Firmware. + +NOTE: Using the `--block-device` parameter is not necessary if a Linux RAM-disk +file-system is used (see the "Obtaining a File-system" section above). + +NOTE: The `--data="<path to FIP binary>"@0x8000000` parameter is used to load a +Firmware Image Package at the start of NOR FLASH0 (see the "Building the +Trusted Firmware" section above). + + <path-to>/Foundation_v8 \ + --cores=4 \ + --no-secure-memory \ + --visualization \ + --gicv3 \ + --data="<path-to>/<bl1-binary>"@0x0 \ + --data="<path-to>/<FIP-binary>"@0x8000000 \ + --block-device="<path-to>/<file-system-image>" + +The default use-case for the Foundation FVP is to enable the GICv3 device in +the model but use the GICv2 FDT, in order for Linux to drive the GIC in GICv2 +emulation mode. + +The memory mapped addresses `0x0` and `0x8000000` correspond to the start of +trusted ROM and NOR FLASH0 respectively. + +### Notes regarding Base FVP configuration options + +1. The `-C bp.flashloader0.fname` parameter is used to load a Firmware Image +Package at the start of NOR FLASH0 (see the "Building the Trusted Firmware" +section above). + +2. Using `cache_state_modelled=1` makes booting very slow. The software will +still work (and run much faster) without this option but this will hide any +cache maintenance defects in the software. + +3. Using the `-C bp.virtioblockdevice.image_path` parameter is not necessary +if a Linux RAM-disk file-system is used (see the "Obtaining a root file-system" +section above). + +4. Setting the `-C bp.secure_memory` parameter to `1` is only supported on +Base FVP versions 5.4 and newer. Setting this parameter to `0` is also +supported. The `-C bp.tzc_400.diagnostics=1` parameter is optional. It +instructs the FVP to provide some helpful information if a secure memory +violation occurs. + +5. The `--data="<path-to><bl31/bl32/bl33-binary>"@base address of binaries` +parameter is used to load bootloader images in the Base FVP memory (see the +"Building the Trusted Firmware" section above). The base address used to +load the binaries with --data should match the image base addresses in +platform_def.h used while linking the images. +BL3-2 image is only needed if BL3-1 has been built to expect a secure-EL1 +payload. + + +### Running on the AEMv8 Base FVP with reset to BL1 entrypoint + +Please read "Notes regarding Base FVP configuration options" section above for +information about some of the options to run the software. + +The following `FVP_Base_AEMv8A-AEMv8A` parameters should be used to boot Linux +with 8 CPUs using the ARM Trusted Firmware. + + <path-to>/FVP_Base_AEMv8A-AEMv8A \ + -C pctl.startup=0.0.0.0 \ + -C bp.secure_memory=1 \ + -C bp.tzc_400.diagnostics=1 \ + -C cluster0.NUM_CORES=4 \ + -C cluster1.NUM_CORES=4 \ + -C cache_state_modelled=1 \ + -C bp.pl011_uart0.untimed_fifos=1 \ + -C bp.secureflashloader.fname="<path-to>/<bl1-binary>" \ + -C bp.flashloader0.fname="<path-to>/<FIP-binary>" \ + -C bp.virtioblockdevice.image_path="<path-to>/<file-system-image>" + +### Running on the Cortex-A57-A53 Base FVP with reset to BL1 entrypoint + +Please read "Notes regarding Base FVP configuration options" section above for +information about some of the options to run the software. + +The following `FVP_Base_Cortex-A57x4-A53x4` model parameters should be used to +boot Linux with 8 CPUs using the ARM Trusted Firmware. + + <path-to>/FVP_Base_Cortex-A57x4-A53x4 \ + -C pctl.startup=0.0.0.0 \ + -C bp.secure_memory=1 \ + -C bp.tzc_400.diagnostics=1 \ + -C cache_state_modelled=1 \ + -C bp.pl011_uart0.untimed_fifos=1 \ + -C bp.secureflashloader.fname="<path-to>/<bl1-binary>" \ + -C bp.flashloader0.fname="<path-to>/<FIP-binary>" \ + -C bp.virtioblockdevice.image_path="<path-to>/<file-system-image>" + +### Running on the AEMv8 Base FVP with reset to BL3-1 entrypoint + +Please read "Notes regarding Base FVP configuration options" section above for +information about some of the options to run the software. + +The following `FVP_Base_AEMv8A-AEMv8A` parameters should be used to boot Linux +with 8 CPUs using the ARM Trusted Firmware. + +NOTE: Uses the `-c clusterX.cpuX.RVBAR=@base address of BL3-1` where X is +the cluster number in clusterX and cpu number in cpuX is used to set the reset +vector for each core. + + <path-to>/FVP_Base_AEMv8A-AEMv8A \ + -C pctl.startup=0.0.0.0 \ + -C bp.secure_memory=1 \ + -C bp.tzc_400.diagnostics=1 \ + -C cluster0.NUM_CORES=4 \ + -C cluster1.NUM_CORES=4 \ + -C cache_state_modelled=1 \ + -C bp.pl011_uart0.untimed_fifos=1 \ + -C cluster0.cpu0.RVBAR=0x04006000 \ + -C cluster0.cpu1.RVBAR=0x04006000 \ + -C cluster0.cpu2.RVBAR=0x04006000 \ + -C cluster0.cpu3.RVBAR=0x04006000 \ + -C cluster1.cpu0.RVBAR=0x04006000 \ + -C cluster1.cpu1.RVBAR=0x04006000 \ + -C cluster1.cpu2.RVBAR=0x04006000 \ + -C cluster1.cpu3.RVBAR=0x04006000 \ + --data cluster0.cpu0="<path-to>/<bl31-binary>"@0x04006000 \ + --data cluster0.cpu0="<path-to>/<bl32-binary>"@0x04024000 \ + --data cluster0.cpu0="<path-to>/<bl33-binary>"@0x88000000 \ + -C bp.virtioblockdevice.image_path="<path-to>/<file-system-image>" + +### Running on the Cortex-A57-A53 Base FVP with reset to BL3-1 entrypoint + +Please read "Notes regarding Base FVP configuration options" section above for +information about some of the options to run the software. + +The following `FVP_Base_Cortex-A57x4-A53x4` model parameters should be used to +boot Linux with 8 CPUs using the ARM Trusted Firmware. + +NOTE: Uses the `-c clusterX.cpuX.RVBARADDR=@base address of BL3-1` where X is +the cluster number in clusterX and cpu number in cpuX is used to set the reset +vector for each core. + + <path-to>/FVP_Base_Cortex-A57x4-A53x4 \ + -C pctl.startup=0.0.0.0 \ + -C bp.secure_memory=1 \ + -C bp.tzc_400.diagnostics=1 \ + -C cache_state_modelled=1 \ + -C bp.pl011_uart0.untimed_fifos=1 \ + -C cluster0.cpu0.RVBARADDR=0x04006000 \ + -C cluster0.cpu1.RVBARADDR=0x04006000 \ + -C cluster0.cpu2.RVBARADDR=0x04006000 \ + -C cluster0.cpu3.RVBARADDR=0x04006000 \ + -C cluster1.cpu0.RVBARADDR=0x04006000 \ + -C cluster1.cpu1.RVBARADDR=0x04006000 \ + -C cluster1.cpu2.RVBARADDR=0x04006000 \ + -C cluster1.cpu3.RVBARADDR=0x04006000 \ + --data cluster0.cpu0="<path-to>/<bl31-binary>"@0x04006000 \ + --data cluster0.cpu0="<path-to>/<bl32-binary>"@0x04024000 \ + --data cluster0.cpu0="<path-to>/<bl33-binary>"@0x88000000 \ + -C bp.virtioblockdevice.image_path="<path-to>/<file-system-image>" + +### Configuring the GICv2 memory map + +The Base FVP models support GICv2 with the default model parameters at the +following addresses. The Foundation FVP also supports these addresses when +configured for GICv3 in GICv2 emulation mode. + + GICv2 Distributor Interface 0x2f000000 + GICv2 CPU Interface 0x2c000000 + GICv2 Virtual CPU Interface 0x2c010000 + GICv2 Hypervisor Interface 0x2c02f000 + +The AEMv8 Base FVP can be configured to support GICv2 at addresses +corresponding to the legacy (Versatile Express) memory map as follows. These are +the default addresses when using the Foundation FVP in GICv2 mode. + + GICv2 Distributor Interface 0x2c001000 + GICv2 CPU Interface 0x2c002000 + GICv2 Virtual CPU Interface 0x2c004000 + GICv2 Hypervisor Interface 0x2c006000 + +The choice of memory map is reflected in the build variant field (bits[15:12]) +in the `SYS_ID` register (Offset `0x0`) in the Versatile Express System +registers memory map (`0x1c010000`). + +* `SYS_ID.Build[15:12]` + + `0x1` corresponds to the presence of the Base GIC memory map. This is the + default value on the Base FVPs. + +* `SYS_ID.Build[15:12]` + + `0x0` corresponds to the presence of the Legacy VE GIC memory map. This is + the default value on the Foundation FVP. + +This register can be configured as described in the following sections. + +NOTE: If the legacy VE GIC memory map is used, then the corresponding FDT and +BL3-3 images should be used. + +#### Configuring AEMv8 Foundation FVP GIC for legacy VE memory map + +The following parameters configure the Foundation FVP to use GICv2 with the +legacy VE memory map: + + <path-to>/Foundation_v8 \ + --cores=4 \ + --no-secure-memory \ + --visualization \ + --no-gicv3 \ + --data="<path-to>/<bl1-binary>"@0x0 \ + --data="<path-to>/<FIP-binary>"@0x8000000 \ + --block-device="<path-to>/<file-system-image>" + +Explicit configuration of the `SYS_ID` register is not required. + +#### Configuring AEMv8 Base FVP GIC for legacy VE memory map + +The following parameters configure the AEMv8 Base FVP to use GICv2 with the +legacy VE memory map. They must added to the parameters described in the +"Running on the AEMv8 Base FVP" section above: + + -C cluster0.gic.GICD-offset=0x1000 \ + -C cluster0.gic.GICC-offset=0x2000 \ + -C cluster0.gic.GICH-offset=0x4000 \ + -C cluster0.gic.GICH-other-CPU-offset=0x5000 \ + -C cluster0.gic.GICV-offset=0x6000 \ + -C cluster0.gic.PERIPH-size=0x8000 \ + -C cluster1.gic.GICD-offset=0x1000 \ + -C cluster1.gic.GICC-offset=0x2000 \ + -C cluster1.gic.GICH-offset=0x4000 \ + -C cluster1.gic.GICH-other-CPU-offset=0x5000 \ + -C cluster1.gic.GICV-offset=0x6000 \ + -C cluster1.gic.PERIPH-size=0x8000 \ + -C gic_distributor.GICD-alias=0x2c001000 \ + -C bp.variant=0x0 + +The `bp.variant` parameter corresponds to the build variant field of the +`SYS_ID` register. Setting this to `0x0` allows the ARM Trusted Firmware to +detect the legacy VE memory map while configuring the GIC. + + +- - - - - - - - - - - - - - - - - - - - - - - - - - + +_Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved._ + + +[Firmware Design]: ./firmware-design.md + +[ARM FVP website]: http://www.arm.com/fvp +[Linaro Toolchain]: http://releases.linaro.org/13.11/components/toolchain/binaries/ +[EDK2]: http://github.com/tianocore/edk2 +[DS-5]: http://www.arm.com/products/tools/software-tools/ds-5/index.php |