6.Porting Guide

6.1.Introduction

Porting Trusted Firmware-A (TF-A) to a new platform involves making somemandatory 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 declared ininclude/plat/common/platform.h. The firmware provides a defaultimplementation of variables and functions to fulfill the optional requirementsin order to ease the porting effort. Each platform port can use them as is orprovide their own implementation if the default implementation is inadequate.

Note

TF-A historically provided default implementations of platform interfacesasweak functions. This practice is now discouraged and new platforminterfaces as they get introduced in the code base should bestronglydefined. We intend to convert existing weak functions over time. Untilthen, you will find references toweak functions in this document.

Please review theThreat Model documents as part of the portingeffort. Some platform interfaces play a key role in mitigating against some ofthe threats. Failing to fulfill these expectations could undermine the securityguarantees offered by TF-A. These platform responsibilities are highlighted inthe threat assessment section, under the “Mitigations implemented?” box foreach threat.

Some modifications are common to all Boot Loader (BL) stages. Section 2discusses these in detail. The subsequent sections discuss the remainingmodifications for each BL stage in detail.

Please refer to thePlatform Ports Policy for the policy regardingcompatibility and deprecation of these porting interfaces.

Only Arm development platforms (such as FVP and Juno) may use thefunctions/definitions ininclude/plat/arm/common/ and the correspondingsource files inplat/arm/common/. This is done so that there are nodependencies between platforms maintained by different people/companies. If youwant to use any of the functionality present inplat/arm files, pleasepropose a patch that moves the code toplat/common so that it can bediscussed.

6.2.Common modifications

This section covers the modifications that should be made by the platform foreach BL stage to correctly port the firmware stack. They are categorized aseither mandatory or optional.

6.3.Common mandatory modifications

A platform port must enable the Memory Management Unit (MMU) as well as theinstruction and data caches for each BL stage. Setting up the translationtables is the responsibility of the platform port because memory maps differacross platforms. A memory translation library (seelib/xlat_tables_v2/) isprovided to help in this setup.

Note that although this library supports non-identity mappings, this is intendedonly for re-mapping peripheral physical addresses and allows platforms with highI/O addresses to reduce their virtual address space. All other addressescorresponding to code and data must currently use an identity mapping.

Also, the only translation granule size supported in TF-A is 4KB, as variousparts of the code assume that is the case. It is not possible to switch to16 KB or 64 KB granule sizes at the moment.

In Arm standard platforms, each BL stage configures the MMU in theplatform-specific architecture setup function,blX_plat_arch_setup(), and usesan identity mapping for all addresses.

If the build optionUSE_COHERENT_MEM is enabled, each platform can allocate ablock of identity mapped secure memory with Device-nGnRE attributes aligned topage boundary (4K) for each BL stage. All sections which allocate coherentmemory are grouped under.coherent_ram. For ex: Bakery locks are placed in asection identified by name.bakery_lock inside.coherent_ram so that itspossible for the firmware to place variables in it using the following C codedirective:

__section(".bakery_lock")

Or alternatively the following assembler code directive:

.section.bakery_lock

The.coherent_ram section is a sum of all sections like.bakery_lock which areused to allocate any data structures that are accessed both when a CPU isexecuting with its MMU and caches enabled, and when it’s running with its MMUand caches disabled. Examples are given below.

The following variables, functions and constants must be defined by the platformfor the firmware to work correctly.

6.3.1.File : platform_def.h [mandatory]

Each platform must ensure that a header file of this name is in the systeminclude path with the following constants defined. This will require updatingthe list ofPLAT_INCLUDES in theplatform.mk file.

Platform ports may optionally use the fileinclude/plat/common/common_def.h,which provides typical values for some of the constants below. These values arelikely to be suitable for all platform ports.

  • #define : PLATFORM_LINKER_FORMAT

    Defines the linker format used by the platform, for exampleelf64-littleaarch64.

  • #define : PLATFORM_LINKER_ARCH

    Defines the processor architecture for the linker by the platform, forexampleaarch64.

  • #define : PLATFORM_STACK_SIZE

    Defines the normal stack memory available to each CPU. This constant is usedbyplat/common/aarch64/platform_mp_stack.S andplat/common/aarch64/platform_up_stack.S.

  • #define : CACHE_WRITEBACK_GRANULE

    Defines the size in bytes of the largest cache line across all the cachelevels in the platform.

  • #define : FIRMWARE_WELCOME_STR

    Defines the character string printed by BL1 upon entry into thebl1_main()function.

  • #define : PLATFORM_CORE_COUNT

    Defines the total number of CPUs implemented by the platform across allclusters in the system.

  • #define : PLAT_NUM_PWR_DOMAINS

    Defines the total number of nodes in the power domain topologytree at all the power domain levels used by the platform.This macro is used by the PSCI implementation to allocatedata structures to represent power domain topology.

  • #define : PLAT_MAX_PWR_LVL

    Defines the maximum power domain level that the power management operationsshould apply to. More often, but not always, the power domain levelcorresponds to affinity level. This macro allows the PSCI implementationto know the highest power domain level that it should consider for powermanagement operations in the system that the platform implements. Forexample, the Base AEM FVP implements two clusters with a configurablenumber of CPUs and it reports the maximum power domain level as 1.

  • #define : PLAT_MAX_OFF_STATE

    Defines the local power state corresponding to the deepest power downpossible at every power domain level in the platform. The local powerstates for each level may be sparsely allocated between 0 and this valuewith 0 being reserved for the RUN state. The PSCI implementation uses thisvalue to initialize the local power states of the power domain nodes andto specify the requested power state for a PSCI_CPU_OFF call.

  • #define : PLAT_MAX_RET_STATE

    Defines the local power state corresponding to the deepest retention statepossible at every power domain level in the platform. This macro should bea value less than PLAT_MAX_OFF_STATE and greater than 0. It is used by thePSCI implementation to distinguish between retention and power down localpower states within PSCI_CPU_SUSPEND call.

  • #define : PLAT_MAX_PWR_LVL_STATES

    Defines the maximum number of local power states per power domain levelthat the platform supports. The default value of this macro is 2 sincemost platforms just support a maximum of two local power states at eachpower domain level (power-down and retention). If the platform needs toaccount for more local power states, then it must redefine this macro.

    Currently, this macro is used by the Generic PSCI implementation to sizethe array used for PSCI_STAT_COUNT/RESIDENCY accounting.

  • #define : BL1_RO_BASE

    Defines the base address in secure ROM where BL1 originally lives. Must bealigned 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 liveat 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 canoccupy 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. This constant is not applicablewhen BL2_IN_XIP_MEM is set to ‘1’.

  • #define : BL2_LIMIT

    Defines the maximum address in secure RAM that the BL2 image can occupy.This constant is not applicable when BL2_IN_XIP_MEM is set to ‘1’.

  • #define : BL2_RO_BASE

    Defines the base address in secure XIP memory where BL2 RO section originallylives. Must be aligned on a page-size boundary. This constant is only neededwhen BL2_IN_XIP_MEM is set to ‘1’.

  • #define : BL2_RO_LIMIT

    Defines the maximum address in secure XIP memory that BL2’s actual content(i.e. excluding any data section allocated at runtime) can occupy. Thisconstant is only needed when BL2_IN_XIP_MEM is set to ‘1’.

  • #define : BL2_RW_BASE

    Defines the base address in secure RAM where BL2’s read-write data will liveat runtime. Must be aligned on a page-size boundary. This constant is onlyneeded when BL2_IN_XIP_MEM is set to ‘1’.

  • #define : BL2_RW_LIMIT

    Defines the maximum address in secure RAM that BL2’s read-write data canoccupy at runtime. This constant is only needed when BL2_IN_XIP_MEM is setto ‘1’.

  • #define : BL31_BASE

    Defines the base address in secure RAM where BL2 loads the BL31 binaryimage. Must be aligned on a page-size boundary.

  • #define : BL31_LIMIT

    Defines the maximum address in secure RAM that the BL31 image can occupy.

  • #define : PLAT_RSE_COMMS_PAYLOAD_MAX_SIZE

    Defines the maximum message size between AP and RSE. Need to define ifplatform supports RSE.

For every image, the platform must define individual identifiers that will beused by BL1 or BL2 to load the corresponding image into memory from non-volatilestorage. For the sake of performance, integer numbers will be used asidentifiers. The platform will use those identifiers to return the relevantinformation about the image to be loaded (file handler, load address,authentication information, etc.). The following image identifiers aremandatory:

  • #define : BL2_IMAGE_ID

    BL2 image identifier, used by BL1 to load BL2.

  • #define : BL31_IMAGE_ID

    BL31 image identifier, used by BL2 to load BL31.

  • #define : BL33_IMAGE_ID

    BL33 image identifier, used by BL2 to load BL33.

If Trusted Board Boot is enabled, the following certificate identifiers mustalso be defined:

  • #define : TRUSTED_BOOT_FW_CERT_ID

    BL2 content certificate identifier, used by BL1 to load the BL2 contentcertificate.

  • #define : TRUSTED_KEY_CERT_ID

    Trusted key certificate identifier, used by BL2 to load the trusted keycertificate.

  • #define : SOC_FW_KEY_CERT_ID

    BL31 key certificate identifier, used by BL2 to load the BL31 keycertificate.

  • #define : SOC_FW_CONTENT_CERT_ID

    BL31 content certificate identifier, used by BL2 to load the BL31 contentcertificate.

  • #define : NON_TRUSTED_FW_KEY_CERT_ID

    BL33 key certificate identifier, used by BL2 to load the BL33 keycertificate.

  • #define : NON_TRUSTED_FW_CONTENT_CERT_ID

    BL33 content certificate identifier, used by BL2 to load the BL33 contentcertificate.

  • #define : FWU_CERT_ID

    Firmware Update (FWU) certificate identifier, used by NS_BL1U to load theFWU content certificate.

If the AP Firmware Updater Configuration image, BL2U is used, the followingmust also be defined:

  • #define : BL2U_BASE

    Defines the base address in secure memory where BL1 copies the BL2U binaryimage. Must be aligned on a page-size boundary.

  • #define : BL2U_LIMIT

    Defines the maximum address in secure memory that the BL2U image can occupy.

  • #define : BL2U_IMAGE_ID

    BL2U image identifier, used by BL1 to fetch an image descriptorcorresponding to BL2U.

If the SCP Firmware Update Configuration Image, SCP_BL2U is used, the followingmust also be defined:

  • #define : SCP_BL2U_IMAGE_ID

    SCP_BL2U image identifier, used by BL1 to fetch an image descriptorcorresponding to SCP_BL2U.

    Note

    TF-A does not provide source code for this image.

If the Non-Secure Firmware Updater ROM, NS_BL1U is used, the following mustalso be defined:

  • #define : NS_BL1U_BASE

    Defines the base address in non-secure ROM where NS_BL1U executes.Must be aligned on a page-size boundary.

    Note

    TF-A does not provide source code for this image.

  • #define : NS_BL1U_IMAGE_ID

    NS_BL1U image identifier, used by BL1 to fetch an image descriptorcorresponding to NS_BL1U.

If the Non-Secure Firmware Updater, NS_BL2U is used, the following must alsobe defined:

  • #define : NS_BL2U_BASE

    Defines the base address in non-secure memory where NS_BL2U executes.Must be aligned on a page-size boundary.

    Note

    TF-A does not provide source code for this image.

  • #define : NS_BL2U_IMAGE_ID

    NS_BL2U image identifier, used by BL1 to fetch an image descriptorcorresponding to NS_BL2U.

For the the Firmware update capability of TRUSTED BOARD BOOT, the followingmacros may also be defined:

  • #define : PLAT_FWU_MAX_SIMULTANEOUS_IMAGES

    Total number of images that can be loaded simultaneously. If the platformdoesn’t specify any value, it defaults to 10.

If a SCP_BL2 image is supported by the platform, the following constants mustalso be defined:

  • #define : SCP_BL2_IMAGE_ID

    SCP_BL2 image identifier, used by BL2 to load SCP_BL2 into secure memoryfrom platform storage before being transferred to the SCP.

  • #define : SCP_FW_KEY_CERT_ID

    SCP_BL2 key certificate identifier, used by BL2 to load the SCP_BL2 keycertificate (mandatory when Trusted Board Boot is enabled).

  • #define : SCP_FW_CONTENT_CERT_ID

    SCP_BL2 content certificate identifier, used by BL2 to load the SCP_BL2content certificate (mandatory when Trusted Board Boot is enabled).

If a BL32 image is supported by the platform, the following constants mustalso be defined:

  • #define : BL32_IMAGE_ID

    BL32 image identifier, used by BL2 to load BL32.

  • #define : TRUSTED_OS_FW_KEY_CERT_ID

    BL32 key certificate identifier, used by BL2 to load the BL32 keycertificate (mandatory when Trusted Board Boot is enabled).

  • #define : TRUSTED_OS_FW_CONTENT_CERT_ID

    BL32 content certificate identifier, used by BL2 to load the BL32 contentcertificate (mandatory when Trusted Board Boot is enabled).

  • #define : BL32_BASE

    Defines the base address in secure memory where BL2 loads the BL32 binaryimage. Must be aligned on a page-size boundary.

  • #define : BL32_LIMIT

    Defines the maximum address that the BL32 image can occupy.

If the Test Secure-EL1 Payload (TSP) instantiation of BL32 is supported by theplatform, the following constants must also be defined:

  • #define : TSP_SEC_MEM_BASE

    Defines the base address of the secure memory used by the TSP image on theplatform. This must be at the same address or belowBL32_BASE.

  • #define : TSP_SEC_MEM_SIZE

    Defines the size of the secure memory used by the BL32 image on theplatform.TSP_SEC_MEM_BASE andTSP_SEC_MEM_SIZE must fullyaccommodate the memory required by the BL32 image, defined byBL32_BASEandBL32_LIMIT.

  • #define : TSP_IRQ_SEC_PHY_TIMER

    Defines the ID of the secure physical generic timer interrupt used by theTSP’s interrupt handling code.

If the platform port uses the translation table library code, the followingconstants must also be defined:

  • #define : PLAT_XLAT_TABLES_DYNAMIC

    Optional flag that can be set per-image to enable the dynamic allocation ofregions even when the MMU is enabled. If not defined, only staticfunctionality will be available, if defined and set to 1 it will alsoinclude the dynamic functionality.

  • #define : MAX_XLAT_TABLES

    Defines the maximum number of translation tables that are allocated by thetranslation table library code. To minimize the amount of runtime memoryused, choose the smallest value needed to map the required virtual addressesfor each BL stage. IfPLAT_XLAT_TABLES_DYNAMIC flag is enabled for a BLimage,MAX_XLAT_TABLES must be defined to accommodate the dynamic regionsas well.

  • #define : MAX_MMAP_REGIONS

    Defines the maximum number of regions that are allocated by the translationtable library code. A region consists of physical base address, virtual baseaddress, size and attributes (Device/Memory, RO/RW, Secure/Non-Secure), asdefined in themmap_region_t structure. The platform defines the regionsthat should be mapped. Then, the translation table library will create thecorresponding tables and descriptors at runtime. To minimize the amount ofruntime memory used, choose the smallest value needed to register therequired regions for each BL stage. IfPLAT_XLAT_TABLES_DYNAMIC flag isenabled for a BL image,MAX_MMAP_REGIONS must be defined to accommodatethe dynamic regions as well.

  • #define : PLAT_VIRT_ADDR_SPACE_SIZE

    Defines the total size of the virtual address space in bytes. For example,for a 32 bit virtual address space, this value should be(1ULL<<32).

  • #define : PLAT_PHY_ADDR_SPACE_SIZE

    Defines the total size of the physical address space in bytes. For example,for a 32 bit physical address space, this value should be(1ULL<<32).

If the platform port uses the IO storage framework, the following constantsmust also be defined:

  • #define : MAX_IO_DEVICES

    Defines the maximum number of registered IO devices. Attempting to registermore devices than this value usingio_register_device() will fail with-ENOMEM.

  • #define : MAX_IO_HANDLES

    Defines the maximum number of open IO handles. Attempting to open more IOentities than this value usingio_open() will fail with -ENOMEM.

  • #define : MAX_IO_BLOCK_DEVICES

    Defines the maximum number of registered IO block devices. Attempting toregister more devices this value usingio_dev_open() will failwith -ENOMEM. MAX_IO_BLOCK_DEVICES should be less than MAX_IO_DEVICES.With this macro, multiple block devices could be supported at the sametime.

