diff --git a/docs/firmware-design.md b/docs/firmware-design.md index 90ce4b1..52667e2 100644 --- a/docs/firmware-design.md +++ b/docs/firmware-design.md @@ -728,6 +728,11 @@ **Note : These PSCI APIs require appropriate Secure Payload Dispatcher hooks to be registered with the generic PSCI code to be supported. +The PSCI implementation in ARM Trusted Firmware is a library which can be +integrated with AArch64 or AArch32 EL3 Runtime Software for ARMv8-A systems. +A guide to integrating PSCI library with AArch32 EL3 Runtime Software +can be found [here][PSCI Lib guide]. + 5. Secure-EL1 Payloads and Dispatchers --------------------------------------- @@ -1923,3 +1928,4 @@ [INTRG]: ./interrupt-framework-design.md [CPUBM]: ./cpu-specific-build-macros.md [Firmware Update]: ./firmware-update.md +[PSCI Lib guide]: ./psci-lib-integration-guide.md diff --git a/docs/psci-lib-integration-guide.md b/docs/psci-lib-integration-guide.md new file mode 100644 index 0000000..f290966 --- /dev/null +++ b/docs/psci-lib-integration-guide.md @@ -0,0 +1,535 @@ +PSCI Library Integration guide for ARMv8-A AArch32 systems +========================================================== + +Contents +-------- + +1. [Introduction](#1-introduction) +2. [Generic call sequence for PSCI Library interface (AArch32)](#2-generic-call-sequence-for-psci-library-interface-aarch32) +3. [PSCI CPU context management](#3-psci-cpu-context-management) +4. [PSCI Library Interface](#4-psci-library-interface) +5. [EL3 Runtime Software dependencies](#5-el3-runtime-software-dependencies) + + +1. Introduction +--------------- + +This document describes the PSCI library interface with a focus on how to +integrate with a suitable Trusted OS for an ARMv8-A AArch32 system. The PSCI +Library implements the PSCI Standard as described in [PSCI spec] and is meant +to be integrated with EL3 Runtime Software which invokes the PSCI Library +interface appropriately. **EL3 Runtime Software** refers to software executing +at the highest secure privileged mode, which is EL3 in AArch64 or Secure SVC/ +Monitor mode in AArch32, and provides runtime services to the non-secure world. +The runtime service request is made via SMC (Secure Monitor Call) and the call +must adhere to [SMCCC]. In AArch32, EL3 Runtime Software may additionally +include Trusted OS functionality. A minimal AArch32 Secure Payload, SP-MIN, is +provided in ARM Trusted Firmware to illustrate the usage and integration of the +PSCI library. The description of PSCI library interface and its integration +with EL3 Runtime Software in this document is targeted towards AArch32 systems. + +2. Generic call sequence for PSCI Library interface (AArch32) +------------------------------------------------------------- + +The generic call sequence of PSCI Library interfaces +[(see section 4)](#4-psci-library-interface) during cold boot in AArch32 +system is described below: + +1. After cold reset, the EL3 Runtime Software performs its cold boot + initialization including the PSCI library pre-requisites mentioned in + [section 4](#4-psci-library-interface), and also the necessary platform + setup. + +2. Call `psci_setup()` in Monitor mode. + +3. Optionally call `psci_register_spd_pm_hook()` to register callbacks to + do bookkeeping for the EL3 Runtime Software during power management. + +4. Call `psci_prepare_next_non_secure_ctx()` to initialize the non-secure CPU + context. + +5. Get the non-secure `cpu_context_t` for the current CPU by calling + `cm_get_context()` , then programming the registers in the non-secure + context and exiting to non-secure world. If the EL3 Runtime Software needs + additional configuration to be set for non-secure context, like routing + FIQs to the secure world, the values of the registers can be modified prior + to programming. See [section 3](#3-psci-cpu-context-management) for more + details on CPU context management. + +The generic call sequence of PSCI library interfaces during warm boot in +AArch32 systems is described below: + +1. After warm reset, the EL3 Runtime Software performs the necessary warm + boot initialization including the PSCI library pre-requisites mentioned in + [section 4](#4-psci-library-interface) (Note that the Data cache + **must not** be enabled). + +2. Call `psci_warmboot_entrypoint()` in Monitor mode. This interface + initializes/restores the non-secure CPU context as well. + +3. Do step 5 of the cold boot call sequence described above. + +The generic call sequence of PSCI library interfaces on receipt of a PSCI SMC +on an AArch32 system is described below: + +1. On receipt of an SMC, save the register context as per [SMCCC]. + +2. If the SMC function identifier corresponds to a SMC32 PSCI API, construct + the appropriate arguments and call the `psci_smc_handler()` interface. + The invocation may or may not return back to the caller depending on + whether the PSCI API resulted in power down of the CPU. + +3. If `psci_smc_handler()` returns, populate the return value in R0 (AArch32)/ + X0 (AArch64) and restore other registers as per [SMCCC]. + + +3. PSCI CPU context management +------------------------------ + +PSCI library is in charge of initializing/restoring the non-secure CPU system +registers according to [PSCI specification][PSCI spec] during cold/warm boot. +This is referred to as `PSCI CPU Context Management`. Registers that need to +be preserved across CPU power down/power up cycles are maintained in +`cpu_context_t` data structure. The initialization of other non-secure CPU +system registers which do not require coordination with the EL3 Runtime +Software is done directly by the PSCI library (see `cm_prepare_el3_exit()`). + +The EL3 Runtime Software is responsible for managing register context +during switch between Normal and Secure worlds. The register context to be +saved and restored depends on the mechanism used to trigger the world switch. +For example, if the world switch was triggered by an SMC call, then the +registers need to be saved and restored according to [SMCCC]. In AArch64, +due to the tight integration with BL31, both BL31 and PSCI library +use the same `cpu_context_t` data structure for PSCI CPU context management +and register context management during world switch. This cannot be assumed +for AArch32 EL3 Runtime Software since most AArch32 Trusted OSes already implement +a mechanism for register context management during world switch. Hence, when +the PSCI library is integrated with a AArch32 EL3 Runtime Software, the +`cpu_context_t` is stripped down for just PSCI CPU context management. + +During cold/warm boot, after invoking appropriate PSCI library interfaces, it +is expected that the EL3 Runtime Software will query the `cpu_context_t` and +write appropriate values to the corresponding system registers. This mechanism +resolves 2 additional problems for AArch32 EL3 Runtime Software: + +1. Values for certain system registers like SCR and SCTLR cannot be + unilaterally determined by PSCI library and need inputs from the EL3 + Runtime Software. Using `cpu_context_t` as an intermediary data store + allows EL3 Runtime Software to modify the register values appropriately + before programming them. + +2. The PSCI library provides appropriate LR and SPSR values (entrypoint + information) for exit into non-secure world. Using `cpu_context_t` as an + intermediary data store allows the EL3 Runtime Software to store these + values safely until it is ready for exit to non-secure world. + +Currently the `cpu_context_t` data structure for AArch32 stores the following +registers: R0 - R3, LR (R14), SCR, SPSR, SCTLR. + +The EL3 Runtime Software must implement accessors to get/set pointers +to CPU context `cpu_context_t` data and these are described in +[section 5.2](#52-cpu-context-management-api). + + +4. PSCI Library Interface +------------------------- + +The PSCI library implements the [PSCI Specification][PSCI spec]. The interfaces +to this library are declared in `psci.h` and are as listed below: + +``` + u_register_t psci_smc_handler(uint32_t smc_fid, u_register_t x1, + u_register_t x2, u_register_t x3, + u_register_t x4, void *cookie, + void *handle, u_register_t flags); + int psci_setup(const psci_lib_args_t *lib_args); + void psci_warmboot_entrypoint(void); + void psci_register_spd_pm_hook(const spd_pm_ops_t *pm); + void psci_prepare_next_non_secure_ctx(entry_point_info_t *next_image_info); +``` + +The CPU context data 'cpu_context_t' is programmed to the registers differently +when PSCI is integrated with an AArch32 EL3 Runtime Software compared to +when the PSCI is integrated with an AArch64 EL3 Runtime Software (BL31). For +example, in the case of AArch64, there is no need to retrieve `cpu_context_t` +data and program the registers as it will done implicitly as part of +`el3_exit`. The description below of the PSCI interfaces is targeted at +integration with an AArch32 EL3 Runtime Software. + +The PSCI library is responsible for initializing/restoring the non-secure world +to an appropriate state after boot and may choose to directly program the +non-secure system registers. The PSCI generic code takes care not to directly +modify any of the system registers affecting the secure world and instead +returns the values to be programmed to these registers via `cpu_context_t`. +The EL3 Runtime Software is responsible for programming those registers and +can use the proposed values provided in the `cpu_context_t`, modifying the +values if required. + +PSCI library needs the flexibility to access both secure and non-secure +copies of banked registers. Hence it needs to be invoked in Monitor mode +for AArch32 and in EL3 for AArch64. The NS bit in SCR (in AArch32) or SCR_EL3 +(in AArch64) must be set to 0. Additional requirements for the PSCI library +interfaces are: + + * Instruction cache must be enabled + * Both IRQ and FIQ must be masked for the current CPU + * The page tables must be setup and the MMU enabled + * The C runtime environment must be setup and stack initialized + * The Data cache must be enabled prior to invoking any of the PSCI library + interfaces except for `psci_warmboot_entrypoint()`. + +Further requirements for each interface can be found in the interface +description. + +### 4.1 Interface : psci_setup() + + Argument : const psci_lib_args_t *lib_args + Return : void + +This function is to be called by the primary CPU during cold boot before +any other interface to the PSCI library. It takes `lib_args`, a const pointer +to `psci_lib_args_t`, as the argument. The `psci_lib_args_t` is a versioned +structure and is declared in `psci.h` header as follows: + +``` + typedef struct psci_lib_args { + /* The version information of PSCI Library Interface */ + param_header_t h; + /* The warm boot entrypoint function */ + mailbox_entrypoint_t mailbox_ep; + } psci_lib_args_t; +``` + +The first field `h`, of `param_header_t` type, provides the version +information. The second field `mailbox_ep` is the warm boot entrypoint address +and is used to configure the platform mailbox. Helper macros are provided in +psci.h to construct the `lib_args` argument statically or during runtime. Prior +to calling the `psci_setup()` interface, the platform setup for cold boot +must have completed. Major actions performed by this interface are: + + * Initializes architecture. + * Initializes PSCI power domain and state coordination data structures. + * Calls `plat_setup_psci_ops()` with warm boot entrypoint `mailbox_ep` as + argument. + * Calls `cm_set_context_by_index()` (see + [section 5.2](#52-cpu-context-management-api)) for all the CPUs in the + platform + +### 4.2 Interface : psci_prepare_next_non_secure_ctx() + + Argument : entry_point_info_t *next_image_info + Return : void + +After `psci_setup()` and prior to exit to the non-secure world, this function +must be called by the EL3 Runtime Software to initialize the non-secure world +context. The non-secure world entrypoint information `next_image_info` (first +argument) will be used to determine the non-secure context. After this function +returns, the EL3 Runtime Software must retrieve the `cpu_context_t` (using +cm_get_context()) for the current CPU and program the registers prior to exit +to the non-secure world. + +### 4.3 Interface : psci_register_spd_pm_hook() + + Argument : const spd_pm_ops_t * + Return : void + +As explained in [section 5.4](#54-secure-payload-power-management-callback), +the EL3 Runtime Software may want to perform some bookkeeping during power +management operations. This function is used to register the `spd_pm_ops_t` +(first argument) callbacks with the PSCI library which will be called +ppropriately during power management. Calling this function is optional and +need to be called by the primary CPU during the cold boot sequence after +`psci_setup()` has completed. + +### 4.4 Interface : psci_smc_handler() + + Argument : uint32_t smc_fid, u_register_t x1, + u_register_t x2, u_register_t x3, + u_register_t x4, void *cookie, + void *handle, u_register_t flags + Return : u_register_t + +This function is the top level handler for SMCs which fall within the +PSCI service range specified in [SMCCC]. The function ID `smc_fid` (first +argument) determines the PSCI API to be called. The `x1` to `x4` (2nd to 5th +arguments), are the values of the registers r1 - r4 (in AArch32) or x1 - x4 +(in AArch64) when the SMC is received. These are the arguments to PSCI API as +described in [PSCI spec]. The 'flags' (8th argument) is a bit field parameter +and is detailed in 'smcc.h' header. It includes whether the call is from the +secure or non-secure world. The `cookie` (6th argument) and the `handle` +(7th argument) are not used and are reserved for future use. + +The return value from this interface is the return value from the underlying +PSCI API corresponding to `smc_fid`. This function may not return back to the +caller if PSCI API causes power down of the CPU. In this case, when the CPU +wakes up, it will start execution from the warm reset address. + +### 4.5 Interface : psci_warmboot_entrypoint() + + Argument : void + Return : void + +This function performs the warm boot initialization/restoration as mandated by +[PSCI spec]. For AArch32, on wakeup from power down the CPU resets to secure +SVC mode and the EL3 Runtime Software must perform the prerequisite +initializations mentioned at top of this section. This function must be called +with Data cache disabled but with MMU initialized and enabled. The major +actions performed by this function are: + + * Invalidates the stack and enables the data cache. + * Initializes architecture and PSCI state coordination. + * Restores/Initializes the peripheral drivers to the required state via + appropriate `plat_psci_ops_t` hooks + * Restores the EL3 Runtime Software context via appropriate `spd_pm_ops_t` + callbacks. + * Restores/Initializes the non-secure context and populates the + `cpu_context_t` for the current CPU. + +Upon the return of this function, the EL3 Runtime Software must retrieve the +non-secure `cpu_context_t` using `cm_get_context()` and program the registers +prior to exit to the non-secure world. + + +5. EL3 Runtime Software dependencies +--------------------------------------- + +The PSCI Library includes supporting frameworks like context management, +cpu operations (cpu_ops) and per-cpu data framework. Other helper library +functions like bakery locks and spin locks are also included in the library. +The dependencies which must be fulfilled by the EL3 Runtime Software +for integration with PSCI library are described below. + +### 5.1 General dependencies + +The PSCI library being a Multiprocessor (MP) implementation, EL3 Runtime +Software must provide an SMC handling framework capable of MP adhering to +[SMCCC] specification. + +The EL3 Runtime Software must also export cache maintenance primitives +and some helper utilities for assert, print and memory operations as listed +below. The ARM Trusted Firmware source tree provides implementations for all +these functions but the EL3 Runtime Software may use its own implementation. + +**Functions : assert(), memcpy(), memset** + +These must be implemented as described in ISO C Standard. + +**Function : flush_dcache_range()** + + Argument : uintptr_t addr, size_t size + Return : void + +This function cleans and invalidates (flushes) the data cache for memory +at address `addr` (first argument) address and of size `size` (second argument). + +**Function : inv_dcache_range()** + + Argument : uintptr_t addr, size_t size + Return : void + +This function invalidates (flushes) the data cache for memory at address +`addr` (first argument) address and of size `size` (second argument). + +**Function : do_panic()** + + Argument : void + Return : void + +This function will be called by the PSCI library on encountering a critical +failure that cannot be recovered from. This function **must not** return. + +**Function : tf_printf()** + +This is printf-compatible function, but unlike printf, it does not return any +value. The ARM Trusted Firmware source tree provides an implementation which +is optimized for stack usage and supports only a subset of format specifiers. +The details of the format specifiers supported can be found in the +`tf_printf.c` file in ARM Trusted Firmware source tree. + +### 5.2 CPU Context management API + +The CPU context management data memory is statically allocated by PSCI library +in BSS section. The PSCI library requires the EL3 Runtime Software to implement +APIs to store and retrieve pointers to this CPU context data. SP-MIN +demonstrates how these APIs can be implemented but the EL3 Runtime Software can +choose a more optimal implementation (like dedicating the secure TPIDRPRW +system register (in AArch32) for storing these pointers). + +**Function : cm_set_context_by_index()** + + Argument : unsigned int cpu_idx, void *context, unsigned int security_state + Return : void + +This function is called during cold boot when the `psci_setup()` PSCI library +interface is called. + +This function must store the pointer to the CPU context data, `context` (2nd +argument), for the specified `security_state` (3rd argument) and CPU identified +by `cpu_idx` (first argument). The `security_state` will always be non-secure +when called by PSCI library and this argument is retained for compatibility +with BL31. The `cpu_idx` will correspond to the index returned by the +`plat_core_pos_by_mpidr()` for `mpidr` of the CPU. + +The actual method of storing the `context` pointers is implementation specific. +For example, SP-MIN stores the pointers in the array `sp_min_cpu_ctx_ptr` +declared in `sp_min_main.c`. + +**Function : cm_get_context()** + + Argument : uint32_t security_state + Return : void * + +This function must return the pointer to the `cpu_context_t` structure for +the specified `security_state` (first argument) for the current CPU. The caller +must ensure that `cm_set_context_by_index` is called first and the appropriate +context pointers are stored prior to invoking this API. The `security_state` +will always be non-secure when called by PSCI library and this argument +is retained for compatibility with BL31. + +**Function : cm_get_context_by_index()** + + Argument : unsigned int cpu_idx, unsigned int security_state + Return : void * + +This function must return the pointer to the `cpu_context_t` structure for +the specified `security_state` (second argument) for the CPU identified by +`cpu_idx` (first argument). The caller must ensure that +`cm_set_context_by_index` is called first and the appropriate context +pointers are stored prior to invoking this API. The `security_state` will +always be non-secure when called by PSCI library and this argument is +retained for compatibility with BL31. The `cpu_idx` will correspond to the +index returned by the `plat_core_pos_by_mpidr()` for `mpidr` of the CPU. + +### 5.3 Platform API + +The platform layer abstracts the platform-specific details from the generic +PSCI library. The following platform APIs/macros must be defined by the EL3 +Runtime Software for integration with the PSCI library. + +The mandatory platform APIs are: + + * plat_my_core_pos + * plat_core_pos_by_mpidr + * plat_get_syscnt_freq2 + * plat_get_power_domain_tree_desc + * plat_setup_psci_ops + * plat_reset_handler + * plat_panic_handler + * plat_get_my_stack + +The mandatory platform macros are: + + * PLATFORM_CORE_COUNT + * PLAT_MAX_PWR_LVL + * PLAT_NUM_PWR_DOMAINS + * CACHE_WRITEBACK_GRANULE + * PLAT_MAX_OFF_STATE + * PLAT_MAX_RET_STATE + * PLAT_MAX_PWR_LVL_STATES (optional) + * PLAT_PCPU_DATA_SIZE (optional) + +The details of these APIs/macros can be found in [Porting Guide]. + +All platform specific operations for power management are done via +`plat_psci_ops_t` callbacks registered by the platform when +`plat_setup_psci_ops()` API is called. The description of each of +the callbacks in `plat_psci_ops_t` can be found in PSCI section of the +[Porting Guide]. If any these callbacks are not registered, then the +PSCI API associated with that callback will not be supported by PSCI +library. + +### 5.4 Secure payload power management callback + +During PSCI power management operations, the EL3 Runtime Software may +need to perform some bookkeeping, and PSCI library provides +`spd_pm_ops_t` callbacks for this purpose. These hooks must be +populated and registered by using `psci_register_spd_pm_hook()` PSCI +library interface. + +Typical bookkeeping during PSCI power management calls include save/restore +of the EL3 Runtime Software context. Also if the EL3 Runtime Software makes +use of secure interrupts, then these interrupts must also be managed +appropriately during CPU power down/power up. Any secure interrupt targeted +to the current CPU must be disabled or re-targeted to other running CPU prior +to power down of the current CPU. During power up, these interrupt can be +enabled/re-targeted back to the current CPU. + +``` + typedef struct spd_pm_ops { + void (*svc_on)(u_register_t target_cpu); + int32_t (*svc_off)(u_register_t __unused); + void (*svc_suspend)(u_register_t max_off_pwrlvl); + void (*svc_on_finish)(u_register_t __unused); + void (*svc_suspend_finish)(u_register_t max_off_pwrlvl); + int32_t (*svc_migrate)(u_register_t from_cpu, u_register_t to_cpu); + int32_t (*svc_migrate_info)(u_register_t *resident_cpu); + void (*svc_system_off)(void); + void (*svc_system_reset)(void); + } spd_pm_ops_t; +``` +A brief description of each callback is given below: + +* svc_on, svc_off, svc_on_finish + + The `svc_on`, `svc_off` callbacks are called during PSCI_CPU_ON, + PSCI_CPU_OFF APIs respectively. The `svc_on_finish` is called when the + target CPU of PSCI_CPU_ON API powers up and executes the + `psci_warmboot_entrypoint()` PSCI library interface. + +* svc_suspend, svc_suspend_finish + + The `svc_suspend` callback is called during power down bu either + PSCI_SUSPEND or PSCI_SYSTEM_SUSPEND APIs. The `svc_suspend_finish` is + called when the CPU wakes up from suspend and executes the + `psci_warmboot_entrypoint()` PSCI library interface. The `max_off_pwrlvl` + (first parameter) denotes the highest power domain level being powered down + to or woken up from suspend. + +* svc_system_off, svc_system_reset + + These callbacks are called during PSCI_SYSTEM_OFF and PSCI_SYSTEM_RESET + PSCI APIs respectively. + +* svc_migrate_info + + This callback is called in response to PSCI_MIGRATE_INFO_TYPE or + PSCI_MIGRATE_INFO_UP_CPU APIs. The return value of this callback must + correspond to the return value of PSCI_MIGRATE_INFO_TYPE API as described + in [PSCI spec]. If the secure payload is a Uniprocessor (UP) + implementation, then it must update the mpidr of the CPU it is resident in + via `resident_cpu` (first argument). The updates to `resident_cpu` is + ignored if the secure payload is a multiprocessor (MP) implementation. + +* svc_migrate + + This callback is only relevant if the secure payload in EL3 Runtime + Software is a Uniprocessor (UP) implementation and supports migration from + the current CPU `from_cpu` (first argument) to another CPU `to_cpu` + (second argument). This callback is called in response to PSCI_MIGRATE + API. This callback is never called if the secure payload is a + Multiprocessor (MP) implementation. + +### 5.5 CPU operations + +The CPU operations (cpu_ops) framework implement power down sequence specific +to the CPU and the details of which can be found in the `CPU specific +operations framework` section of [Firmware Design]. The ARM Trusted Firmware +tree implements the `cpu_ops` for various supported CPUs and the EL3 Runtime +Software needs to include the required `cpu_ops` in its build. The start and +end of the `cpu_ops` descriptors must be exported by the EL3 Runtime Software +via the `__CPU_OPS_START__` and `__CPU_OPS_END__` linker symbols. + +The `cpu_ops` descriptors also include reset sequences and may include errata +workarounds for the CPU. The EL3 Runtime Software can choose to call this +during cold/warm reset if it does not implement its own reset sequence/errata +workarounds. + + +- - - - - - - - - - - - - - - - - - - - - - - - - - + +_Copyright (c) 2016, ARM Limited and Contributors. All rights reserved._ + +[PSCI spec]: http://infocenter.arm.com/help/topic/com.arm.doc.den0022c/DEN0022C_Power_State_Coordination_Interface.pdf "Power State Coordination Interface PDD (ARM DEN 0022C)" +[SMCCC]: https://silver.arm.com/download/ARM_and_AMBA_Architecture/AR570-DA-80002-r0p0-00rel0/ARM_DEN0028A_SMC_Calling_Convention.pdf "SMC Calling Convention" +[Porting Guide]: porting-guide.md +[Firmware Design]: ./firmware-design.md