You copied the Doc URL to your clipboard.

CMSE Support

CMSE is an extension to the C language that can be implemented by tool vendors to provide toolchain support for Secure executable files that are written in the C language. Non-secure executable files do not require any additional toolchain support.

The <arm_cmse.h> header must be included before using CMSE support, except for using the __ARM_FEATURE_CMSE macro.

Bits 0 and 1 of feature macro __ARM_FEATURE_CMSE are set if CMSE support for Secure executable files is available.

Availability of CMSE implies availability of the TT instruction.

A compiler might provide a switch to enable support for creating CMSE Secure executable files. ARM recommends such a switch to be named -mcmse.

Non-secure memory usage

Secure code must only use Secure memory except when communicating with the Non-secure state.

The security implications of accessing Non-secure memory through a pointer are the responsibility of the developer.

Arguments and return value

A caller from the Non-secure state is not aware it is calling an entry function. If it must use the stack to write arguments or read a result value that uses the Non-secure stack.

If a toolchain supports stack-based arguments, it must be aware of the volatile behavior of Non-secure memory and the requirements of using Non-secure memory.

In practice, a compiler might generate code that:

  • Copies stack-based arguments from the Non-secure stack to the parameter on the Secure stack in the prologue of the entry function.
  • Copies the stack-based return value from the Secure stack to the Non-secure stack in the epilogue.

A possible optimization would be to access the Non-secure stack directly for arguments that read at most once, but accessibility checks are still required.

The following figure shows the stack use of an entry function.

entry_function.png

Return from an entry function

An entry function must use the BXNS instruction to return to its Non-secure caller.

This instruction switches to Non-secure state if the target address has its LSB unset. The LSB of the return address in the LR is automatically cleared by the SG instruction when it switches the state from Non-secure to Secure.

Note

To prevent information leakage when an entry function returns, the registers that contain secret information must be cleared.

The code sequence directly preceding the BXNS instruction that transitions to Non-secure code must:

  • Clear all caller-saved registers except:
    • Registers that hold the result value and the return address of the entry function.
    • Registers that do not contain secret information.
  • Clear all registers and flags that have UNDEFINED values at the return of a procedure, according to the Procedure Call Standard for the ARM Architecture (AAPCS).
  • Restore all callee-saved registers as required by the Procedure Call Standard for the ARM Architecture (AAPCS).

Floating-point registers can be cleared conditionally by checking the SFPA bit of the special-purpose CONTROL register.

A toolchain can provide the developer with the means to specify that some types of variables never hold secret information. For example, by setting the TS bit of FPCCR, The ARMv8-M Security Extension assumes that floating-point registers never hold secret information.

Because of these requirements, performing tail-calls from an entry function is difficult.

Security state of the caller

An entry function can be called from Secure or Non-secure state. Software must distinguish between these cases. To enable this, the ARMv8-M Security Extensions define the following intrinsic:

Intrinsic

Description

int cmse_nonsecure_caller(void)

Returns non-zero if entry function is called from Non-secure state and zero otherwise.

Non-secure function call

A call to a function that switches state from Secure to Non-secure is called a Non-secure function call. A Non-secure function call must use function pointers. This is a consequence of separating Secure and Non-secure code into separate executable files.

A Non-secure function type must be declared using the function attribute __attribute__((cmse_nonsecure_call)).

A Non-secure function type must only be used as a base type of a pointer. This restriction disallows function definitions with this attribute and ensures that a Secure executable file only contains Secure function definitions.

Performing a call

A function call through a pointer with a Non-secure function type as its base type must switch to the Non-secure state. To create a function call that switches to the Non-secure state, an implementation must emit code that clears the LSB of the function address and branches using the BLXNS instruction.

Note

A Non-secure function call to an entry function is possible. This call to an entry function behaves like any other Non-secure function call.

All registers that contain secret information must be cleared to prevent information leakage when performing a Non-secure function call. Registers that contain values that are used after the Non-secure function call must be restored after the call returns. Secure code cannot depend on the Non-secure state to restore these registers.

The code sequence directly preceding the BLXNS instruction that transitions to Non-secure code must:

  • Save all callee- and live caller-saved registers by copying them to Secure memory.
  • Clear all callee- and caller-saved registers except:
    • The LR.
    • The registers that hold the arguments of the call.
    • Registers that do not hold secret information.
  • Clear all registers and flags that have UNDEFINED values at the entry to a procedure according to the AAPCS.

A toolchain could provide the developer with the means to specify that some types of variables never hold secret information.

When the Non-secure function call returns, caller and callee that are saved registers that are saved before the call must be restored.

An implementation need does not have to save and restore a register if its value is not live across the call. However, callee-saved registers are live across the call in almost all situations. These requirements specify behavior that is similar to a regular function call, except that:

  • Callee-saved registers must be saved as if they are caller-saved registers.
  • Registers that are not banked and potentially contain secret information must be cleared.

The floating-point registers can efficiently be saved and cleared using the VLSTM instruction, and restored using VLLDM instruction.

Arguments and return value

The callee of a Non-secure function call is called in Non-secure state. If stack use is required according to the AAPCS, the Non-secure state expects to find the arguments on the Non-secure stack and writes the return value to Non-secure memory.

The stack usage during a Non-secure function call is shown in the following figure:

nonseure_function.png

Intrinsic

Description

cmse_nsfptr_create(p)

Returns the value of p with its LSB cleared. The argument p can be any function pointer type.

cmse_is_nsfptr(p)

Returns non-zero if p has LSB unset, zero otherwise. The argument p can be any function pointer type.

Note

The exact type signatures of these intrinsics are implementation-defined because there is no type defined by the C programming language that can hold all function pointers. ARM recommends implementing these intrinsics as macros and recommends that the return type of cmse_nsfptr_create() is identical to the type of its argument.

A Non-secure returning function must be declared by using the attribute __attribute__((cmse_nonsecure_return)) on a function declaration.

A Non-secure returning function has a special epilogue, identical to that of an entry function.

Was this page helpful? Yes No