If the platform needs to allocate data within the per-cpu data framework inBL31, it should define the following macro. Currently this is only required ifthe platform decides not to use the coherent memory section by undefining theUSE_COHERENT_MEM build flag. In this case, the framework allocates therequired memory within the the per-cpu data to minimize wastage.

  • #define : PLAT_PCPU_DATA_SIZE

    Defines the memory (in bytes) to be reserved within the per-cpu datastructure for use by the platform layer.

The following constants are optional. They should be defined when the platformmemory layout implies some image overlaying like in Arm standard platforms.

  • #define : BL31_PROGBITS_LIMIT

    Defines the maximum address in secure RAM that the BL31’s progbits sectionscan occupy.

  • #define : TSP_PROGBITS_LIMIT

    Defines the maximum address that the TSP’s progbits sections can occupy.

If the platform supports OS-initiated mode, i.e. the build optionPSCI_OS_INIT_MODE is enabled, and if the platform’s maximum power domainlevel for PSCI_CPU_SUSPEND differs fromPLAT_MAX_PWR_LVL, the followingconstant must be defined.

  • #define : PLAT_MAX_CPU_SUSPEND_PWR_LVL

    Defines the maximum power domain level that PSCI_CPU_SUSPEND should apply to.

If the platform port uses the PL061 GPIO driver, the following constant mayoptionally be defined:

  • PLAT_PL061_MAX_GPIOSMaximum number of GPIOs required by the platform. This allows control howmuch memory is allocated for PL061 GPIO controllers. The default value is

    1. $(eval $(call add_define,PLAT_PL061_MAX_GPIOS))

If the platform port uses the partition driver, the following constant mayoptionally be defined:

  • PLAT_PARTITION_MAX_ENTRIESMaximum number of partition entries required by the platform. This allowscontrol how much memory is allocated for partition entries. The defaultvalue is 128.For example, define the build flag inplatform.mk:PLAT_PARTITION_MAX_ENTRIES := 12$(eval $(call add_define,PLAT_PARTITION_MAX_ENTRIES))

  • PLAT_PARTITION_BLOCK_SIZEThe size of partition block. It could be either 512 bytes or 4096 bytes.The default value is 512.For example, define the build flag inplatform.mk:PLAT_PARTITION_BLOCK_SIZE := 4096$(eval $(call add_define,PLAT_PARTITION_BLOCK_SIZE))

If the platform port uses the Arm® Ethos™-N NPU driver, the followingconfiguration must be performed:

  • The NPU SiP service handler must be hooked up. This consists of both theinitial setup (ethosn_smc_setup) and the handler itself(ethosn_smc_handler)

If the platform port uses the Arm® Ethos™-N NPU driver with TZMP1 supportenabled, the following constants and configuration must also be defined:

  • ETHOSN_NPU_PROT_FW_NSAID

    Defines the Non-secure Access IDentity (NSAID) that the NPU shall use toaccess the protected memory that contains the NPU’s firmware.

  • ETHOSN_NPU_PROT_DATA_RW_NSAID

    Defines the Non-secure Access IDentity (NSAID) that the NPU shall use forread/write access to the protected memory that contains inference data.

  • ETHOSN_NPU_PROT_DATA_RO_NSAID

    Defines the Non-secure Access IDentity (NSAID) that the NPU shall use forread-only access to the protected memory that contains inference data.

  • ETHOSN_NPU_NS_RW_DATA_NSAID

    Defines the Non-secure Access IDentity (NSAID) that the NPU shall use forread/write access to the non-protected memory.

  • ETHOSN_NPU_NS_RO_DATA_NSAID

    Defines the Non-secure Access IDentity (NSAID) that the NPU shall use forread-only access to the non-protected memory.

  • ETHOSN_NPU_FW_IMAGE_BASE andETHOSN_NPU_FW_IMAGE_LIMIT

    Defines the physical address range that the NPU’s firmware will be loadedinto and executed from.

  • Configure the platforms TrustZone Controller (TZC) with appropriate regionsof protected memory. At minimum this must include a region for the NPU’sfirmware code and a region for protected inference data, and these must beaccessible using the NSAIDs defined above.

  • Include the NPU firmware and certificates in the FIP.

  • Provide FCONF entries to configure the image source for the NPU firmwareand certificates.

  • Add MMU mappings such that:

  • BL2 can write the NPU firmware into the region defined byETHOSN_NPU_FW_IMAGE_BASE andETHOSN_NPU_FW_IMAGE_LIMIT

  • BL31 (SiP service) can read the NPU firmware from the same region

  • Add the firmware image IDETHOSN_NPU_FW_IMAGE_ID to the list of imagesloaded by BL2.

Please see the reference implementation code for the Juno platform as an example.

The following constant is optional. It should be defined to override the defaultbehaviour of theassert() function (for example, to save memory).

  • PLAT_LOG_LEVEL_ASSERTIfPLAT_LOG_LEVEL_ASSERT is higher or equal thanLOG_LEVEL_VERBOSE,assert() prints the name of the file, the line number and the assertedexpression. Else if it is higher thanLOG_LEVEL_INFO, it prints the filename and the line number. Else if it is lower thanLOG_LEVEL_INFO, itdoesn’t print anything to the console. IfPLAT_LOG_LEVEL_ASSERT isn’tdefined, it defaults toLOG_LEVEL.

If the platform port uses the DRTM feature, the following constants must bedefined:

  • #define : PLAT_DRTM_EVENT_LOG_MAX_SIZE

    Maximum Event Log size used by the platform. Platform can decide the maximumsize of the Event Log buffer, depending upon the highest hash algorithmchosen and the number of components selected to measure during the DRTMexecution flow.

  • #define : PLAT_DRTM_MMAP_ENTRIES

    Number of the MMAP entries used by the DRTM implementation to calculate thesize of address map region of the platform.

6.3.2.File : plat_macros.S [mandatory]

Each platform must ensure a file of this name is in the system include path withthe following macro defined. In the Arm development platforms, this file isfound inplat/arm/board/<plat_name>/include/plat_macros.S.

  • Macro : plat_crash_print_regs

    This macro allows the crash reporting routine to print relevant platformregisters in case of an unhandled exception in BL31. This aids in debuggingand this macro can be defined to be empty in case register reporting is notdesired.

    For instance, GIC or interconnect registers may be helpful fortroubleshooting.

6.4.Handling Reset

BL1 by default implements the reset vector where execution starts from a coldor warm boot. BL31 can be optionally set as a reset vector using theRESET_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 thatthe CPU is placed in a platform-specific state until the primary CPUperforms 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 BL31 image in the same processor mode as it waswhen released from reset.

The following functions need to be implemented by the platform port to enablereset vector code to perform the above tasks.

6.4.1.Function : plat_get_my_entrypoint() [mandatory when PROGRAMMABLE_RESET_ADDRESS == 0]

Argument:voidReturn:uintptr_t

This function is called with the MMU and caches disabled(SCTLR_EL3.M = 0 andSCTLR_EL3.C = 0). The function is responsible fordistinguishing between a warm and cold reset for the current CPU usingplatform-specific means. If it’s a warm reset, then it returns the warmreset entrypoint point provided toplat_setup_psci_ops() duringBL31 initialization. If it’s a cold reset then this function must return zero.

This function does not follow the Procedure Call Standard used by theApplication Binary Interface for the Arm 64-bit architecture. The caller shouldnot assume that callee saved registers are preserved across a call to thisfunction.

This function fulfills requirement 1 and 3 listed above.

Note that for platforms that support programming the reset address, it isexpected that a CPU will start executing code directly at the right address,both on a cold and warm reset. In this case, there is no need to identify thetype of reset nor to query the warm reset entrypoint. Therefore, implementingthis function is not required on such platforms.

6.4.2.Function : plat_secondary_cold_boot_setup() [mandatory when COLD_BOOT_SINGLE_CPU == 0]

Argument:void

This function is called with the MMU and data caches disabled. It is responsiblefor placing the executing secondary CPU in a platform-specific state until theprimary CPU performs the necessary actions to bring it out of that state andallow entry into the OS. This function must not return.

In the Arm FVP port, when using the normal boot flow, each secondary CPU powersitself off. The primary CPU is responsible for powering up the secondary CPUswhen normal world software requires them. When booting an EL3 payload instead,they stay powered on and are put in a holding pen until their mailbox getspopulated.

This function fulfills requirement 2 above.

Note that for platforms that can’t release secondary CPUs out of reset, only theprimary CPU will execute the cold boot code. Therefore, implementing thisfunction is not required on such platforms.

6.4.3.Function : plat_is_my_cpu_primary() [mandatory when COLD_BOOT_SINGLE_CPU == 0]

Argument:voidReturn:unsignedint

This function identifies whether the current CPU is the primary CPU or asecondary CPU. A return value of zero indicates that the CPU is not theprimary CPU, while a non-zero return value indicates that the CPU is theprimary CPU.

Note that for platforms that can’t release secondary CPUs out of reset, only theprimary CPU will execute the cold boot code. Therefore, there is no need todistinguish between primary and secondary CPUs and implementing this function isnot required.

6.4.4.Function : platform_mem_init() [mandatory]

Argument:voidReturn:void

This function is called before any access to data is made by the firmware, inorder to carry out any essential memory initialization.

6.4.5.Function: plat_get_rotpk_info()

Argument:void*,void**,unsignedint*,unsignedint*Return:int

This function is mandatory when Trusted Board Boot is enabled. It returns apointer to the ROTPK stored in the platform (or a hash of it) and its length.The ROTPK must be encoded in DER format according to the following ASN.1structure:

AlgorithmIdentifier::=SEQUENCE{algorithmOBJECTIDENTIFIER,parametersANYDEFINEDBYalgorithmOPTIONAL}SubjectPublicKeyInfo::=SEQUENCE{algorithmAlgorithmIdentifier,subjectPublicKeyBITSTRING}

In case the function returns a hash of the key:

DigestInfo::=SEQUENCE{digestAlgorithmAlgorithmIdentifier,digestOCTETSTRING}

The function returns 0 on success. Any other value is treated as error by theTrusted Board Boot. The function also reports extra information relatedto the ROTPK in the flags parameter:

ROTPK_IS_HASH:IndicatesthattheROTPKreturnedbytheplatformisahash.ROTPK_NOT_DEPLOYED:ThisallowstheplatformtoskipcertificateROTPKverificationwhiletheplatformROTPKisnotdeployed.Whenthisflagisset,thefunctiondoesnotneedtoreturnaplatformROTPK,andtheauthenticationframeworkusestheROTPKinthecertificatewithoutverifyingitagainsttheplatformvalue.Thisflagmustnotbeusedinadeployedproductionenvironment.

6.4.6.Function: plat_get_nv_ctr()

Argument:void*,unsignedint*Return:int

This function is mandatory when Trusted Board Boot is enabled. It returns thenon-volatile counter value stored in the platform in the second argument. Thecookie in the first argument may be used to select the counter in case theplatform provides more than one (for example, on platforms that use the defaultTBBR CoT, the cookie will correspond to the OID values defined inTRUSTED_FW_NVCOUNTER_OID or NON_TRUSTED_FW_NVCOUNTER_OID).

The function returns 0 on success. Any other value means the counter value couldnot be retrieved from the platform.

6.4.7.Function: plat_set_nv_ctr()

Argument:void*,unsignedintReturn:int

This function is mandatory when Trusted Board Boot is enabled. It sets a newcounter value in the platform. The cookie in the first argument may be used toselect the counter (as explained in plat_get_nv_ctr()). The second argument isthe updated counter value to be written to the NV counter.

The function returns 0 on success. Any other value means the counter value couldnot be updated.

6.4.8.Function: plat_set_nv_ctr2()

Argument:void*,constauth_img_desc_t*,unsignedintReturn:int

This function is optional when Trusted Board Boot is enabled. If thisinterface is defined, thenplat_set_nv_ctr() need not be defined. Thefirst argument passed is a cookie and is typically used todifferentiate between a Non Trusted NV Counter and a Trusted NVCounter. The second argument is a pointer to an authentication imagedescriptor and may be used to decide if the counter is allowed to beupdated or not. The third argument is the updated counter value tobe written to the NV counter.

The function returns 0 on success. Any other value means the counter valueeither could not be updated or the authentication image descriptor indicatesthat it is not allowed to be updated.

6.5.Dynamic Root of Trust for Measurement support (in BL31)

The functions mentioned in this section are mandatory, when platform enablesDRTM_SUPPORT build flag.

6.5.1.Function : plat_get_addr_mmap()

Argument:voidReturn:constmmap_region_t*

This function is used to return the address of the platformaddress-map table,which describes the regions of normal memory, memory mapped I/Oand non-volatile memory.

6.5.2.Function : plat_has_non_host_platforms()

Argument:voidReturn:bool

This function returnstrue if the platform has any trusted devices capable ofDMA, otherwise returnsfalse.

6.5.3.Function : plat_has_unmanaged_dma_peripherals()

Argument:voidReturn:bool

This function returnstrue if platform uses peripherals whose DMA is notmanaged by an SMMU, otherwise returnsfalse.

Note -If the platform has peripherals that are not managed by the SMMU, then theplatform should investigate such peripherals to determine whether they canbe trusted, and such peripherals should be moved under “Non-host platforms”if they can be trusted.

6.5.4.Function : plat_get_total_num_smmus()

Argument:voidReturn:unsignedint

This function returns the total number of SMMUs in the platform.

6.5.5.Function : plat_enumerate_smmus()

Argument:voidReturn:constuintptr_t*,size_t

This function returns an array of SMMU addresses and the actual number of SMMUsreported by the platform.

6.5.6.Function : plat_drtm_get_dma_prot_features()

Argument:voidReturn:constplat_drtm_dma_prot_features_t*

This function returns the address of plat_drtm_dma_prot_features_t structurecontaining the maximum number of protected regions and bitmap with the typesof DMA protection supported by the platform.For more details see section 3.3 Table 6 ofDRTM specification.

6.5.7.Function : plat_drtm_dma_prot_get_max_table_bytes()

Argument:voidReturn:uint64_t

This function returns the maximum size of DMA protected regions table inbytes.

6.5.8.Function : plat_drtm_get_tpm_features()

Argument:voidReturn:constplat_drtm_tpm_features_t*

This function returns the address ofplat_drtm_tpm_features_t structurecontaining PCR usage schema, TPM-based hash, and firmware hash algorithmsupported by the platform.

6.5.9.Function : plat_drtm_get_min_size_normal_world_dce()

Argument:voidReturn:uint64_t

This function returns the size normal-world DCE of the platform.

6.5.10.Function : plat_drtm_get_imp_def_dlme_region_size()

Argument:voidReturn:uint64_t

This function returns the size of implementation defined DLME regionof the platform.

6.5.11.Function : plat_drtm_get_tcb_hash_table_size()

Argument:voidReturn:uint64_t

This function returns the size of TCB hash table of the platform.

6.5.12.Function : plat_drtm_get_acpi_tables_region_size()

Argument:voidReturn:uint64_t

This function returns the size of ACPI tables region of the platform.

6.5.13.Function : plat_drtm_get_tcb_hash_features()

Argument:voidReturn:uint64_t

This function returns the Maximum number of TCB hashes recorded by theplatform.For more details see section 3.3 Table 6 ofDRTM specification.

6.5.14.Function : plat_drtm_get_dlme_img_auth_features()

Argument:voidReturn:uint64_t

This function returns the DLME image authentication features.For more details see section 3.3 Table 6 ofDRTM specification.

6.5.15.Function : plat_drtm_validate_ns_region()

Argument:uintptr_t,uintptr_tReturn:int

This function validates that given region is within the Non-Secure regionof DRAM. This function takes a region start address and size an inputarguments, and returns 0 on success and -1 on failure.

6.5.16.Function : plat_set_drtm_error()

Argument:uint64_tReturn:int

This function writes a 64 bit error code received as input intonon-volatile storage and returns 0 on success and -1 on failure.

6.5.17.Function : plat_get_drtm_error()

Argument:uint64_t*Return:int

This function reads a 64 bit error code from the non-volatile storageinto the received address, and returns 0 on success and -1 on failure.

6.6.Common mandatory function modifications

The following functions are mandatory functions which need to be implementedby the platform port.

