Secure to Non-Secure State Transition in ARM Bootloaders
The transition from secure to non-secure state in ARM-based systems, particularly during the bootloader phase, is a critical operation that requires careful handling to ensure system security and functionality. This process involves switching from a secure execution environment, where sensitive operations such as hardware initialization and security checks are performed, to a non-secure environment where user-specific configurations and applications run. The ARM architecture provides specific mechanisms and instructions to facilitate this transition, but improper implementation can lead to security vulnerabilities or system failures.
In a typical ARM system, the boot process begins in the secure state, where the SOC bootloader executes. This bootloader is responsible for performing essential security checks, initializing the hardware, and configuring the system’s memory protection units (MPUs) and security attribution units (SAUs). Once these tasks are completed, the system must transition to the non-secure state to execute the device bootloader or application code. This transition is not trivial and requires adherence to specific architectural guidelines to ensure that the system remains secure and functional.
The ARM architecture defines the BXNS and BLXNS instructions for branching from secure to non-secure code. These instructions are designed to handle the state transition while preserving the security context. However, before invoking these instructions, the secure code must perform several preparatory steps, such as saving non-banked registers to secure memory, ensuring that the least significant bit (LSB) of the branch target address is set to 0, and clearing all non-banked registers. These steps are crucial to prevent leakage of secure information and to ensure that the non-secure code executes in a clean state.
Additionally, the ARM C Language Extensions (ACLE) provide the __attribute__((cmse_nonsecure_call))
function attribute, which simplifies the process of creating non-secure function pointers. This attribute instructs the compiler to generate the necessary code for a secure to non-secure transition, including the required register manipulations and state changes. Using this attribute can help reduce the risk of errors in the transition code, but it is still essential to understand the underlying mechanisms to ensure correct implementation.
Memory and Peripheral Access Control in Secure and Non-Secure States
The ARM architecture enforces strict memory and peripheral access controls to maintain the separation between secure and non-secure states. These controls are implemented through Memory Protection Controllers (MPCs) and Peripheral Protection Controllers (PPCs), which act as gatekeepers to determine whether a memory region or peripheral can be accessed from a particular security state.
Secure code can access non-secure memory and peripheral registers, but this access must be performed through non-secure alias addresses. These alias addresses are mapped to the same physical memory or peripheral but are tagged with a non-secure attribute, allowing secure code to access them without violating the security model. However, this access is subject to the configuration of the MPC and PPC, which must be properly set up during the secure boot phase to allow such accesses.
The MPC and PPC are responsible for enforcing the security attributes of memory and peripheral regions. These controllers are programmed during the secure boot process to define which regions are accessible from the secure state and which are restricted to the non-secure state. For example, a secure bootloader may configure the MPC to allow secure access to certain non-secure memory regions for initialization purposes, while restricting access to other regions that contain sensitive data.
It is important to note that the security attributes of memory and peripheral regions are not static and can be dynamically modified by secure code. This flexibility allows secure code to temporarily grant non-secure access to certain regions when necessary, but it also introduces the risk of misconfiguration. Improper configuration of the MPC or PPC can lead to security vulnerabilities, such as unauthorized access to secure memory or peripherals from the non-secure state.
Implementing Secure to Non-Secure Transitions and Access Controls
To implement a secure to non-secure transition in an ARM-based system, the following steps must be carefully followed:
-
Prepare the Secure Environment: Before transitioning to the non-secure state, the secure code must ensure that all non-banked registers are saved to secure memory. This step is crucial to prevent leakage of secure information to the non-secure state. Additionally, the secure code must clear all non-banked registers to ensure that the non-secure code executes in a clean state.
-
Set the Branch Target Address: The branch target address for the non-secure code must be properly configured. The least significant bit (LSB) of the address must be set to 0 to indicate a non-secure branch. This is a requirement of the ARM architecture and ensures that the processor correctly interprets the branch as a transition to the non-secure state.
-
Invoke the BXNS or BLXNS Instruction: The BXNS or BLXNS instruction is used to perform the actual transition to the non-secure state. These instructions handle the state change and ensure that the processor switches to the non-secure execution environment. It is important to note that these instructions can only be executed from the secure state.
-
Configure the MPC and PPC: The Memory Protection Controller (MPC) and Peripheral Protection Controller (PPC) must be properly configured to allow secure access to non-secure memory and peripherals. This configuration is typically performed during the secure boot phase and involves setting the appropriate security attributes for each memory and peripheral region.
-
Use Non-Secure Alias Addresses: Secure code must use non-secure alias addresses to access non-secure memory and peripherals. These alias addresses are mapped to the same physical memory or peripheral but are tagged with a non-secure attribute, allowing secure code to access them without violating the security model.
-
Validate the Transition: After transitioning to the non-secure state, it is important to validate that the transition was successful and that the system is operating as expected. This may involve checking the state of certain registers or peripherals to ensure that the non-secure code is executing correctly.
-
Handle Errors and Exceptions: In the event of an error or exception during the transition, the system must be able to recover gracefully. This may involve reverting to the secure state, logging the error, and taking appropriate corrective actions.
By following these steps, developers can ensure a secure and reliable transition from the secure to non-secure state in ARM-based systems. Proper implementation of these steps is critical to maintaining the security and functionality of the system, particularly in applications where the separation of secure and non-secure execution environments is essential.
In conclusion, the transition from secure to non-secure state in ARM-based systems is a complex process that requires careful attention to detail. By understanding the underlying mechanisms and following best practices, developers can ensure that their systems remain secure and functional throughout the boot process and beyond.