Introduction
Trusted Firmware-A (TF-A) provides a reference implementation of secure world software for Armv7-A and Armv8-A, including a Secure Monitor executing at Exception Level 3 (EL3).
TF-A is used as the initial start code on ARMv8-A cores for am62x. The following is the sequence of A53 execution with TF-A:
- After setting up the initial core state and applying any needed errata fixes it sets up itself as the EL3 monitor handler.
- Following that, it passes execution on to the FreeRTOS/NoRTOS application running in the non-secure world. TF-A passes control and starts application core image in non-secure EL2 level.
- Post that, the application startup code switches to non-secure EL1 after doing some initializations.
The FreeRTOS/NoRTOS kernel runs in non-secure EL1 level at all times. All exceptions/interrupts are routed to non-secure EL1 in the application.
TF-A Flow
Building TF-A
Getting the TF-A Source Code
- Attention
- TF-A requires Device Tree Compiler (DTC) to be installed in the build environment. There is one limitation that DTC is not present in Windows and only Linux users can install the compiler. Hence, TF-A can be built only on Linux machines, and thus Windows users need to use the pre-built binaries.
-
If building the TF-A bl31 binary is needed separately, users can go to this path in the SDK: ${MCU_PLUS_SDK_PATH}/source/atf/trusted-firmware-a and build from there.
Otherwise, the TF-A repository can be cloned from the below source:
$ git clone https://git.trustedfirmware.org/TF-A/trusted-firmware-a.git
$ git checkout <hash>
Where hash is the commit shown here: 58b25570c9ef91753b14c2103f45f4be9dddb696
Setting up the toolchain paths
To compile TF-A source independent of the SDK, set the cross compiler paths to the toolchain [Recommended] as shown below.
host# export CROSS_COMPILE_64="${CGT_GCC_AARCH64_PATH}/bin/aarch64-none-elf-
Refer to GCC_AARCH64_DOWNLOAD section for more details on usage.
Building the TF-A binary
$ export TFA_DIR=<path-to-trusted-firmware-a>
$ cd $TFA_DIR
$ make CROSS_COMPILE="$CROSS_COMPILE_64" ARCH=aarch64 PLAT=k3 TARGET_BOARD=lite
Default load locations for A53 core 0:
TF-A image | 0x80000000 |
RTOS application core image | 0x80080000 |
- Note
- The pre-built TF-A binary is packaged in the SDK at the following location:
${MCU_PLUS_SDK_PATH}/source/atf/lib/soc/am62x/
Application core startup sequence in TF-A integrated flow
The following points are important in understanding the application core startup sequence in TF-A integrated flow:
- The application starts from non-secure EL2 in TF-A integrated flow. Hence, the TF-A/non-TF-A bootflow has been dynamically handled based on the Exception level the application is at in the startup sequence.
- Hence, if the kernel starts from EL3, it's running without TF-A and if it starts from non-secure EL2, it's booted with TF-A.
_c_int00:
mrs x0, currentel
cmp x0, #0xC
bne _c_int00_atf /* Current EL is not EL3, hence application booted with ATF. */
- TF-A is enabling secure Group 1 and Group 0 interrupts, hence Non-secure Group 1 interrupts have been enabled in EL2.
- Cache invalidation happens in EL3 in MCU+ in the normal bootflow without TF-A.
Generating bootable appimage with TF-A binary
In the default flow,
- The TF-A binary generated from the TF-A repo (built at the time of building libs) is converted into an executable and linkable format (ELF) file.
- The generated ELF is then converted into an RPRC file.
- The TF-A RPRC generated is combined with the bootimage's RPRC file to create an appimage.
The appimage structure can be explained through the following code snippet.
ifeq ($(ATF_INTEGRATED_BOOT), yes)
MULTI_CORE_IMAGE_PARAMS = \
$(ATF_RPRC_NAME)@$(BOOTIMAGE_CORE_ID_a53ss0-0) \
$(BOOTIMAGE_RPRC_NAME)@$(BOOTIMAGE_CORE_ID_load_only) \
else
MULTI_CORE_IMAGE_PARAMS = \
$(BOOTIMAGE_RPRC_NAME)@$(BOOTIMAGE_CORE_ID_a53ss0-0) \
endif
Users can go back to the normal boot flow without TF-A by setting the "ATF_INTEGRATED_BOOT" flag as "no" in the build command or in the individual example makefiles.
Command to build hello world example without TF-A:
make -s -C examples/hello_world/am62x-sk/a53ss0-0_freertos/gcc-aarch64 all ATF_INTEGRATED_BOOT=no
To build all the examples without TF-A:
make -s -j4 all DEVICE=am62x ATF_INTEGRATED_BOOT=no
Linker update in TF-A integrated flow
- Since, TF-A expects BL33 (application core image) at the address 0x80080000, this address has been added in the linker script as the origin of the memory region DDR.
- Region before 0x80080000 of the DDR memory is being used by TF-A.
MEMORY {
DDR : ORIGIN = 0x80080000, LENGTH = 0x2000000
LOG_SHM_MEM : ORIGIN = 0xA1000000, LENGTH = 0x40000
AMP_SHM : ORIGIN = 0x99000000, LENGTH = 0x4000
}
- Since, TF-A keeps the PC at the above address after it's exit, we expect our startup code to be present at this memory address.