6.6.1.Function : plat_my_core_pos()

Argument:voidReturn:unsignedint

This function returns the index of the calling CPU which is used as aCPU-specific linear index into blocks of memory (for example while allocatingper-CPU stacks). This function will be invoked very early in theinitialization sequence which mandates that this function should beimplemented in assembly and should not rely on the availability of a Cruntime environment. This function can clobber x0 - x8 and must preservex9 - x29.

This function plays a crucial role in the power domain topology framework inPSCI and details of this can be found inPSCI Power Domain Tree Structure.

6.6.2.Function : plat_core_pos_by_mpidr()

Argument:u_register_tReturn:int

This function validates theMPIDR of a CPU and converts it to an index,which can be used as a CPU-specific linear index into blocks of memory. Incase theMPIDR is invalid, this function returns -1. This function will onlybe invoked by BL31 after the power domain topology is initialized and canutilize the C runtime environment. For further details about how TF-Arepresents the power domain topology and how this relates to the linear CPUindex, please referPSCI Power Domain Tree Structure.

6.6.3.Function : plat_get_mbedtls_heap() [when TRUSTED_BOARD_BOOT == 1]

Arguments:void**heap_addr,size_t*heap_sizeReturn:int

This function is invoked during Mbed TLS library initialisation to get a heap,by means of a starting address and a size. This heap will then be usedinternally by the Mbed TLS library. Hence, each BL stage that utilises Mbed TLSmust be able to provide a heap to it.

A helper function can be found indrivers/auth/mbedtls/mbedtls_common.c inwhich a heap is statically reserved during compile time inside every image(i.e. every BL stage) that utilises Mbed TLS. In this default implementation,the function simply returns the address and size of this “pre-allocated” heap.For a platform to use this default implementation, only a call to the helperfrom inside plat_get_mbedtls_heap() body is enough and nothing else is needed.

However, by writting their own implementation, platforms have the potential tooptimise memory usage. For example, on some Arm platforms, the Mbed TLS heap isshared between BL1 and BL2 stages and, thus, the necessary space is not reservedtwice.

On success the function should return 0 and a negative error code otherwise.

6.6.4.Function : plat_get_enc_key_info() [when FW_ENC_STATUS == 0 or 1]

Arguments:enumfw_enc_status_tfw_enc_status,uint8_t*key,size_t*key_len,unsignedint*flags,constuint8_t*img_id,size_timg_id_lenReturn:int

This function provides a symmetric key (either SSK or BSSK depending onfw_enc_status) which is invoked during runtime decryption of encryptedfirmware images.plat/common/plat_bl_common.c provides a dummy weakimplementation for testing purposes which must be overridden by the platformtrying to implement a real world firmware encryption use-case.

It also allows the platform to pass symmetric key identifier rather thanactual symmetric key which is useful in cases where the crypto backend providessecure storage for the symmetric key. So in this caseENC_KEY_IS_IDENTIFIERflag must be set inflags.

In addition to above a platform may also choose to provide an image specificsymmetric key/identifier using img_id.

On success the function should return 0 and a negative error code otherwise.

Note that this API depends onDECRYPTION_SUPPORT build flag.

6.6.5.Function : plat_fwu_set_images_source() [when PSA_FWU_SUPPORT == 1]

Argument:conststructfwu_metadata*metadataReturn:void

This function is mandatory when PSA_FWU_SUPPORT is enabled.It provides a means to retrieve image specification (offset innon-volatile storage and length) of active/updated images using the passedFWU metadata, and update I/O policies of active/updated images using retrievedimage specification information.Further I/O layer operations such as I/O open, I/O read, etc. on theseimages rely on this function call.

In Arm platforms, this function is used to set an I/O policy of the FIP image,container of all active/updated secure and non-secure images.

6.6.6.Function : plat_fwu_set_metadata_image_source() [when PSA_FWU_SUPPORT == 1]

Argument:unsignedintimage_id,uintptr_t*dev_handle,uintptr_t*image_specReturn:int

This function is mandatory when PSA_FWU_SUPPORT is enabled. It isresponsible for setting up the platform I/O policy of the requested metadataimage (either FWU_METADATA_IMAGE_ID or BKUP_FWU_METADATA_IMAGE_ID) that willbe used to load this image from the platform’s non-volatile storage.

FWU metadata can not be always stored as a raw image in non-volatile storageto define its image specification (offset in non-volatile storage and length)statically in I/O policy.For example, the FWU metadata image is stored as a partition inside the GUIDpartition table image. Its specification is defined in the partition tablethat needs to be parsed dynamically.This function provides a means to retrieve such dynamic information to setthe I/O policy of the FWU metadata image.Further I/O layer operations such as I/O open, I/O read, etc. on FWU metadataimage relies on this function call.

It returns ‘0’ on success, otherwise a negative error value on error.Alongside, returns device handle and image specification from the I/O policyof the requested FWU metadata image.

6.6.7.Function : plat_fwu_get_boot_idx() [when PSA_FWU_SUPPORT == 1]

Argument:voidReturn:uint32_t

This function is mandatory when PSA_FWU_SUPPORT is enabled. It provides themeans to retrieve the boot index value from the platform. The boot index is thebank from which the platform has booted the firmware images.

By default, the platform will read the metadata structure and try to boot fromthe active bank. If the platform fails to boot from the active bank due toreasons like an Authentication failure, or on crossing a set number of watchdogresets while booting from the active bank, the platform can then switch to bootfrom a different bank. This function then returns the bank that the platformshould boot its images from.

6.7.Common optional modifications

The following are helper functions implemented by the firmware that performcommon platform-specific tasks. A platform may choose to override thesedefinitions.

6.7.1.Function : plat_set_my_stack()

Argument:voidReturn:void

This function sets the current stack pointer to the normal memory stack thathas been allocated for the current CPU. For BL images that only require astack for the primary CPU, the UP version of the function is used. The sizeof the stack allocated to each CPU is specified by the platform definedconstantPLATFORM_STACK_SIZE.

Common implementations of this function for the UP and MP BL images areprovided inplat/common/aarch64/platform_up_stack.S andplat/common/aarch64/platform_mp_stack.S

6.7.2.Function : plat_get_my_stack()

Argument:voidReturn:uintptr_t

This function returns the base address of the normal memory stack thathas been allocated for the current CPU. For BL images that only require astack for the primary CPU, the UP version of the function is used. The sizeof the stack allocated to each CPU is specified by the platform definedconstantPLATFORM_STACK_SIZE.

Common implementations of this function for the UP and MP BL images areprovided inplat/common/aarch64/platform_up_stack.S andplat/common/aarch64/platform_mp_stack.S

6.7.3.Function : plat_report_exception()

Argument:unsignedintReturn:void

A platform may need to report various information about its status when anexception is taken, for example the current exception level, the CPU securitystate (secure/non-secure), the exception type, and so on. This function iscalled 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 assumptionsabout the way the platform displays its status information.

For AArch64, this function receives the exception type as its argument.Possible values for exceptions types are listed in theinclude/common/bl_common.h header file. Note that these constants are notrelated to any architectural exception code; they are just a TF-A convention.

For AArch32, this function receives the exception mode as its argument.Possible values for exception modes are listed in theinclude/lib/aarch32/arch.h header file.

6.7.4.Function : plat_reset_handler()

Argument:voidReturn:void

A platform may need to do additional initialization after reset. This functionallows the platform to do the platform specific initializations. Platformspecific errata workarounds could also be implemented here. The API shouldpreserve the values of callee saved registers x19 to x29.

The default implementation doesn’t do anything. If a platform needs to overridethe default implementation, refer to theFirmware Design for generalguidelines.

6.7.5.Function : plat_disable_acp()

Argument:voidReturn:void

This API allows a platform to disable the Accelerator Coherency Port (ifpresent) during a cluster power down sequence. The default weak implementationdoesn’t do anything. Since this API is called during the power down sequence,it has restrictions for stack usage and it can use the registers x0 - x17 asscratch registers. It should preserve the value in x18 register as it is usedby the caller to store the return address.

6.7.6.Function : plat_error_handler()

Argument:intReturn:void

This API is called when the generic code encounters an error situation fromwhich it cannot continue. It allows the platform to perform error reporting orrecovery actions (for example, reset the system). This function must not return.

The parameter indicates the type of error using standard codes fromerrno.h.Possible errors reported by the generic code are:

  • -EAUTH: a certificate or image could not be authenticated (when TrustedBoard Boot is enabled)

  • -ENOENT: the requested image or certificate could not be found or an IOerror was detected

  • -ENOMEM: resources exhausted. TF-A does not use dynamic memory, so thiserror is usually an indication of an incorrect array size

The default implementation simply spins.

6.7.7.Function : plat_panic_handler()

Argument:voidReturn:void

This API is called when the generic code encounters an unexpected errorsituation from which it cannot recover. This function must not return,and must be implemented in assembly because it may be called before the Cenvironment is initialized.

Note

The address from where it was called is stored in x30 (Link Register).The default implementation simply spins.

6.7.8.Function : plat_system_reset()

Argument:voidReturn:void

This function is used by the platform to resets the system. It can be usedin any specific use-case where system needs to be resetted. For example,in case of DRTM implementation this function reset the system afterwriting the DRTM error code in the non-volatile storage. This functionnever returns. Failure in reset results in panic.

6.7.9.Function : plat_get_bl_image_load_info()

Argument:voidReturn:bl_load_info_t*

This function returns pointer to the list of images that the platform haspopulated to load. This function is invoked in BL2 to load theBL3xx images.

6.7.10.Function : plat_get_next_bl_params()

Argument:voidReturn:bl_params_t*

This function returns a pointer to the shared memory that the platform haskept aside to pass TF-A related information that next BL image needs. Thisfunction is invoked in BL2 to pass this information to the next BLimage.

6.7.11.Function : plat_get_stack_protector_canary()

Argument:voidReturn:u_register_t

This function returns a random value that is used to initialize the canary usedwhen the stack protector is enabled with ENABLE_STACK_PROTECTOR. A predictablevalue will weaken the protection as the attacker could easily write the rightvalue as part of the attack most of the time. Therefore, it should return atrue random number.

Warning

For the protection to be effective, the global data need to be placed ata lower address than the stack bases. Failure to do so would allow anattacker to overwrite the canary as part of the stack buffer overflow attack.

6.7.12.Function : plat_flush_next_bl_params()

Argument:voidReturn:void

This function flushes to main memory all the image params that are passed tonext image. This function is invoked in BL2 to flush this informationto the next BL image.

6.7.13.Function : plat_log_get_prefix()

Argument:unsignedintReturn:constchar*

This function defines the prefix string corresponding to thelog_level to beprepended to all the log output from TF-A. Thelog_level (argument) willcorrespond to one of the standard log levels defined in debug.h. The platformcan override the common implementation to define a different prefix string forthe log output. The implementation should be robust to future changes thatincrease the number of log levels.

6.7.14.Function : plat_get_soc_version()

Argument:voidReturn:int32_t

This function returns soc version which mainly consist of below fields

soc_version[30:24]=JEP-106continuationcodefortheSiPsoc_version[23:16]=JEP-106identificationcodewithparitybitfortheSiPsoc_version[15:0]=ImplementationdefinedSoCID

6.7.15.Function : plat_get_soc_revision()

Argument:voidReturn:int32_t

This function returns soc revision in below format

soc_revision[0:30]=SOCrevisionofspecificSOC

6.7.16.Function : plat_is_smccc_feature_available()

Argument:u_register_tReturn:int32_t

This function returns SMC_ARCH_CALL_SUCCESS if the platform supportsthe SMCCC function specified in the argument; otherwise returnsSMC_ARCH_CALL_NOT_SUPPORTED.

6.7.17.Function : plat_can_cmo()

Argument:voidReturn:uint64_t

When CONDITIONAL_CMO flag is enabled:

  • This function indicates whether cache management operations should beperformed. It returns 0 if CMOs should be skipped and non-zerootherwise.

  • The function must not clobber x1, x2 and x3. It’s also not safe to rely onstack. Otherwise obey AAPCS.

6.7.18.Struct: plat_try_images_ops [optional]

This optional structure holds platform hooks for alternative images load.It has to be defined in platform code and registered by callingplat_setup_try_img_ops() function, passing it the address of theplat_try_images_ops struct.

6.7.18.1.Function : plat_setup_try_img_ops [optional]

Argument:conststructplat_try_images_ops*Return:void

This optional function is called to register platform try images ops, givenas argument.

6.7.18.2.Function : plat_try_images_ops.next_instance [optional]

Argument:unsignedintimage_idReturn:int

This optional function tries to load images from alternative places.In case PSA FWU is not used, it can be any instance or media. If PSA FWU isused, it is mandatory that the backup image is on the same media.This is required for MTD devices like NAND.The argument is the ID of the image for which we are looking for an alternativeplace. It returns 0 in case of success and a negative errno value otherwise.

6.8.Modifications specific to a Boot Loader stage

6.9.Boot Loader Stage 1 (BL1)

BL1 implements the reset vector where execution starts from after a cold orwarm 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 thatonly this CPU executes the remaining BL1 code, including loading and passingcontrol to the BL2 stage.

  3. Identifying and starting the Firmware Update process (if required).

  4. Loading the BL2 image from non-volatile storage into secure memory at theaddress specified by the platform defined constantBL2_BASE.

  5. Populating ameminfo structure with the following information in memory,accessible by BL2 immediately upon entry.

    meminfo.total_base=BaseaddressofsecureRAMvisibletoBL2meminfo.total_size=SizeofsecureRAMvisibletoBL2

    By default, BL1 places thismeminfo structure at the end of securememory visible to BL2.

    It is possible for the platform to decide where it wants to place thememinfo structure for BL2 or restrict the amount of memory visible toBL2 by overriding the weak default implementation ofbl1_plat_handle_post_image_load API.

The following functions need to be implemented by the platform port to enableBL1 to perform the above tasks.

6.9.1.Function : bl1_early_platform_setup() [mandatory]

Argument:voidReturn:void

This function executes with the MMU and data caches disabled. It is only calledby the primary CPU.

On Arm standard platforms, this function:

  • Enables a secure instance of SP805 to act as the Trusted Watchdog.

  • Initializes a UART (PL011 console), which enables access to theprintffamily of functions in BL1.

  • Enables issuing of snoop and DVM (Distributed Virtual Memory) requests tothe CCI slave interface corresponding to the cluster that includes theprimary CPU.

6.9.2.Function : bl1_plat_arch_setup() [mandatory]

Argument:voidReturn:void

This function performs any platform-specific and architectural setup that theplatform requires. Platform-specific setup might include configuration ofmemory controllers and the interconnect.

In Arm standard platforms, this function enables the MMU.

This function helps fulfill requirement 2 above.

6.9.3.Function : bl1_platform_setup() [mandatory]

Argument:voidReturn:void

This function executes with the MMU and data caches enabled. It is responsiblefor performing any remaining platform-specific setup that can occur after theMMU and data cache have been enabled.

In Arm standard platforms, this function initializes the storage abstractionlayer used to load the next bootloader image.

This function helps fulfill requirement 4 above.

6.9.4.Function : bl1_plat_sec_mem_layout() [mandatory]

Argument:voidReturn:meminfo*

This function should only be called on the cold boot path. It executes with theMMU and data caches enabled. The pointer returned by this function must point toameminfo structure containing the extents and availability of secure RAM forthe BL1 stage.

meminfo.total_base=BaseaddressofsecureRAMvisibletoBL1meminfo.total_size=SizeofsecureRAMvisibletoBL1

This information is used by BL1 to load the BL2 image in secure RAM. BL1 alsopopulates a similar structure to tell BL2 the extents of memory available forits own use.

This function helps fulfill requirements 4 and 5 above.

6.9.5.Function : bl1_plat_prepare_exit() [optional]

Argument:entry_point_info_t*Return:void

This function is called prior to exiting BL1 in response to theBL1_SMC_RUN_IMAGE SMC request raised by BL2. It should be used to performplatform specific clean up or bookkeeping operations before transferringcontrol to the next image. It receives the address of theentry_point_info_tstructure passed from BL2. This function runs with MMU disabled.

6.9.6.Function : bl1_plat_set_ep_info() [optional]

Argument:unsignedintimage_id,entry_point_info_t*ep_infoReturn:void

This function allows platforms to overrideep_info for the givenimage_id.

The default implementation just returns.

6.9.7.Function : bl1_plat_get_next_image_id() [optional]

Argument:voidReturn:unsignedint

This and the following function must be overridden to enable the FWU feature.

BL1 calls this function after platform setup to identify the next image to beloaded and executed. If the platform returnsBL2_IMAGE_ID then BL1 proceedswith the normal boot sequence, which loads and executes BL2. If the platformreturns a different image id, BL1 assumes that Firmware Update is required.

The default implementation always returnsBL2_IMAGE_ID. The Arm developmentplatforms override this function to detect if firmware update is required, andif so, return the first image in the firmware update process.

6.9.8.Function : bl1_plat_get_image_desc() [optional]

Argument:unsignedintimage_idReturn:image_desc_t*

BL1 calls this function to get the image descriptor informationimage_desc_tfor the providedimage_id from the platform.

The default implementation always returns a common BL2 image descriptor. Armstandard platforms return an image descriptor corresponding to BL2 or one ofthe firmware update images defined in the Trusted Board Boot Requirementsspecification.

6.9.9.Function : bl1_plat_handle_pre_image_load() [optional]

Argument:unsignedintimage_idReturn:int

This function can be used by the platforms to update/use image informationcorresponding toimage_id. This function is invoked in BL1, both in coldboot and FWU code path, before loading the image.

6.9.10.Function : bl1_plat_calc_bl2_layout() [optional]

Argument:constmeminfo_t*bl1_mem_layout,meminfo_t*bl2_mem_layoutReturn:void

This utility function calculates the memory layout of BL2, representing it in ameminfo_t structure. The default implementation derives this layout from thepositioning of BL1’s RW data at the top of the memory layout.

6.9.11.Function : bl1_plat_handle_post_image_load() [optional]

Argument:unsignedintimage_idReturn:int

This function can be used by the platforms to update/use image informationcorresponding toimage_id. This function is invoked in BL1, both in coldboot and FWU code path, after loading and authenticating the image.

The default weak implementation of this function calculates the amount ofTrusted SRAM that can be used by BL2 and allocates ameminfo_tstructure at the beginning of this free memory and populates it. The addressofmeminfo_t structure is updated inarg1 of the entrypointinformation to BL2.

6.9.12.Function : bl1_plat_fwu_done() [optional]

Argument:unsignedintimage_id,uintptr_timage_src,unsignedintimage_sizeReturn:void

BL1 calls this function when the FWU process is complete. It must not return.The platform may override this function to take platform specific action, forexample to initiate the normal boot flow.

The default implementation spins forever.

6.9.13.Function : bl1_plat_mem_check() [mandatory]

Argument:uintptr_tmem_base,unsignedintmem_size,unsignedintflagsReturn:int

BL1 calls this function while handling FWU related SMCs, more specifically whencopying or authenticating an image. Its responsibility is to ensure that theregion of memory identified bymem_base andmem_size is mapped in BL1, andthat this memory corresponds to either a secure or non-secure memory region asindicated by the security state of theflags argument.

This function can safely assume that the value resulting from the addition ofmem_base andmem_size fits into auintptr_t type variable and does notoverflow.

This function must return 0 on success, a non-null error code otherwise.

The default implementation of this function asserts therefore platforms mustoverride it when using the FWU feature.

6.10.Boot Loader Stage 2 (BL2)

The BL2 stage is executed only by the primary CPU, which is determined in BL1using theplatform_is_primary_cpu() function. BL1 passed control to BL2 atBL2_BASE. BL2 executes in Secure EL1 and and invokesplat_get_bl_image_load_info() to retrieve the list of images to load fromnon-volatile storage to secure/non-secure RAM. After all the images are loadedthen BL2 invokesplat_get_next_bl_params() to get the list of executableimages to be passed to the next BL image.

The following functions must be implemented by the platform port to enable BL2to perform the above tasks.

6.10.1.Function : bl2_early_platform_setup2() [mandatory]

Argument:u_register_t,u_register_t,u_register_t,u_register_tReturn:void

This function executes with the MMU and data caches disabled. It is only calledby the primary CPU. The 4 arguments are passed by BL1 to BL2 and these argumentsare platform specific.

On Arm standard platforms, the arguments received are :

arg0 - Points to load address of FW_CONFIG

arg1 -meminfo structure populated by BL1. The platform copiesthe contents ofmeminfo as it may be subsequently overwritten by BL2.

On Arm standard platforms, this function also:

  • Initializes a UART (PL011 console), which enables access to theprintffamily of functions in BL2.

  • Initializes the storage abstraction layer used to load further bootloaderimages. It is necessary to do this early on platforms with a SCP_BL2 image,since the laterbl2_platform_setup must be done after SCP_BL2 is loaded.

6.10.2.Function : bl2_plat_arch_setup() [mandatory]

Argument:voidReturn:void

This function executes with the MMU and data caches disabled. It is only calledby the primary CPU.

The purpose of this function is to perform any architectural initializationthat varies across platforms.

On Arm standard platforms, this function enables the MMU.

6.10.3.Function : bl2_platform_setup() [mandatory]

Argument:voidReturn:void

This function may execute with the MMU and data caches enabled if the platformport does the necessary initialization inbl2_plat_arch_setup(). It is onlycalled by the primary CPU.

The purpose of this function is to perform any platform initializationspecific to BL2.

In Arm standard platforms, this function performs security setup, includingconfiguration of the TrustZone controller to allow non-secure masters accessto most of DRAM. Part of DRAM is reserved for secure world use.

6.10.4.Function : bl2_plat_handle_pre_image_load() [optional]

Argument:unsignedintReturn:int

This function can be used by the platforms to update/use image informationfor givenimage_id. This function is currently invoked in BL2 beforeloading each image.

6.10.5.Function : bl2_plat_handle_post_image_load() [optional]

Argument:unsignedintReturn:int

This function can be used by the platforms to update/use image informationfor givenimage_id. This function is currently invoked in BL2 afterloading each image.

6.10.6.Function : bl2_plat_preload_setup [optional]

Argument:voidReturn:void

This optional function performs any BL2 platform initializationrequired before image loading, that is not done later inbl2_platform_setup().

6.11.Boot Loader Stage 2 (BL2) at EL3

When the platform has a non-TF-A Boot ROM it is desirable to jumpdirectly to BL2 instead of TF-A BL1. In this case BL2 is expected toexecute at EL3 instead of executing at EL1. Refer to theFirmware Designdocument for more information.

All mandatory functions of BL2 must be implemented, except the functionsbl2_early_platform_setup and bl2_el3_plat_arch_setup, becausetheir work is done now by bl2_el3_early_platform_setup andbl2_el3_plat_arch_setup. These functions should generally implementthe bl1_plat_xxx() and bl2_plat_xxx() functionality combined.

6.11.1.Function : bl2_el3_early_platform_setup() [mandatory]

Argument:u_register_t,u_register_t,u_register_t,u_register_tReturn:void

This function executes with the MMU and data caches disabled. It is only calledby the primary CPU. This function receives four parameters which can be usedby the platform to pass any needed information from the Boot ROM to BL2.

On Arm standard platforms, this function does the following:

  • Initializes a UART (PL011 console), which enables access to theprintffamily of functions in BL2.

  • Initializes the storage abstraction layer used to load further bootloaderimages. It is necessary to do this early on platforms with a SCP_BL2 image,since the laterbl2_platform_setup must be done after SCP_BL2 is loaded.

  • Initializes the private variables that define the memory layout used.

6.11.2.Function : bl2_el3_plat_arch_setup() [mandatory]

Argument:voidReturn:void

This function executes with the MMU and data caches disabled. It is only calledby the primary CPU.

The purpose of this function is to perform any architectural initializationthat varies across platforms.

On Arm standard platforms, this function enables the MMU.

6.11.3.Function : bl2_el3_plat_prepare_exit() [optional]

Argument:voidReturn:void

This function is called prior to exiting BL2 and run the next image.It should be used to perform platform specific clean up or bookkeepingoperations before transferring control to the next image. This functionruns with MMU disabled.

6.12.FWU Boot Loader Stage 2 (BL2U)

The AP Firmware Updater Configuration, BL2U, is an optional part of the FWUprocess and is executed only by the primary CPU. BL1 passes control to BL2U atBL2U_BASE. BL2U executes in Secure-EL1 and is responsible for:

  1. (Optional) Transferring the optional SCP_BL2U binary image from AP securememory to SCP RAM. BL2U uses the SCP_BL2Uimage_info passed by BL1.SCP_BL2U_BASE defines the address in AP secure memory where SCP_BL2Ushould be copied from. Subsequent handling of the SCP_BL2U image isimplemented by the platform specificbl2u_plat_handle_scp_bl2u() function.IfSCP_BL2U_BASE is not defined then this step is not performed.

  2. Any platform specific setup required to perform the FWU process. Forexample, Arm standard platforms initialize the TZC controller so that thenormal world can access DDR memory.

The following functions must be implemented by the platform port to enableBL2U to perform the tasks mentioned above.

6.12.1.Function : bl2u_early_platform_setup() [mandatory]

Argument:meminfo*mem_info,void*plat_infoReturn:void

This function executes with the MMU and data caches disabled. It is onlycalled by the primary CPU. The arguments to this function is the addressof thememinfo structure and platform specific info provided by BL1.

The platform may copy the contents of themem_info andplat_info intoprivate storage as the original memory may be subsequently overwritten by BL2U.

On Arm CSS platformsplat_info is interpreted as animage_info_t structure,to extract SCP_BL2U image information, which is then copied into a privatevariable.

6.12.2.Function : bl2u_plat_arch_setup() [mandatory]

Argument:voidReturn:void

This function executes with the MMU and data caches disabled. It is onlycalled by the primary CPU.

The purpose of this function is to perform any architectural initializationthat varies across platforms, for example enabling the MMU (since the memorymap differs across platforms).

6.12.3.Function : bl2u_platform_setup() [mandatory]

Argument:voidReturn:void

This function may execute with the MMU and data caches enabled if the platformport does the necessary initialization inbl2u_plat_arch_setup(). It is onlycalled by the primary CPU.

The purpose of this function is to perform any platform initializationspecific to BL2U.

In Arm standard platforms, this function performs security setup, includingconfiguration of the TrustZone controller to allow non-secure masters accessto most of DRAM. Part of DRAM is reserved for secure world use.

6.12.4.Function : bl2u_plat_handle_scp_bl2u() [optional]

Argument:voidReturn:int

This function is used to perform any platform-specific actions required tohandle the SCP firmware. Typically it transfers the image into SCP memory usinga platform-specific protocol and waits until SCP executes it and signals to theApplication Processor (AP) for BL2U execution to continue.

This function returns 0 on success, a negative error code otherwise.This function is included if SCP_BL2U_BASE is defined.

6.13.Boot Loader Stage 3-1 (BL31)

During cold boot, the BL31 stage is executed only by the primary CPU. This isdetermined in BL1 using theplatform_is_primary_cpu() function. BL1 passescontrol to BL31 atBL31_BASE. During warm boot, BL31 is executed by allCPUs. BL31 executes at EL3 and is responsible for:

  1. Re-initializing all architectural and platform state. Although BL1 performssome of this initialization, BL31 remains resident in EL3 and must ensurethat EL3 architectural and platform state is completely initialized. Itshould 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. On ARM platforms, BL31 uses thebl_params listpopulated by BL2 in memory to do this.

  3. Providing runtime firmware services. Currently, BL31 only implements asubset of the Power State Coordination Interface (PSCI) API as a runtimeservice. SeePower State Coordination Interface (in BL31) below for details of porting the PSCIimplementation.

  4. Optionally passing control to the BL32 image, pre-loaded at a platform-specific address by BL2. BL31 exports a set of APIs that allow runtimeservices to specify the security state in which the next image should beexecuted and run the corresponding image. On ARM platforms, BL31 uses thebl_params list populated by BL2 in memory to do this.

If BL31 is a reset vector, It also needs to handle the reset as specified insection 2.2 before the tasks described above.

The following functions must be implemented by the platform port to enable BL31to perform the above tasks.

6.13.1.Function : bl31_early_platform_setup2() [mandatory]

Argument:u_register_t,u_register_t,u_register_t,u_register_tReturn:void

This function executes with the MMU and data caches disabled. It is only calledby the primary CPU. BL2 can pass 4 arguments to BL31 and these arguments areplatform specific.

In Arm standard platforms, the arguments received are :

arg0 - The pointer to the head ofbl_params_t listwhich is list of executable images following BL31,

arg1 - Points to load address of SOC_FW_CONFIG if present

except in case of Arm FVP and Juno platform.

In case of Arm FVP and Juno platform, points to load addressof FW_CONFIG.

arg2 - Points to load address of HW_CONFIG if present

arg3 - A special value to verify platform parameters from BL2 to BL31. Notused in release builds.

The function runs through thebl_param_t list and extracts the entry pointinformation for BL32 and BL33. It also performs the following:

  • Initialize a UART (PL011 console), which enables access to theprintffamily of functions in BL31.

  • Enable issuing of snoop and DVM (Distributed Virtual Memory) requests to theCCI slave interface corresponding to the cluster that includes the primaryCPU.

6.13.2.Function : bl31_plat_arch_setup() [mandatory]

Argument:voidReturn:void

This function executes with the MMU and data caches disabled. It is only calledby the primary CPU.

The purpose of this function is to perform any architectural initializationthat varies across platforms.

On Arm standard platforms, this function enables the MMU.

6.13.3.Function : bl31_platform_setup() [mandatory]

Argument:voidReturn:void

This function may execute with the MMU and data caches enabled if the platformport does the necessary initialization inbl31_plat_arch_setup(). It is onlycalled by the primary CPU.

The purpose of this function is to complete platform initialization so that bothBL31 runtime services and normal world software can function correctly.

On Arm standard platforms, this function does the following:

  • Initialize the generic interrupt controller.

    Depending on the GIC driver selected by the platform, the appropriate GICv2or GICv3 initialization will be done, which mainly consists of:

    • Enable secure interrupts in the GIC CPU interface.

    • Disable the legacy interrupt bypass mechanism.

    • Configure the priority mask register to allow interrupts of all prioritiesto be signaled to the CPU interface.

    • Mark SGIs 8-15 and the other secure interrupts on the platform as secure.

    • Target all secure SPIs to CPU0.

    • Enable these secure interrupts in the GIC distributor.

    • Configure all other interrupts as non-secure.

    • Enable signaling of secure interrupts in the GIC distributor.

  • Enable system-level implementation of the generic timer counter through thememory mapped interface.

  • Grant access to the system counter timer module

  • Initialize the power controller device.

    In particular, initialise the locks that prevent concurrent accesses to thepower controller device.

6.13.4.Function : bl31_plat_runtime_setup() [optional]

Argument:voidReturn:void

The purpose of this function is to allow the platform to perform any BL31 runtimesetup just prior to BL31 exit during cold boot. The default weak implementationof this function is empty. Any platform that needs to perform additional runtimesetup, before BL31 exits, will need to override this function.

6.13.5.Function : bl31_plat_get_next_image_ep_info() [mandatory]

Argument:uint32_tReturn:entry_point_info*

This function may execute with the MMU and data caches enabled if the platformport does the necessary initializations inbl31_plat_arch_setup().

This function is called bybl31_main() to retrieve information provided byBL2 for the next image in the security state specified by the argument. BL31uses this information to pass control to that image in the specified securitystate. This function must return a pointer to theentry_point_info structure(that was copied duringbl31_early_platform_setup()) if the image exists. Itshould return NULL otherwise.

6.13.6.Function : plat_rmmd_get_cca_attest_token() [mandatory when ENABLE_RME == 1]

Argument:uintptr_t,size_t*,uintptr_t,size_t,size_t*Return:int

This function returns the Platform attestation token. If the full token doesnot fit in the buffer, the function will return a hunk of the token andindicate how many bytes were copied and how many are pending. Multiple callsto this function may be needed to retrieve the entire token.

The parameters of the function are:

arg0 - A pointer to the buffer where the Platform token should be copied by

this function. If the platform token does not completely fit in thebuffer, the function may return a piece of the token only.

arg1 - Contains the size (in bytes) of the buffer passed in arg0. In

addition, this parameter is used by the function to return the sizeof the platform token length hunk copied to the buffer.

arg2 - A pointer to the buffer where the challenge object is stored.

arg3 - The length of the challenge object in bytes. Possible values are 32,

48 and 64. This argument must be zero for subsequent calls toretrieve the remaining hunks of the token.

arg4 - Returns the remaining length of the token (in bytes) that is yet to

be returned in further calls.

The function returns 0 on success, -EINVAL on failure and -EAGAIN if theresource associated with the platform token retrieval is busy.

6.13.7.Function : plat_rmmd_get_cca_realm_attest_key() [mandatory when ENABLE_RME == 1]

Argument:uintptr_t,size_t*,unsignedintReturn:int

This function returns the delegated realm attestation key which will be used tosign Realm attestation token. The API currently only supports P-384 ECC curvekey.

The parameters of the function are:

arg0 - A pointer to the buffer where the attestation key should be copied

by this function. The buffer must be big enough to hold theattestation key.

arg1 - Contains the size (in bytes) of the buffer passed in arg0. The

function returns the attestation key length in this parameter.

arg2 - The type of the elliptic curve to which the requested attestation key

belongs.

The function returns 0 on success, -EINVAL on failure.

6.13.8.Function : plat_rmmd_get_el3_rmm_shared_mem() [when ENABLE_RME == 1]

Argument:uintptr_t*Return:size_t

This function returns the size of the shared area between EL3 and RMM (or 0 onfailure). A pointer to the shared area (or a NULL pointer on failure) is storedin the pointer passed as argument.

6.13.9.Function : plat_rmmd_load_manifest() [when ENABLE_RME == 1]

Arguments:rmm_manifest_t*manifestReturn:int

When ENABLE_RME is enabled, this function populates a boot manifest for theRMM image and stores it in the area specified by manifest.

When ENABLE_RME is disabled, this function is not used.

6.13.10.Function : plat_rmm_mecid_key_update() [when ENABLE_RME == 1]

Argument:uint16_tReturn:int

This function is invoked by BL31’s RMMD when there is a request from the RMMmonitor to update the tweak for the encryption key associated to a MECID.

The first parameter (uint16_tmecid) contains the MECID for which theencryption key is to be updated.

Return value is 0 upon success and -EFAULT otherwise.

This function needs to be implemented by a platform if it enables RME.

6.13.11.Function : plat_rmmd_el3_token_sign_push_req() [mandatory when RMMD_ENABLE_EL3_TOKEN_SIGN == 1]

Arguments:conststructel3_token_sign_request*reqReturn:int

Queue realm attestation token signing request from the RMM in EL3. The interface betweenthe RMM and EL3 is modeled as a queue but the underlying implementation may be different,so long as the semantics of queuing and the error codes are used as defined below.

SeeEL3 Token Sign Request structure for definition of the request structure.

Optional interface from the RMM-EL3 interface v0.4 onwards.

The parameters of the functions are:

arg0: Pointer to the token sign request to be pushed to EL3.The structure must be located in the RMM-EL3 sharedmemory buffer and must be locked before use.

Return codes:
  • E_RMM_OK On Success.

  • E_RMM_INVAL If the arguments are invalid.

  • E_RMM_AGAIN Indicates that the request was not queued since thequeue in EL3 is full. This may also be returned for any reasonor situation in the system, that prevents accepting the requestfrom the RMM.

  • E_RMM_UNK If the SMC is not implemented or if interfaceversion is < 0.4.

6.13.12.Function : plat_rmmd_el3_token_sign_pull_resp() [mandatory when RMMD_ENABLE_EL3_TOKEN_SIGN == 1]

Arguments:structel3_token_sign_response*respReturn:int

Populate the attestation signing response in theresp parameter. The interface betweenthe RMM and EL3 is modeled as a queue for responses but the underlying implementation maybe different, so long as the semantics of queuing and the error codes are used as definedbelow.

SeeEL3 Token Sign Response structure for definition of the response structure.

Optional interface from the RMM-EL3 interface v0.4 onwards.

The parameters of the functions are:

resp: Pointer to the token sign response to get from EL3.The structure must be located in the RMM-EL3 sharedmemory buffer and must be locked before use.

Return:
  • E_RMM_OK On Success.

  • E_RMM_INVAL If the arguments are invalid.

  • E_RMM_AGAIN Indicates that a response is not ready yet.

  • E_RMM_UNK If the SMC is not implemented or if interfaceversion is < 0.4.

6.13.13.Function : plat_rmmd_el3_token_sign_get_rak_pub() [mandatory when RMMD_ENABLE_EL3_TOKEN_SIGN == 1]

Argument:uintptr_t,size_t*,unsignedintReturn:int

This function returns the public portion of the realm attestation key which will be used tosign Realm attestation token. Typically, with delegated attestation, the private key isreturned, however, there may be platforms where the private key bits are better protectedin a platform specific manner such that the private key is not exposed. In such cases,the RMM will only cache the public key and forward any requests such as signing, thatuses the private key to EL3. The API currently only supports P-384 ECC curve key.

This is an optional interface from the RMM-EL3 interface v0.4 onwards.

The parameters of the function are:

arg0 - A pointer to the buffer where the public key should be copiedby this function. The buffer must be big enough to hold theattestation key.

arg1 - Contains the size (in bytes) of the buffer passed in arg0. Thefunction returns the attestation key length in this parameter.

arg2 - The type of the elliptic curve to which the requested attestation keybelongs.

The function returns E_RMM_OK on success, RMM_E_INVAL if arguments are invalid andE_RMM_UNK if the SMC is not implemented or if interface version is < 0.4.

6.13.14.Function : plat_rmmd_el3_ide_key_program() [mandatory when RMMD_ENABLE_IDE_KEY_PROG == 1]

Argument:uint64_t,uint64_t,uint64_t,structrp_ide_key_info_t*,uint64_t,uint64_tReturn:int

This function sets the key/IV info for an IDE stream at the Root port. The key is 256 bitsand IV is 96 bits. The caller calls this SMC to program this key to the Rx and Tx portsand for each substream corresponding to a single keyset. The platform should validatethe argumentsEcam address andRootport ID before acting on it. The argumentsrequest IDandcookie are to be ignored for blocking mode and are pass-through to the response fornon-blocking mode.

The platform needs to ensure proper exclusives are in place when accessed from multiple CPUs.Depending on the expected latency for IDE-KM interface, the platform should choose blockingor non-blocking semantics. More details about IDE Setup flow can be foundin thisRFC.

The parameters of the function are:

arg0 - The ecam address, to access and configure PCI devices in a system.

arg1 - The rootport ID used to identify the PCIe rootport of a connected device.

arg2 - The IDE stream info associated with a physical device, this parameter packs thethe keyset, direction, substream and stream ID info.

arg3 - Structure with key and IV info.

arg4 - The request ID, is used in non-blocking mode only and can be ignored in blocking mode.

arg5 - The cookie variable, is used in non-blocking mode only and can be ignored in blockingmode.

The function returns E_RMM_OK on success, E_RMM_INVAL if arguments are invalid, E_RMM_FAULTif the key programming is unsuccesful, E_RMM_UNK for an unknown error, E_RMM_AGAIN returnedonly for non-blocking mode if the IDE-KM interface is busy or the request queue is full.E_RMM_INPROGRESS returned if the request is queued successfully and used only in non-blockingmode.

6.13.15.Function : plat_rmmd_el3_ide_key_set_go() [mandatory when RMMD_ENABLE_IDE_KEY_PROG == 1]

Argument:uint64_t,uint64_t,uint64_t,uint64_t,uint64_tReturn:int

This function activates the IDE stream at the Root Port once all the keys have beenprogrammed. The platform should validate the argumentsEcam address andRootport IDbefore acting on it. The argumentsrequest ID andcookie are to be ignored for blockingmode and are pass-through to the response for non-blocking mode.

The platform needs to ensure proper exclusives are in place when accessed from multiple CPUs.Depending on the expected latency for IDE-KM interface, the platform should choose blockingor non-blocking semantics. More details about IDE Setup flow can be foundin thisRFC.

The parameters of the function are:

arg0 - The ecam address, to access and configure PCI devices in a system.

arg1 - The rootport ID used to identify the PCIe rootport of a connected device.

arg2 - The IDE stream info associated with a physical device, this parameter packs thethe keyset, direction, substream and stream ID info.

arg3 - The request ID, is used in non-blocking mode only and can be ignored in blocking mode.

arg4 - The cookie variable, is used in non-blocking mode only and can be ignored in blockingmode.

The function returns E_RMM_OK on success, E_RMM_INVAL if arguments are invalid, E_RMM_FAULTif the key programming is unsuccesful, E_RMM_UNK for an unknown error, E_RMM_AGAIN returnedonly for non-blocking mode if the IDE-KM interface is busy or the request queue is full.E_RMM_INPROGRESS returned if the request is queued successfully and used only in non-blockingmode.

6.13.16.Function : plat_rmmd_el3_ide_key_set_stop() [mandatory when RMMD_ENABLE_IDE_KEY_PROG == 1]

Argument:uint64_t,uint64_t,uint64_t,uint64_t,uint64_tReturn:int

This function stops the IDE stream and is used to tear down the IDE stream at Root Port.The platform should validate the argumentsEcam address andRootport ID before actingon it. The argumentsrequest ID andcookie are to be ignored for blockingmode and are pass-through to the response for non-blocking mode.

The platform needs to ensure proper exclusives are in place when accessed from multiple CPUs.Depending on the expected latency for IDE-KM interface, the platform should choose blockingor non-blocking semantics. More details about IDE Setup flow can be foundin thisRFC.

The parameters of the function are:

arg0 - The ecam address, to access and configure PCI devices in a system.

arg1 - The rootport ID used to identify the PCIe rootport of a connected device.

arg2 - The IDE stream info associated with a physical device, this parameter packs thethe keyset, direction, substream and stream ID info.

arg3 - The request ID, is used in non-blocking mode only and can be ignored in blocking mode.

arg4 - The cookie variable, is used in non-blocking mode only and can be ignored in blockingmode.

The function returns E_RMM_OK on success, E_RMM_INVAL if arguments are invalid, E_RMM_FAULTif the key programming is unsuccesful, E_RMM_UNK for an unknown error, E_RMM_AGAIN returnedonly for non-blocking mode if the IDE-KM interface is busy or the request queue is full.E_RMM_INPROGRESS returned if the request is queued successfully and used only in non-blockingmode.

6.13.17.Function : plat_rmmd_el3_ide_km_pull_response() [mandatory when RMMD_ENABLE_IDE_KEY_PROG == 1]

Argument:uint64_t,uint64_t,uint64_t*,uint64_t*,uint64_t*Return:int

This function retrieves a reponse for any of the prior non-blocking IDE-KM requests. Thecaller has to identify the request and populate the accurate response. For blocking calls,this function always returns E_RMM_UNK.

The platform needs to ensure proper exclusives are in place when accessed from multiple CPUs.Depending on the expected latency for IDE-KM interface, the platform should choose blockingor non-blocking semantics. More details about IDE Setup flow can be foundin thisRFC.

The parameters of the function are:

arg0 - The ecam address, to access and configure PCI devices in a system.

arg1 - The rootport ID used to identify the PCIe rootport of a connected device.

arg2 - Retrieved response corresponding to the previous IDE_KM request.

arg3 - returns the passthrough request ID of the retrieved response.

arg4 - returns the passthrough cookie of the retrieved response.

The function returns E_RMM_OK if response is retrieved successfully, E_RMM_INVAL if argumentsto this function are invalid, E_RMM_UNK if response retrieval failed for an unknown error orIDE-KM interface is having blocking semantics, E_RMM_AGAIN if the response queue is empty.

Thearg2 return parameter can return the following values:E_RMM_OK - The previous request was successful.E_RMM_FAULT - The previous request was not successful.E_RMM_INVAL - Arguments to previous request were incorrect.E_RMM_UNK - Previous request returned Unknown error.

6.13.18.Function : bl31_plat_enable_mmu [optional]

Argument:uint32_tReturn:void

This function enables the MMU. The boot code calls this function with MMU andcaches disabled. This function should program necessary registers to enabletranslation, and upon return, the MMU on the calling PE must be enabled.

The function must honor flags passed in the first argument. These flags aredefined by the translation library, and can be found in the fileinclude/lib/xlat_tables/xlat_mmu_helpers.h.

On DynamIQ systems, this function must not use stack while enabling MMU, whichis how the function in xlat table library version 2 is implemented.

6.13.19.Function : plat_init_apkey [optional]

Argument:voidReturn:uint128_t

This function returns the 128-bit value which can be used to program ARMv8.3pointer authentication keys.

The value should be obtained from a reliable source of randomness.

This function is only needed if ARMv8.3 pointer authentication is used in theTrusted Firmware by building withBRANCH_PROTECTION option set to 1, 2 or 3.

6.13.20.Function : plat_get_syscnt_freq2() [mandatory]

Argument:voidReturn:unsignedint

This function is used by the architecture setup code to retrieve the counterfrequency for the CPU’s generic timer. This value will be programmed into theCNTFRQ_EL0 register. In Arm standard platforms, it returns the base frequencyof the system counter, which is retrieved from the first entry in the frequencymodes table.

6.13.21.#define : PLAT_PERCPU_BAKERY_LOCK_SIZE [optional]

WhenUSE_COHERENT_MEM=0, this constant defines the total memory (inbytes) aligned to the cache line boundary that should be allocated per-cpu toaccommodate all the bakery locks.

If this constant is not defined whenUSE_COHERENT_MEM=0, the linkercalculates the size of the.bakery_lock input section, aligns it to thenearestCACHE_WRITEBACK_GRANULE, multiplies it withPLATFORM_CORE_COUNTand stores the result in a linker symbol. This constant prevents a platformfrom relying on the linker and provide a more efficient mechanism foraccessing per-cpu bakery lock information.

If this constant is defined and its value is not equal to the valuecalculated by the linker then a link time assertion is raised. A compile timeassertion is raised if the value of the constant is not aligned to the cacheline boundary.

6.13.22.SDEI porting requirements

TheSDEI dispatcher requires the platform to provide the following macrosand functions, of which some are optional, and some others mandatory.

6.13.22.1.Macros

6.13.22.1.1.Macro: PLAT_SDEI_NORMAL_PRI [mandatory]

This macro must be defined to the EL3 exception priority level associated withNormalSDEI events on the platform. This must have a higher value(therefore of lower priority) thanPLAT_SDEI_CRITICAL_PRI.

6.13.22.1.2.Macro: PLAT_SDEI_CRITICAL_PRI [mandatory]

This macro must be defined to the EL3 exception priority level associated withCriticalSDEI events on the platform. This must have a lower value(therefore of higher priority) thanPLAT_SDEI_NORMAL_PRI.

Note:SDEI exception priorities must be the lowest among Securepriorities. Among theSDEI exceptions, CriticalSDEI priority mustbe higher than NormalSDEI priority.

6.13.22.2.Functions

6.13.22.2.1.Function: int plat_sdei_validate_entry_point() [optional]
Argument:uintptr_tep,unsignedintclient_modeReturn:int

This function validates the entry point address of the event handler provided bythe client for both event registration andComplete and ResumeSDEI calls.The function ensures that the address is valid in the client translation regime.

The second argument is the exception level that the client is executing in. Itcan be Non-Secure EL1 or Non-Secure EL2.

The function must return0 for successful validation, or-1 upon failure.

The default implementation always returns0. On Arm platforms, this functiontranslates the entry point address within the client translation regime andfurther ensures that the resulting physical address is located in Non-secureDRAM.

6.13.22.2.2.Function: void plat_sdei_handle_masked_trigger(uint64_t mpidr, unsigned int intr) [optional]
Argument:uint64_tArgument:unsignedintReturn:void

SDEI specification requires that a PE comes out of reset with the eventsmasked. The client therefore is expected to callPE_UNMASK to unmaskSDEI events on the PE. NoSDEI events can be dispatched until suchtime.

Should a PE receive an interrupt that was bound to anSDEI event while theevents are masked on the PE, the dispatcher implementation invokes the functionplat_sdei_handle_masked_trigger. The MPIDR of the PE that received theinterrupt and the interrupt ID are passed as parameters.

The default implementation only prints out a warning message.

6.13.23.TRNG porting requirements

TheTRNG backend requires the platform to provide the following valuesand mandatory functions.

6.13.23.1.Values

6.13.23.1.1.value: uuid_t plat_trng_uuid [mandatory]

This value must be defined to the UUID of the TRNG backend that is specific tothe hardware afterplat_entropy_setup function is called. This value mustconform to the SMCCC calling convention; The most significant 32 bits of theUUID must not equal0xffffffff or the signed integer-1 as this value inw0 indicates failure to get a TRNG source.

6.13.23.2.Functions

6.13.23.2.1.Function: void plat_entropy_setup(void) [mandatory]
Argument:noneReturn:none

This function is expected to do platform-specific initialization of any TRNGhardware. This may include generating a UUID from a hardware-specific seed.

6.13.23.2.2.Function: bool plat_get_entropy(uint64_t *out) [mandatory]
Argument:uint64_t*Return:boolOut:whenthereturnvalueistrue,theentropyhasbeenwrittenintothestoragepointedto

This function writes entropy into storage provided by the caller. If no entropyis available, it must return false and the storage must not be written.

6.14.Power State Coordination Interface (in BL31)

The TF-A implementation of the PSCI API is based around the concept of apower domain. Apower domain is a CPU or a logical group of CPUs whichshare some state on which power management operations can be performed asspecified byPSCI. Each CPU in the system is assigned a cpu index which isa unique number between0 andPLATFORM_CORE_COUNT-1. Thepower domains are arranged in a hierarchical tree structure and eachpower domain can be identified in a system by the cpu index of any CPU thatis part of that domain and apower domain level. A processing element (forexample, a CPU) is at level 0. If thepower domain node above a CPU is alogical grouping of CPUs that share some state, then level 1 is that group ofCPUs (for example, a cluster), and level 2 is a group of clusters (forexample, the system). More details on the power domain topology and itsorganization can be found inPSCI Power Domain Tree Structure.

BL31’s platform initialization code exports a pointer to the platform-specificpower management operations required for the PSCI implementation to functioncorrectly. This information is populated in theplat_psci_ops structure. ThePSCI implementation calls members of theplat_psci_ops structure for performingpower management operations on the power domains. For example, the targetCPU is specified by itsMPIDR in a PSCICPU_ON call. Thepwr_domain_on()handler (if present) is called for the CPU power domain.

Thepower-state parameter of a PSCICPU_SUSPEND call can be used todescribe composite power states specific to a platform. The PSCI implementationdefines a generic representation of the power-state parameter, which is anarray of local power states where each index corresponds to a power domainlevel. Each entry contains the local power state the power domain at that powerlevel could enter. It depends on thevalidate_power_state() handler toconvert the power-state parameter (possibly encoding a composite power state)passed in a PSCICPU_SUSPEND call to this representation.

The following functions form part of platform port of PSCI functionality.

6.14.1.Function : plat_psci_stat_accounting_start() [optional]

Argument:constpsci_power_state_t*Return:void

This is an optional hook that platforms can implement for residency statisticsaccounting before entering a low power state. Thepwr_domain_state field ofstate_info (first argument) can be inspected if stat accounting is donedifferently at CPU level versus higher levels. As an example, if the element atindex 0 (CPU power level) in thepwr_domain_state array indicates a power downstate, special hardware logic may be programmed in order to keep track of theresidency statistics. For higher levels (array indices > 0), the residencystatistics could be tracked in software using PMF. IfENABLE_PMF is set, thedefault implementation will use PMF to capture timestamps.

6.14.2.Function : plat_psci_stat_accounting_stop() [optional]

Argument:constpsci_power_state_t*Return:void

This is an optional hook that platforms can implement for residency statisticsaccounting after exiting from a low power state. Thepwr_domain_state fieldofstate_info (first argument) can be inspected if stat accounting is donedifferently at CPU level versus higher levels. As an example, if the element atindex 0 (CPU power level) in thepwr_domain_state array indicates a power downstate, special hardware logic may be programmed in order to keep track of theresidency statistics. For higher levels (array indices > 0), the residencystatistics could be tracked in software using PMF. IfENABLE_PMF is set, thedefault implementation will use PMF to capture timestamps.

6.14.3.Function : plat_psci_stat_get_residency() [optional]

Argument:unsignedint,constpsci_power_state_t*,unsignedintReturn:u_register_t

This is an optional interface that is is invoked after resuming from a low powerstate and provides the time spent resident in that low power state by the powerdomain at a particular power domain level. When a CPU wakes up from suspend,all its parent power domain levels are also woken up. The generic PSCI codeinvokes this function for each parent power domain that is resumed and itidentified by thelvl (first argument) parameter. Thestate_info (secondargument) describes the low power state that the power domain has resumed from.The current CPU is the first CPU in the power domain to resume from the lowpower state and thelast_cpu_idx (third parameter) is the index of the lastCPU in the power domain to suspend and may be needed to calculate the residencyfor that power domain.

6.14.4.Function : plat_get_target_pwr_state() [optional]

Argument:unsignedint,constplat_local_state_t*,unsignedintReturn:plat_local_state_t

The PSCI generic code uses this function to let the platform participate instate coordination during a power management operation. The function is passeda pointer to an array of platform specific local power statestates (secondargument) which contains the requested power state for each CPU at a particularpower domain levellvl (first argument) within the power domain. The functionis expected to traverse this array of uptoncpus (third argument) and returna coordinated target power state by the comparing all the requested powerstates. The target power state should not be deeper than any of the requestedpower states.

A weak definition of this API is provided by default wherein it assumesthat the platform assigns a local state value in order of increasing depthof the power state i.e. for two power states X & Y, if X < Ythen X represents a shallower power state than Y. As a result, thecoordinated target local power state for a power domain will be the minimumof the requested local power state values.

6.14.5.Function : plat_get_power_domain_tree_desc() [mandatory]

Argument:voidReturn:constunsignedchar*

This function returns a pointer to the byte array containing the power domaintopology tree description. The format and method to construct this array aredescribed inPSCI Power Domain Tree Structure. The BL31 PSCIinitialization code requires this array to be described by the platform, eitherstatically or dynamically, to initialize the power domain topology tree. In casethe array is populated dynamically, then plat_core_pos_by_mpidr() andplat_my_core_pos() should also be implemented suitably so that the topology treedescription matches the CPU indices returned by these APIs. These APIs togetherform the platform interface for the PSCI topology framework.

6.14.6.Function : plat_setup_psci_ops() [mandatory]

Argument:uintptr_t,constplat_psci_ops**Return:int

This function may execute with the MMU and data caches enabled if the platformport does the necessary initializations inbl31_plat_arch_setup(). It is onlycalled by the primary CPU.

This function is called by PSCI initialization code. Its purpose is to letthe platform layer know about the warm boot entrypoint through thesec_entrypoint (first argument) and to export handler routines forplatform-specific psci power management actions by populating the passedpointer with a pointer to BL31’s privateplat_psci_ops structure.

A description of each member of this structure is given below. Please refer tothe Arm FVP specific implementation of these handlers inplat/arm/board/fvp/fvp_pm.c as an example. For each PSCI function that theplatform wants to support, the associated operation or operations in thisstructure must be provided and implemented (Refer section 4 ofFirmware Design for the PSCI API supported in TF-A). To disable a PSCIfunction in a platform port, the operation should be removed from thisstructure instead of providing an empty implementation.

6.14.6.1.plat_psci_ops.cpu_standby()

Perform the platform-specific actions to enter the standby state for a cpuindicated by the passed argument. This provides a fast path for CPU standbywherein overheads of PSCI state management and lock acquisition is avoided.For this handler to be invoked by the PSCICPU_SUSPEND API implementation,the suspend state type specified in thepower-state parameter should beSTANDBY and the target power domain level specified should be the CPU. Thehandler should put the CPU into a low power retention state (usually byissuing a wfi instruction) and ensure that it can be woken up from thatstate by a normal interrupt. The generic code expects the handler to succeed.

6.14.6.2.plat_psci_ops.pwr_domain_on()

Perform the platform specific actions to power on a CPU, specifiedby theMPIDR (first argument). The generic code expects the platform toreturn PSCI_E_SUCCESS on success or PSCI_E_INTERN_FAIL for any failure.

6.14.6.3.plat_psci_ops.pwr_domain_off_early() [optional]

This optional function performs the platform specific actions to check ifpowering off the calling CPU and its higher parent power domain levels asindicated by thetarget_state (first argument) is possible or allowed.

Thetarget_state encodes the platform coordinated target local power statesfor the CPU power domain and its parent power domain levels.

For this handler, the local power state for the CPU power domain will be apower down state where as it could be either power down, retention or run statefor the higher power domain levels depending on the result of statecoordination. The generic code expects PSCI_E_DENIED return code if theplatform thinks that CPU_OFF should not proceed on the calling CPU.

6.14.6.4.plat_psci_ops.pwr_domain_off()

Perform the platform specific actions to prepare to power off the calling CPUand its higher parent power domain levels as indicated by thetarget_state(first argument). It is called by the PSCICPU_OFF API implementation.

Thetarget_state encodes the platform coordinated target local power statesfor the CPU power domain and its parent power domain levels. The handlerneeds to perform power management operation corresponding to the local stateat each power level.

For this handler, the local power state for the CPU power domain will be apower down state where as it could be either power down, retention or run statefor the higher power domain levels depending on the result of statecoordination. The generic code expects the handler to succeed.

6.14.6.5.plat_psci_ops.pwr_domain_validate_suspend() [optional]

This is an optional function that is only compiled into the build if the buildoptionPSCI_OS_INIT_MODE is enabled.

If implemented, this function allows the platform to perform platform specificvalidations based on hardware states. The generic code expects this function toreturn PSCI_E_SUCCESS on success, or either PSCI_E_DENIED orPSCI_E_INVALID_PARAMS as appropriate for any invalid requests.

6.14.6.6.plat_psci_ops.pwr_domain_suspend_pwrdown_early() [optional]

This optional function may be used as a performance optimization to replaceor complement pwr_domain_suspend() on some platforms. Its calling semanticsare identical to pwr_domain_suspend(), except the PSCI implementation onlycalls this function when suspending to a power down state, and it guaranteesthat data caches are enabled.

When HW_ASSISTED_COHERENCY = 0, the PSCI implementation disables data cachesbefore calling pwr_domain_suspend(). If the target_state corresponds to apower down state and it is safe to perform some or all of the platformspecific actions in that function with data caches enabled, it may be moreefficient to move those actions to this function. When HW_ASSISTED_COHERENCY= 1, data caches remain enabled throughout, and so there is no advantage tomoving platform specific actions to this function.

6.14.6.7.plat_psci_ops.pwr_domain_suspend()

Perform the platform specific actions to prepare to suspend the callingCPU and its higher parent power domain levels as indicated by thetarget_state (first argument). It is called by the PSCICPU_SUSPENDAPI implementation.

Thetarget_state has a similar meaning as described inthepwr_domain_off() operation. It encodes the platform coordinatedtarget local power states for the CPU power domain and its parentpower domain levels. The handler needs to perform power management operationcorresponding to the local state at each power level. The generic codeexpects the handler to succeed.

The difference between turning a power domain off versus suspending it is thatin the former case, the power domain is expected to re-initialize its statewhen it is next powered on (seepwr_domain_on_finish()). In the lattercase, the power domain is expected to save enough state so that it can resumeexecution by restoring this state when its powered on (seepwr_domain_suspend_finish()).

When suspending a core, the platform can also choose to power off the GICv3Redistributor and ITS through an implementation-defined sequence. To achievethis safely, the ITS context must be saved first. The architectural part isimplemented by thegicv3_its_save_disable() helper, but most of the neededsequence is implementation defined and it is therefore the responsibility ofthe platform code to implement the necessary sequence. Then the GICRedistributor context can be saved using thegicv3_rdistif_save() helper.Powering off the Redistributor requires the implementation to support it and itis the responsibility of the platform code to execute the right implementationdefined sequence.

When a system suspend is requested, the platform can also make use of thegicv3_distif_save() helper to save the context of the GIC Distributor afterit has saved the context of the Redistributors and ITS of all the cores in thesystem. The context of the Distributor can be large and may require it to beallocated in a special area if it cannot fit in the platform’s global staticdata, for example in DRAM. The Distributor can then be powered down using animplementation-defined sequence.

6.14.6.8.plat_psci_ops.pwr_domain_pwr_down()

This is an optional function and, if implemented, is expected to performplatform specific actions before the CPU is powered down. Since this function isinvoked outside the PSCI locks, the actions performed in this hook must be localto the CPU or the platform must ensure that races between multiple CPUs cannotoccur.

Thetarget_state has a similar meaning as described in thepwr_domain_off()operation and it encodes the platform coordinated target local power states forthe CPU power domain and its parent power domain levels.

It is preferred that this function returns. The caller will invokepsci_power_down_wfi() to powerdown the CPU, mitigate any powerdown errata,and handle any wakeups that may arise. Previously, this function did not returnand instead calledwfi (in an infinite loop) directly. This is stillpossible on platforms where this is guaranteed to be terminal, however, it isstrongly discouraged going forward.

Previously this function was calledpwr_domain_pwr_down_wfi().

6.14.6.9.plat_psci_ops.pwr_domain_on_finish()

This function is called by the PSCI implementation after the calling CPU ispowered on and released from reset in response to an earlier PSCICPU_ON call.It performs the platform-specific setup required to initialize enough state forthis CPU to enter the normal world and also provide secure runtime firmwareservices.

Thetarget_state (first argument) is the prior state of the power domainsimmediately before the CPU was turned on. It indicates which power domainsabove the CPU might require initialization due to having previously been inlow power states. The generic code expects the handler to succeed.

6.14.6.10.plat_psci_ops.pwr_domain_on_finish_late() [optional]

This optional function is called by the PSCI implementation after the callingCPU is fully powered on with respective data caches enabled. The calling CPU andthe associated cluster are guaranteed to be participating in coherency. Thisfunction gives the flexibility to perform any platform-specific actions safely,such as initialization or modification of shared data structures, without theoverhead of explicit cache maintainace operations.

Thetarget_state has a similar meaning as described in thepwr_domain_on_finish()operation. The generic code expects the handler to succeed.

6.14.6.11.plat_psci_ops.pwr_domain_suspend_finish()

This function is called by the PSCI implementation after the calling CPU ispowered on and released from reset in response to an asynchronous wakeupevent, for example a timer interrupt that was programmed by the CPU during theCPU_SUSPEND call orSYSTEM_SUSPEND call. It performs the platform-specificsetup required to restore the saved state for this CPU to resume executionin the normal world and also provide secure runtime firmware services.

Thetarget_state (first argument) has a similar meaning as described inthepwr_domain_on_finish() operation. The generic code expects the platformto succeed.

If the Distributor, Redistributors or ITS have been powered off as part of asuspend, their context must be restored in this function in the reverse orderto how they were saved during suspend sequence.

6.14.6.12.plat_psci_ops.system_off()

This function is called by PSCI implementation in response to aSYSTEM_OFFcall. It performs the platform-specific system poweroff sequence afternotifying the Secure Payload Dispatcher. The caller will callwfi if thisfunction returns, similar toplat_psci_ops.pwr_domain_pwr_down().

6.14.6.13.plat_psci_ops.system_reset()

This function is called by PSCI implementation in response to aSYSTEM_RESETcall. It performs the platform-specific system reset sequence afternotifying the Secure Payload Dispatcher. The caller will callwfi if thisfunction returns, similar toplat_psci_ops.pwr_domain_pwr_down().

6.14.6.14.plat_psci_ops.validate_power_state()

This function is called by the PSCI implementation during theCPU_SUSPENDcall to validate thepower_state parameter of the PSCI API and if valid,populate it inreq_state (second argument) array as power domain levelspecific local states. If thepower_state is invalid, the platform mustreturn PSCI_E_INVALID_PARAMS as error, which is propagated back to thenormal world PSCI client.

6.14.6.15.plat_psci_ops.validate_ns_entrypoint()

This function is called by the PSCI implementation during theCPU_SUSPEND,SYSTEM_SUSPEND andCPU_ON calls to validate the non-secureentry_pointparameter passed by the normal world. If theentry_point is invalid,the platform must return PSCI_E_INVALID_ADDRESS as error, which ispropagated back to the normal world PSCI client.

6.14.6.16.plat_psci_ops.get_sys_suspend_power_state()

This function is called by the PSCI implementation during theSYSTEM_SUSPENDcall to get thereq_state parameter from platform which encodes the powerdomain level specific local states to suspend to system affinity level. Thereq_state will be utilized to do the PSCI state coordination andpwr_domain_suspend() will be invoked with the coordinated target state toenter system suspend.

6.14.6.17.plat_psci_ops.get_pwr_lvl_state_idx()

This is an optional function and, if implemented, is invoked by the PSCIimplementation to convert thelocal_state (first argument) at a specifiedpwr_lvl (second argument) to an index between 0 andPLAT_MAX_PWR_LVL_STATES - 1. This function is only needed if the platformsupports more than two local power states at each power domain level, that isPLAT_MAX_PWR_LVL_STATES is greater than 2, and needs to account for theselocal power states.

6.14.6.18.plat_psci_ops.translate_power_state_by_mpidr()

This is an optional function and, if implemented, verifies thepower_state(second argument) parameter of the PSCI API corresponding to a target powerdomain. The target power domain is identified by using bothMPIDR (firstargument) and the power domain level encoded inpower_state. The power domainlevel specific local states are to be extracted frompower_state and bepopulated in theoutput_state (third argument) array. The functionalityis similar to thevalidate_power_state function described above and isenvisaged to be used in case the validity ofpower_state depend on thetargeted power domain. If thepower_state is invalid for the targeted powerdomain, the platform must return PSCI_E_INVALID_PARAMS as error. If thisfunction is not implemented, then the generic implementation relies onvalidate_power_state function to translate thepower_state.

This function can also be used in case the platform wants to support localpower state encoding forpower_state parameter of PSCI_STAT_COUNT/RESIDENCYAPIs as described in Section 5.18 ofPSCI.

6.14.6.19.plat_psci_ops.get_node_hw_state()

This is an optional function. If implemented this function is intended to returnthe power state of a node (identified by the first parameter, theMPIDR) inthe power domain topology (identified by the second parameter,power_level),as retrieved from a power controller or equivalent component on the platform.Upon successful completion, the implementation must map and return the finalstatus amongHW_ON,HW_OFF orHW_STANDBY. Upon encountering failures, itmust return eitherPSCI_E_INVALID_PARAMS orPSCI_E_NOT_SUPPORTED asappropriate.

Implementations are not expected to handlepower_levels greater thanPLAT_MAX_PWR_LVL.

6.14.6.20.plat_psci_ops.system_reset2()

This is an optional function. If implemented this function iscalled during theSYSTEM_RESET2 call to perform a resetbased on the first parameterreset_type as specified inPSCI. The parametercookie can be used to pass additionalreset information. If thereset_type is not supported, thefunction must returnPSCI_E_NOT_SUPPORTED. For architecturalresets, all failures must returnPSCI_E_INVALID_PARAMETERSand vendor reset can return other PSCI error codes as definedinPSCI. If this function returns success, the caller will callwfi similar toplat_psci_ops.pwr_domain_pwr_down().

6.14.6.21.plat_psci_ops.write_mem_protect()

This is an optional function. If implemented it enables or disables theMEM_PROTECT functionality based on the value ofval.A non-zero value enablesMEM_PROTECT and a value of zerodisables it. Upon encountering failures it must return a negative valueand on success it must return 0.

6.14.6.22.plat_psci_ops.read_mem_protect()

This is an optional function. If implemented it returns the currentstate ofMEM_PROTECT via theval parameter. Upon encounteringfailures it must return a negative value and on success it mustreturn 0.

6.14.6.23.plat_psci_ops.mem_protect_chk()

This is an optional function. If implemented it checks if a memoryregion defined by a base addressbase and with a size oflengthbytes is protected byMEM_PROTECT. If the region is protectedthen it must return 0, otherwise it must return a negative number.

6.15.Interrupt Management framework (in BL31)

BL31 implements an Interrupt Management Framework (IMF) to manage interruptsgenerated in either security state and targeted to EL1 or EL2 in the non-securestate or EL3/S-EL1 in the secure state. The design of this framework isdescribed in theInterrupt Management Framework

A platform should export the following APIs to support the IMF. The followingtext briefly describes each API and its implementation in Arm standardplatforms. The API implementation depends upon the type of interrupt controllerpresent in the platform. Arm standard platform layer supports bothArm Generic Interrupt Controller version 2.0 (GICv2)and3.0 (GICv3). Juno builds the Arm platform layer to use GICv2 and theFVP can be configured to use either GICv2 or GICv3 depending on the build flagFVP_USE_GIC_DRIVER (SeeArm FVP Platform Specific Build Options for moredetails).

See also:Interrupt Controller Abstraction APIs.

6.15.1.Function : plat_interrupt_type_to_line() [mandatory]

Argument:uint32_t,uint32_tReturn:uint32_t

The Arm processor signals an interrupt exception either through the IRQ or FIQinterrupt line. The specific line that is signaled depends on how the interruptcontroller (IC) reports different interrupt types from an execution context ineither security state. The IMF uses this API to determine which interrupt linethe platform IC uses to signal each type of interrupt supported by the frameworkfrom a given security state. This API must be invoked at EL3.

The first parameter will be one of theINTR_TYPE_* values (seeInterrupt Management Framework) indicating the target type of theinterrupt, the second parameter is the security state of the originatingexecution context. The return result is the bit position in theSCR_EL3register of the respective interrupt trap: IRQ=1, FIQ=2.

In the case of Arm standard platforms using GICv2, S-EL1 interrupts areconfigured as FIQs and Non-secure interrupts as IRQs from either securitystate.

In the case of Arm standard platforms using GICv3, the interrupt line to beconfigured depends on the security state of the execution context when theinterrupt is signalled and are as follows:

  • The S-EL1 interrupts are signaled as IRQ in S-EL0/1 context and as FIQ inNS-EL0/1/2 context.

  • The Non secure interrupts are signaled as FIQ in S-EL0/1 context and as IRQin the NS-EL0/1/2 context.

  • The EL3 interrupts are signaled as FIQ in both S-EL0/1 and NS-EL0/1/2context.

6.15.2.Function : plat_ic_get_pending_interrupt_type() [mandatory]

Argument:voidReturn:uint32_t

This API returns the type of the highest priority pending interrupt at theplatform IC. The IMF uses the interrupt type to retrieve the correspondinghandler function.INTR_TYPE_INVAL is returned when there is no interruptpending. The valid interrupt types that can be returned areINTR_TYPE_EL3,INTR_TYPE_S_EL1 andINTR_TYPE_NS. This API must be invoked at EL3.

In the case of Arm standard platforms using GICv2, theHighest PriorityPending Interrupt Register (GICC_HPPIR) is read to determine the id ofthe pending interrupt. The type of interrupt depends upon the id value asfollows.

  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.

In the case of Arm standard platforms using GICv3, the system registerICC_HPPIR0_EL1,Highest Priority Pending group 0 Interrupt Register,is read to determine the id of the pending interrupt. The type of interruptdepends upon the id value as follows.

  1. id =PENDING_G1S_INTID (1020) is reported as a S-EL1 interrupt

  2. id =PENDING_G1NS_INTID (1021) is reported as a Non-secure interrupt.

  3. id =GIC_SPURIOUS_INTERRUPT (1023) is reported as an invalid interrupt type.

  4. All other interrupt id’s are reported as EL3 interrupt.

6.15.3.Function : plat_ic_get_pending_interrupt_id() [mandatory]

Argument:voidReturn:uint32_t

This API returns the id of the highest priority pending interrupt at theplatform IC.INTR_ID_UNAVAILABLE is returned when there is no interruptpending.

In the case of Arm standard platforms using GICv2, theHighest PriorityPending Interrupt Register (GICC_HPPIR) is read to determine the id of thepending interrupt. The id that is returned by API depends upon the value ofthe id read from the interrupt controller as follows.

  1. id < 1022. id is returned as is.

  2. id = 1022. TheAliased 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.

In the case of Arm standard platforms using GICv3, if the API is invoked fromEL3, the system registerICC_HPPIR0_EL1,Highest Priority Pending Interruptgroup 0 Register, is read to determine the id of the pending interrupt. The idthat is returned by API depends upon the value of the id read from theinterrupt controller as follows.

  1. id <PENDING_G1S_INTID (1020). id is returned as is.

  2. id =PENDING_G1S_INTID (1020) orPENDING_G1NS_INTID (1021). The systemregisterICC_HPPIR1_EL1,Highest Priority Pending Interrupt group 1Register is read to determine the id of the group 1 interrupt. This idis returned by the API as long as it is a valid interrupt id

  3. If the id is any of the special interrupt identifiers,INTR_ID_UNAVAILABLE is returned.

When the API invoked from S-EL1 for GICv3 systems, the id read from systemregisterICC_HPPIR1_EL1,Highest Priority Pending group 1 InterruptRegister, is returned if is not equal to GIC_SPURIOUS_INTERRUPT (1023) elseINTR_ID_UNAVAILABLE is returned.

6.15.4.Function : plat_ic_acknowledge_interrupt() [mandatory]

Argument:voidReturn:uint32_t

This API is used by the CPU to indicate to the platform IC that processing ofthe highest pending interrupt has begun. It should return the raw, unmodifiedvalue obtained from the interrupt controller when acknowledging an interrupt.The actual interrupt number shall be extracted from this raw value using the APIplat_ic_get_interrupt_id()<plat_ic_get_interrupt_id>.

This function in Arm standard platforms using GICv2, reads theInterruptAcknowledge Register (GICC_IAR). This changes the state of the highestpriority pending interrupt from pending to active in the interrupt controller.It returns the value read from theGICC_IAR, unmodified.

In the case of Arm standard platforms using GICv3, if the API is invokedfrom EL3, the function reads the system registerICC_IAR0_EL1,InterruptAcknowledge Register group 0. If the API is invoked from S-EL1, the functionreads the system registerICC_IAR1_EL1,Interrupt Acknowledge Registergroup 1. The read changes the state of the highest pending interrupt frompending to active in the interrupt controller. The value read is returnedunmodified.

The TSP uses this API to start processing of the secure physical timerinterrupt.

6.15.5.Function : plat_ic_end_of_interrupt() [mandatory]

Argument:uint32_tReturn:void

This API is used by the CPU to indicate to the platform IC that processing ofthe interrupt corresponding to the id (passed as the parameter) hasfinished. The id should be the same as the id returned by theplat_ic_acknowledge_interrupt() API.

Arm standard platforms write the id to theEnd of Interrupt Register(GICC_EOIR) in case of GICv2, and toICC_EOIR0_EL1 orICC_EOIR1_EL1system register in case of GICv3 depending on where the API is invoked from,EL3 or S-EL1. This deactivates the corresponding interrupt in the interruptcontroller.

The TSP uses this API to finish processing of the secure physical timerinterrupt.

6.15.6.Function : plat_ic_get_interrupt_type() [mandatory]

Argument:uint32_tReturn: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 validinterrupt type (one ofINTR_TYPE_EL3,INTR_TYPE_S_EL1 andINTR_TYPE_NS) isreturned depending upon how the interrupt has been configured by the platformIC. This API must be invoked at EL3.

Arm standard platforms using GICv2 configures S-EL1 interrupts as Group0 interruptsand Non-secure interrupts as Group1 interrupts. It reads the group valuecorresponding to the interrupt id from the relevantInterrupt Group Register(GICD_IGROUPRn). It uses the group value to determine the type of interrupt.

In the case of Arm standard platforms using GICv3, both theInterrupt GroupRegister (GICD_IGROUPRn) andInterrupt Group Modifier Register(GICD_IGRPMODRn) is read to figure out whether the interrupt is configuredas Group 0 secure interrupt, Group 1 secure interrupt or Group 1 NS interrupt.

6.16.Registering a console

Platforms will need to implement the TF-A console framework to register and usea console for visual data output in TF-A. These can be used for data output duringthe different stages of the firmware boot process and also for debugging purposes.

The console framework can be used to output data on to a console using a number ofTF-A supported UARTs. Multiple consoles can be registered at the same time withdifferent output scopes (BOOT, RUNTIME, CRASH) so that data can be displayed ontheir respective consoles without unnecessary cluttering of a single console.

Information for registering a console can be found in theConsole Framework sectionof theSystem Design documentation.

6.17.Common helper functions

6.17.1.Function : elx_panic()

Argument:voidReturn:void

This API is called from assembly files when reporting a critical failurethat has occured in lower EL and is been trapped in EL3. This callmust not return.

6.17.2.Function : el3_panic()

Argument:voidReturn:void

This API is called from assembly files when encountering a critical failure thatcannot be recovered from. This function assumes that it is invoked from a Cruntime environment i.e. valid stack exists. This callmust not return.

6.17.3.Function : panic()

Argument:voidReturn:void

This API called from C files when encountering a critical failure that cannotbe recovered from. This function in turn prints backtrace (if enabled) and callsel3_panic(). This callmust not return.

6.18.Crash Reporting mechanism (in BL31)

BL31 implements a crash reporting mechanism which prints the various registersof the CPU to enable quick crash analysis and debugging. This mechanism relieson the platform implementingplat_crash_console_init,plat_crash_console_putc andplat_crash_console_flush.

The fileplat/common/aarch64/crash_console_helpers.S contains sampleimplementation of all of them. Platforms may include this file to theirmakefiles in order to benefit from them. By default, they will cause the crashoutput to be routed over the normal console infrastructure and get printed onconsoles configured to output in crash state.console_set_scope() can beused to control whether a console is used for crash output.

Note

Platforms are responsible for making sure that they only mark consoles foruse in the crash scope that are able to support this, i.e. that are writtenin assembly and conform with the register clobber rules for putc()(x0-x2, x16-x17) and flush() (x0-x3, x16-x17) crash callbacks.

In some cases (such as debugging very early crashes that happen before thenormal boot console can be set up), platforms may want to control crash outputmore explicitly. These platforms may instead provide custom implementations forthese. They are executed outside of a C environment and without a stack. Manyconsole drivers provide functions namedconsole_xxx_core_init/putc/flushthat are designed to be used by these functions. See Arm platforms (like juno)for an example of this.

6.18.1.Function : plat_crash_console_init [mandatory]

Argument:voidReturn:int

This API is used by the crash reporting mechanism to initialize the crashconsole. It must only use the general purpose registers x0 through x7 to do theinitialization and returns 1 on success.

6.18.2.Function : plat_crash_console_putc [mandatory]

Argument:intReturn:int

This API is used by the crash reporting mechanism to print a character on thedesignated crash console. It must only use general purpose registers x1 andx2 to do its work. The parameter and the return value are in general purposeregister x0.

6.18.3.Function : plat_crash_console_flush [mandatory]

Argument:voidReturn:void

This API is used by the crash reporting mechanism to force write of all buffereddata on the designated crash console. It should only use general purposeregisters x0 through x5 to do its work.

6.18.4.Function : plat_setup_early_console [optional]

Argument:voidReturn:void

This API is used to setup the early console, it is required only if the flagEARLY_CONSOLE is enabled.

6.19.External Abort handling and RAS Support

If any cores on the platform support powerdown abandon (i.e.FEAT_PABANDONis set, check the “Core powerup and powerdown sequence” in their TRMs), thenthese functions should be able to handle being called with power domains off andafter the powerdownwfi. In other words it may run after a call topwr_domain_suspend() and before a call topwr_domain_suspend_finish()(and their power off counterparts).

Should this not be desirable, or if there is no powerdown abandon support, thenRAS errors should be masked by writing any relevant error records in anypowerdown hooks to prevent deadlocks due to a RAS error after the point of noreturn. See the core’s TRM for further information.

6.19.1.Function : plat_ea_handler

Argument:intArgument:uint64_tArgument:void*Argument:void*Argument:uint64_tReturn:void

This function is invoked by the runtime exception handling framework for theplatform to handle an External Abort received at EL3. The intention of thefunction is to attempt to resolve the cause of External Abort and return;if that’s not possible then an orderly shutdown of the system is initiated.

The first parameter (intea_reason) indicates the reason for External Abort.Its value is one ofERROR_EA_* constants defined inea_handle.h.

The second parameter (uint64_tsyndrome) is the respective syndromepresented to EL3 after having received the External Abort. Depending on thenature of the abort (as can be inferred from theea_reason parameter), thiscan be the content of eitherESR_EL3 orDISR_EL1.

The third parameter (void*cookie) is unused for now. The fourth parameter(void*handle) is a pointer to the preempted context. The fifth parameter(uint64_tflags) indicates the preempted security state. These parametersare received from the top-level exception handler.

This function must be implemented if a platform expects Firmware First handlingof External Aborts.

6.19.2.Function : plat_handle_uncontainable_ea

Argument:intArgument:uint64_tReturn:void

This function is invoked by the RAS framework when an External Abort ofUncontainable type is received at EL3. Due to the critical nature ofUncontainable errors, the intention of this function is to initiate orderlyshutdown of the system, and is not expected to return.

This function must be implemented in assembly.

The first and second parameters are the same as that ofplat_ea_handler.

The default implementation of this function callsreport_unhandled_exception.

6.19.3.Function : plat_handle_double_fault

Argument:intArgument:uint64_tReturn:void

This function is invoked by the RAS framework when another External Abort isreceived at EL3 while one is already being handled. I.e., a call toplat_ea_handler is outstanding. Due to its critical nature, the intention ofthis function is to initiate orderly shutdown of the system, and is not expectedrecover or return.

This function must be implemented in assembly.

The first and second parameters are the same as that ofplat_ea_handler.

The default implementation of this function callsreport_unhandled_exception.

6.19.4.Function : plat_handle_el3_ea

Return:void

This function is invoked when an External Abort is received while executing inEL3. Due to its critical nature, the intention of this function is to initiateorderly shutdown of the system, and is not expected recover or return.

This function must be implemented in assembly.

The default implementation of this function callsreport_unhandled_exception.

6.19.5.Function : plat_handle_rng_trap

Argument:uint64_tArgument:cpu_context_t*Return:int

This function is invoked by BL31’s exception handler when there is a synchronoussystem register trap caused by access to the RNDR or RNDRRS registers. It allowsplatforms implementingFEAT_RNG_TRAP and enablingENABLE_FEAT_RNG_TRAP toemulate those system registers by returing back some entropy to the lower EL.

The first parameter (uint64_tesr_el3) contains the content of the ESR_EL3syndrome register, which encodes the instruction that was trapped. The interestinginformation in there is the target register (get_sysreg_iss_rt()).

The second parameter (cpu_context_t*ctx) represents the CPU state in thelower exception level, at the time when the execution of themrs instructionwas trapped. Its content can be changed, to put the entropy into the targetregister.

The return value indicates how to proceed:

  • When returningTRAP_RET_UNHANDLED (-1), the machine will panic.

  • When returningTRAP_RET_REPEAT (0), the exception handler will returnto the same instruction, so its execution will be repeated.

  • When returningTRAP_RET_CONTINUE (1), the exception handler will returnto the next instruction.

This function needs to be implemented by a platform if it enables FEAT_RNG_TRAP.

6.19.6.Function : plat_handle_impdef_trap

Argument:uint64_tArgument:cpu_context_t*Return:int

This function is invoked by BL31’s exception handler when there is a synchronoussystem register trap caused by access to the implementation defined registers.It allows platforms enablingIMPDEF_SYSREG_TRAP to emulate those systemregisters choosing to program bits of their choice. If using in combination withARCH_FEATURE_AVAILABILITY, the macros{SCR,MDCR,CPTR}_PLAT_{BITS,IGNORED,FLIPPED} should be defined to report correctresults.

The first parameter (uint64_tesr_el3) contains the content of the ESR_EL3syndrome register, which encodes the instruction that was trapped.

The second parameter (cpu_context_t*ctx) represents the CPU state in thelower exception level, at the time when the execution of themrs instructionwas trapped.

The return value indicates how to proceed:

  • When returningTRAP_RET_UNHANDLED (-1), the machine will panic.

  • When returningTRAP_RET_REPEAT (0), the exception handler will returnto the same instruction, so its execution will be repeated.

  • When returningTRAP_RET_CONTINUE (1), the exception handler will returnto the next instruction.

This function needs to be implemented by a platform if it enablesIMPDEF_SYSREG_TRAP.

6.20.Build flags

There are some build flags which can be defined by the platform to controlinclusion or exclusion of certain BL stages from the FIP image. These flagsneed to be defined in the platform makefile which will get included by thebuild system.

  • NEED_BL33By default, this flag is definedyes by the build system andBL33build option should be supplied as a build option. The platform has theoption of excluding the BL33 image in thefip image by defining this flagtono. If any of the optionsEL3_PAYLOAD_BASE orPRELOADED_BL33_BASEare used, this flag will be set tono automatically.

  • ARM_ARCH_MAJOR and ARM_ARCH_MINORBy default, ARM_ARCH_MAJOR.ARM_ARCH_MINOR is set to 8.0 indefaults.mk,if the platform makefile/build defines or uses the correct ARM_ARCH_MAJOR andARM_ARCH_MINOR then mandatory Architectural features available for that Archversion will be enabled by default and any optional Arch feature supported bythe Architecture and available in TF-A can be enabled from platform specificmakefile. Look up toarch_features.mk for details pertaining to mandatoryand optional Arch specific features.

6.21.Platform include paths

Platforms are allowed to add more include paths to be passed to the compiler.ThePLAT_INCLUDES variable is used for this purpose. This is needed inparticular for the fileplatform_def.h.

Example:

PLAT_INCLUDES+=-Iinclude/plat/myplat/include

6.22.C Library

To avoid subtle toolchain behavioral dependencies, the header files providedby the compiler are not used. The software is built with the-nostdinc flagto ensure no headers are included from the toolchain inadvertently. Instead therequired headers are included in the TF-A source tree. The library onlycontains those C library definitions required by the local implementation. Ifmore functionality is required, the needed library functions will need to beadded to the local implementation.

Some C headers have been obtained fromFreeBSD andSCC, while others havebeen written specifically for TF-A. Some implementation files have been obtainedfromFreeBSD, others have been written specifically for TF-A as well. Thefiles can be found ininclude/lib/libc andlib/libc.

SCC can be found inhttp://www.simple-cc.org/. A copy of theFreeBSD sourcescan be obtained fromhttp://github.com/freebsd/freebsd.

6.23.Storage abstraction layer

In order to improve platform independence and portability a storage abstractionlayer is used to load data from non-volatile platform storage. Currentlystorage access is only required by BL1 and BL2 phases and performed inside theload_image() function inbl_common.c.

@startumlparticipant bl_commonparticipant arm_io_storageparticipant io_storage== Platform Setup ==bl1_main -> xxx_bl1_setup : bl1_platform_setup()xxx_bl1_setup -> arm_io_storage : plat_arm_io_setup()arm_io_storage -> arm_io_storage : arm_io_setup()ref over arm_io_storage, io_storage : io device registration== Get Image ==bl1_main -> xxx_bl1_setup : bl1_plat_get_next_image_id()bl1_main <-- xxx_bl1_setup : BL2_IMAGE_IDbl1_main -> bl1_main : bl1_load_bl2()activate bl1_mainbl1_main -> plat_bl1_common : bl1_plat_get_image_desc(BL2_IMAGE_ID)bl1_main <-- plat_bl1_common : BL2_IMAGE_DESCbl1_main -> plat_bl1_common : bl1_plat_handle_pre_image_load(BL2_IMAGE_ID)bl1_main -> bl_common : load_auth_image(BL2_IMAGE_ID, image_info)activate bl_commonbl_common -> bl_common : load_auth_image_internal(BL2_IMAGE_ID, image_info, is_parent_image)activate bl_commonbl_common -> bl_common : load_image(BL2_IMAGE_ID, image_info)activate bl_commonbl_common -> arm_io_storage : plat_get_image_source(BL2_IMAGE_ID, &dev_handle, &image_spec)ref over arm_io_storage, io_storage : init and check device (BL2_IMAGE_ID)bl_common <-- arm_io_storage : dev_handlebl_common -> io_storage : io_open(dev_handle, image_spec, &image_handle)ref over io_storage : io_open() on fip devicebl_common <-- io_storage : image_handlebl_common -> io_storage : io_size(image_handle, &image_size)ref over io_storage : io_size() on fip devicebl_common -> io_storage : io_read(image_handle, image_base, image_size, &bytes_read)ref over io_storage : io_read() on fip devicebl_common -> io_storage : io_close(image_handle)ref over io_storage : io_close() on fip devicebl_common -> io_storage : io_dev_close(dev_handle)ref over io_storage : io_dev_close() on fip devicedeactivate bl_commondeactivate bl_commondeactivate bl_common== Prepare Next Image ==bl1_main -> plat_bl1_common : bl1_plat_handle_post_image_load(BL2_IMAGE_ID)deactivate bl1_main== Jump to next Image ==@enduml

It is mandatory to implement at least one storage driver. For the Armdevelopment platforms the Firmware Image Package (FIP) driver is provided asthe default means to load data from storage (seeFirmware Image Package (FIP)).The storage layer is described in the header fileinclude/drivers/io/io_storage.h. The implementation of the common library isindrivers/io/io_storage.c and the driver files are located indrivers/io/.

@startumlpackage arm_io_storage {class plat_io_policy {dev_handle : uintptr_t*image_spec : uintptr_t{abstract} check() : fctptr}class FIP_IMAGE_ID {memmap_dev_handlefip_block_specopen_memmap()}class BL2_IMAGE_ID{fip_dev_handlebl2_uuid_specopen_fip()}class xxx_IMAGE_ID{fip_dev_handlexxx_uuid_specopen_fip()}class arm_io_storage {fip_dev_con : io_dev_connector_t*fip_dev_handle : uintptr_tmemmap_dev_con : io_dev_connector_t*memmap_dev_handle : uintptr_tfip_block_spec : io_block_spec_tpolicies : plat_io_policy[1..*]-open_fip()-open_memmap()+arm_io_setup()+plat_get_image_source()}FIP_IMAGE_ID -up-|> plat_io_policyBL2_IMAGE_ID -up-|> plat_io_policyxxx_IMAGE_ID -up-|> plat_io_policyarm_io_storage *-"1..*" plat_io_policy}package IO {class  io_storage {io_dev_open()io_dev_init()io_dev_close().. synchronous operations ..io_open()io_seek()io_size()io_read()io_write()io_close()io_register_device()}class io_fip {register_io_dev_fip().. io_dev_funcs_t interface ..fip_dev_funcs : io_dev_funcs_t}class io_memmap {register_io_dev_memmap().. io_dev_funcs_t interface ..memmap_dev_funcs : io_dev_funcs_t}interface io_driver {io_entity_tio_dev_info_t.. io_dev_connector_t interface ..dev_open().. io_dev_funcs_t interface ..type()open()seek()size()read()write()close()dev_init()dev_close()io_register_device()}}arm_io_storage .. io_driverarm_io_storage .. io_fiparm_io_storage .. io_memmaparm_io_storage .. io_storage@enduml

Each IO driver must provideio_dev_* structures, as described indrivers/io/io_driver.h. These are returned via a mandatory registrationfunction that is called on platform initialization. The semi-hosting driverimplementation inio_semihosting.c can be used as an example.

Each platform should register devices and their drivers via the storageabstraction layer. These drivers then need to be initialized by bootloaderphases as required in their respectiveblx_platform_setup() functions.

@startumlparticipant arm_io_storageparticipant io_storageparticipant io_fipparticipant io_memmap -> arm_io_storage : arm_io_setup()group io dev registrationarm_io_storage -> io_fip : register_io_dev_fip(&fip_dev_con)io_fip -> io_storage : io_register_device(&dev_info_pool[])note over io_storagedevices[dev_count] = (fip_)dev_info_pooldev_count++end notearm_io_storage -> io_memmap : register_io_dev_memmap(&memmap_dev_con)io_memmap -> io_storage : io_register_device(&memmap_dev_info)note over io_storagedevices[dev_count] = memmap_dev_infodev_count++end notearm_io_storage -> io_storage : io_dev_open(fip_dev_con, NULL, fip_dev_handle) io_storage -> io_storage : dev_open(dev_con, dev_spec, handle)activate io_storageopt dev_open() on fip deviceio_storage -> io_fip : fip_dev_open(dev_spec, dev_info)note over io_fipdev_info = one of the"fip_dev_info" fromdev_info_pool[]end noteend optdeactivate io_storagearm_io_storage -> io_storage : io_dev_open(memmap_dev_con, NULL, memmap_dev_handle)io_storage -> io_storage : dev_open(dev_con, dev_spec, handle)activate io_storageopt dev_open() on memmap deviceio_storage -> io_memmap : memmap_dev_open(dev_spec, dev_info)note over io_memmapdev_info = memmap_dev_infoend noteend optdeactivate io_storageend group@enduml

The storage abstraction layer provides mechanisms (io_dev_init()) toinitialize storage devices before IO operations are called.

@startumlparticipant arm_io_storageparticipant io_storage -> arm_io_storage : plat_get_image_source(image_id, &dev_handle, &image_spec)group init and check device (image_id)alt image_id = BL2_IMAGE_IDnote over arm_io_storageget BL2_IMAGE_ID policy:- fip_dev_handle- open_fip()end noteopt policy->check()arm_io_storage -> arm_io_storage : open_fip(spec)activate arm_io_storagearm_io_storage -> io_storage : io_dev_init(fip_dev_handle, FIP_IMAGE_ID)ref over io_storage : dev_init() on fip devicearm_io_storage -> io_storage : io_open(fip_dev_handle, spec, &local_image_handle)ref over io_storage : io_open() on fip devicearm_io_storage -> io_storage : io_close(local_image_handle)ref over io_storage : io_close() on fip devicehnote over arm_io_storagefip_dev_handle readyend noteend optdeactivate arm_io_storageelse image_id = FIP_IMAGE_IDactivate arm_io_storagenote over arm_io_storageget FIP_IMAGE_ID policy:- memmap_dev_handle- open_memmap()end noteopt policy->check()arm_io_storage -> arm_io_storage : open_memmap(spec)activate arm_io_storagearm_io_storage -> io_storage : io_dev_init(memmap_dev_handle, NULL)ref over io_storage : dev_init() on memmap devicearm_io_storage -> io_storage : io_open(memmap_dev_handle, spec, &local_image_handle)ref over io_storage : io_open() on memmap devicearm_io_storage -> io_storage : io_close(local_image_handle)ref over io_storage : io_close() on memmap devicehnote over arm_io_storagememmap_dev_handle readyend notedeactivate arm_io_storageend  optdeactivate arm_io_storageend altend group@enduml

The basic operations supported by the layerincludeopen(),close(),read(),write(),size() andseek().Drivers do not have to implement all operations, but each platform mustprovide at least one driver for a device capable of supporting genericoperations such as loading a bootloader image.

The current implementation only allows for known images to be loaded by thefirmware. These images are specified by using their identifiers, as defined ininclude/plat/common/common_def.h (or a separate header file included fromthere). The platform layer (plat_get_image_source()) then returns a referenceto a device and a driver-specificspec which will be understood by the driverto allow access to the image data.

The layer is designed in such a way that is it possible to chain drivers withother drivers. For example, file-system drivers may be implemented on top ofphysical block devices, both represented by IO devices with correspondingdrivers. In such a case, the file-system “binding” with the block device maybe deferred until the file-system device is initialised.

The abstraction currently depends on structures being statically allocatedby the drivers and callers, as the system does not yet provide a means ofdynamically allocating memory. This may also have the affect of limiting theamount of open resources per driver.

6.24.Measured Boot Platform Interface

Enabling the MEASURED_BOOT flag adds extra platform requirements. Please refertoMeasured Boot Design for more details.

6.25.Live Firmware Activation Interface

6.25.1.Function : plat_lfa_get_components()

Argument:plat_lfa_component_info_t**Return:int

This platform API provides the list of LFA components available for activation.It populates a pointer to an array ofplat_lfa_component_info_t structures,which contain information about each component (like UUID, ID, etc.). It returns0 on success, or a standard error code on failure.

6.25.2.Function : is_plat_lfa_activation_pending()

Argument:uint32_tReturn:bool

This platform API checks if the specified LFA component, identifiedby itslfa_component_id, is available for activation. It returnstrue if available, otherwise false.

6.25.3.Function : plat_lfa_cancel()

Argument:uint32_tReturn:int

This platform API allows the platform to cancel an ongoing update or activationprocess for the specifiedlfa_component_id. It returns 0 on success ora standard error code on failure.

6.25.4.Function : plat_lfa_load_auth_image()

Argument:uint32_tReturn:int

The platform uses this API to load, authenticate and measure the componentspecified bylfa_component_id. It should return 0 on success or appropriateerror codes for load/authentication failures.


Copyright (c) 2013-2025, Arm Limited and Contributors. All rights reserved.