Cmse-1 4
Cmse-1 4
Contents
1 Preface 4
1.1 Abstract . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.2 Keywords . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.3 Latest release and defects report . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.4 License . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.4.1 About the license . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.5 Contributions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.6 Trademark notice . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.7 Copyright . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
3 SCOPE 9
3.1 Scope . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
3.2 Conventions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
4 OVERVIEW OF CMSE 10
4.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
4.1.1 Security state changes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
4.2 The TT instruction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
4.3 Secure code requirements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
4.3.1 Information leakage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
4.3.2 Non-secure memory access . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
4.3.3 Volatility of non-secure memory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
4.3.4 Inadvertent secure gateway . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
4.4 Development tools . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
4.4.1 Source level security state changes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
4.4.2 Executable files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
4.4.3 Secure gateway veneers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
4.4.4 Example C level development flow of secure code . . . . . . . . . . . . . . . . . . . . . . . . . 17
4.4.5 Reserved names . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
5 TT INSTRUCTION SUPPORT 20
5.1 Feature macro . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
5.2 TT intrinsics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
5.3 Address range check intrinsic . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
6 CMSE SUPPORT 24
6.1 Non-secure memory usage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
6.2 TT intrinsics for CMSE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
6.3 Address range check intrinsic for CMSE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
7 FUTURE EXTENSIONS 36
7.1 Non-secure callable function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
7.2 Non-secure returning function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
1. Preface
1.1 Abstract
This document describes the requirements on Development Tools in order to support Armv8-M and Armv8.1-M
Security Extensions or the new TT instruction of Armv8-M.
1.2 Keywords
ACLE, ABI, CMSE, Armv8-M, Armv8.1-M, Security, Extensions, toolchain, requirements, compiler, linkerarm.
1.4 License
This work is licensed under the Creative Commons Attribution-ShareAlike 4.0 International License. To view a copy
of this license, visit http://creativecommons.org/licenses/by-sa/4.0/ or send a letter to Creative Commons, PO Box
1866, Mountain View, CA 94042, USA.
Grant of Patent License. Subject to the terms and conditions of this license (both the Public License and this Patent
License), each Licensor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irre-
vocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and
otherwise transfer the Licensed Material, where such license applies only to those patent claims licensable by such
Licensor that are necessarily infringed by their contribution(s) alone or by combination of their contribution(s) with
the Licensed Material to which such contribution(s) was submitted. If You institute patent litigation against any
entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Licensed Material or a contribution
incorporated within the Licensed Material constitutes direct or contributory patent infringement, then any licenses
granted to You under this license for that Licensed Material shall terminate as of the date such litigation is filed.
1.5 Contributions
Contributions to this project are licensed under an inbound=outbound model such that any such contributions are
licensed by the contributor under the same terms as those in the LICENSE file.
We do not require copyright assignment. The original contributor will retain the copyright.
1.7 Copyright
Copyright 2019, 2021-2023 Arm Limited and/or its affiliates open-source-offi[email protected].
2.2 References
This document refers to the following documents.
Term Meaning
SAU Security Attribute Unit. Controls the separation of secure and non-secure memory regions.
IDAU Implementation Defined Attribute Unit. Enables system logic outside the processor to
separate secure and non-secure memory regions, similar to the SAU.
MPU Memory Protection Unit. Controls the permissions that privileged and unprivileged
execution modes have, memory region by memory region.
NSC region Non-Secure Callable memory region. Secure memory that is callable by code executing in
non-secure state.
TT Test Target Instruction. Used to inspect MPU, SAU, and IDAU configurations.
Entry function A function in secure memory that can be called from secure and non-secure state.
Term Meaning
Secure gateway A code sequence that provides a secure gateway to an entry function.
veneer
3. SCOPE
3.1 Scope
Armv8-M Security Extensions is in some contexts known as Cortex®-M Security Extensions and is referred to as
CMSE throughout this document. The Armv8.1-M Mainline architecture continues support for Armv8-M Security
Extensions and this document refers to both by Armv8-M unless otherwise specified.
This document states the requirements that development tools must satisfy in order to develop software in C that
uses the feature defined by CMSE. This document describes a machine-level standard that can be mapped directly
by functions written in C and assembly language.
This document also describes the support for the new TT instruction introduced in Armv8-M. This instruction is not
part of CMSE, but is closely related.
Some of the requirements defined by this document will be included in future [ACLE] and [BSABI] documents.
3.2 Conventions
This document consists of informative text and requirements.
Requirement 0
Requirements are numbered in the left margin and highlighted as shown here.
A permanent unique reference consists of the document number, document version, and requirement number.
4. OVERVIEW OF CMSE
4.1 Introduction
CMSE is an optional part of the Armv8-M baseline and mainline architecture defined by [ARMV8M]. CMSE is
designed to combine code from multiple vendors without requiring trust between them. CMSE gives vendors the
ability to protect their software assets (code and data) by restricting access to the memory where their software
assets reside, except for a set of explicitly exported entry points that are defined by the vendor. This supports
the creation of a trusted software stack that provides features such as secure remote firmware updates, while
significantly reducing the attack surface of such code. This is an important feature for any network-connected
device that can be updated after deployment, including any IoT device.
CMSE defines a system-wide division of physical memory into secure regions and non-secure regions and two system-
wide security states that are enforced by hardware. There is a direct relation between the memory regions and the
security states:
• Code executed from a non-secure region (non-secure code) is executed in non-secure state and can only access
memory in non-secure regions.
• Code executed from a secure region (secure code) is executed in secure state and can access memory in both
secure and non-secure regions.[ ]
Attempts to access secure regions from non-secure code or a mismatch between the (secure or non-secure) code
that executes and the security state of the system, results in a SecureFault.
The security states are orthogonal to the exception level, as shown in figure Diagrammatic representation of secure
states.
Memory regions can be defined by the system through the IDAU or can be controlled in software through the
memory mapped SAU registers.
Parts of the system are banked between the security states. The stack pointer is banked, resulting in a stack pointer
for each combination of security state and exception level. All parts of the system accessible in non-secure state
can be accessed in secure state as well, including the banked parts.
A branch to the reserved value FNC_RETURN causes the hardware to switch to secure state, read an address from the
top of the secure stack, and branch to that address. The reserved value FNC_RETURN is written to lr when executing
the BLXNS instruction.
Security state transitions can be caused by hardware through the handling of interrupts. Those transitions are
transparent to software and are ignored in the remainder of this document.
Requirement 1
Secure code must clear secret information from unbanked registers before it initiate a transition from secure
to non-secure state.
Requirement 2
Secure code that accesses non-secure memory on behalf of the non-secure state must only do so if the
non-secure state has permission to perform the same access itself.
The secure code can use the TT instruction to check non-secure memory permissions.
Requirement 3
Secure code must not access non-secure memory unless it does so on behalf of the non-secure state.
Requirement 4
The introductory example of the section Volatility of non-secure memory shows a case that you can handle as
follows:
int array[N]
void foo(volatile int *p) {
int i = *p;
if (i >= 0 && i < N) {
array[i] = 0;
}
}
Situations that the toolchain must handle are described in Non-secure memory usage.
• Uninitialized memory.
• General data in executable memory, for example jump tables.
• A 32-bit wide instruction that contains the bit pattern 1110 1001 0111 1111 in its first half-word that follows
an SG instruction, for example two successive SG instructions.
• A 32-bit wide instruction that contains the bit pattern 1110 1001 0111 1111 in its last half-word that is
followed by an SG instruction, for example an SG instruction that follows an LDR (immediate) instruction.
If an inadvertent SG instruction occurs in an NSC region, the result is an inadvertent secure gateway.
Requirement 5
The secure gateway veneers introduced in Secure gateway veneers limit the instructions that need to be placed in
NSC regions. If the NSC regions contain only these veneers, an inadvertent secure gateway cannot occur.
Requirement 6
Security state changes must be expressed through function calls and returns.
This provides an interface that fits naturally with the C language. A function in secure code that can be called from
the non-secure state through its secure gateway is called an entry function. A function call from secure state to the
non-secure state is called a non-secure function call. This is shown in Security state transitions.
Requirement 7
From the point of view of the non-secure state, a call to a secure gateway is a regular function call, as is the return
from a non-secure function call. It is therefore required that a non-secure executable file can be developed using a
toolchain that is not aware of CMSE.
Developing a secure executable file requires toolchain support whenever a function is called from, calls, or returns
to non-secure state and whenever memory is accessed through an address provided by the non-secure state. The
secure code ABI is otherwise identical to the non-secure code ABI.
For Armv8-M Mainline there are occasions where there is no possible code-generation that abides the VFP ABI rule
that mandates that exception-control bits of the FPSCR may only be modified by specific support functions. After
returning from an entry call or when performing a nonsecure-call using the hard-float ABI the FPSCR will have been
initialized with the secure world’s default FPSCR, the FPDSCR_S. For the soft-float ABI this is not the case as the
VLSTM and VLDM instructions may be used. Armv8.1-M Mainline introduces instructions that enable the saving
and restoring of the FP context. These are the VMSR, VMRS, VSTR and VLDR to system registers FPCXTNS and
FPCXTS.
The interaction between developers of secure code, non-secure code, and (optional) security agnostic library code
is shown in Files shared between parties.
The secure gateway import library, shortened to import library, contains the addresses of the secure gateways of
the secure code. This import library consists of or contains a relocatable file that defines symbols for all the secure
gateways. The non-secure code links against this import library to use the functionality provided by the secure
code.
Requirement 8
A relocatable file containing only copies of the (absolute) symbols of the secure gateways in the secure
executable must be available to link non-secure code against.
Linking against this import library is the only requirement on the toolchain used to develop the non-secure code.
This functionality is very similar to calling ROM functions, and is expected to be available in existing toolchains.
Copyright 2019, 2021-2024 Arm Limited and/or its affiliates open-source-offi[email protected].
Page 15 of 44
Arm®v8-M Security Extensions Requirements on Development Tools Version: 1.4
OVERVIEW OF CMSE
Requirement 9
A toolchain must support generating a secure gateway veneer for each entry function with external linkage.
It consists of an SG instruction followed by a B.W instruction that targets the entry function it veneers.
Secure gateway veneers decouple the addresses of secure gateways (in NSC regions) from the rest of the secure
code. By maintaining a vector of secure gateway veneers at a forever-fixed address, the rest of the secure code can
be updated independently of non-secure code. This also limits the amount of code in NSC regions that potentially
can be called by the non-secure state.
Requirement 10
A secure gateway veneer must be labelled by an ELF symbol that has the same binding, type, and name as
the function it veneers, following the rules for C entities as defined by [AAELF].
To prevent duplicate symbol names, an entry function will “lose” its standard symbol when its secure gateway veneer
is created. For instance, the compiler could use weak symbols for entry functions.
Requirement 11
A toolchain must support creating a vector of secure gateway veneers consisting of one or more veneers
placed consecutively in memory.
Vectors of secure gateway veneers are expected to be placed in NSC memory. All other code in the secure exe-
cutable is expected to be placed in secure memory regions. This placement is under your control.
Preventing inadvertent secure gateways as described in Inadvertent secure gateway is a responsibility shared be-
tween you and the toolchain in use. A toolchain must make it possible for you to avoid creating inadvertent secure
gateways.
Requirement 12
Excluding the first instruction of a secure gateway veneer, a veneer must not contain the bit pattern of the
SG instruction on a 2-byte boundary.
Requirement 13
A vector of secure gateway veneers must be aligned to a 32-byte boundary, and must be zero padded to a
32-byte boundary.
You should take care that the code or data before the vector of secure gateway veneers does not create an inad-
vertent secure gateway with the first secure gateway veneer in the vector. Arm recommends placing the vector of
secure gateway veneers at the start of a NSC region.
Requirement 14
You must have granted control of the position of secure gateway veneers in a vector.
This last requirement gives you complete control over the address of a secure gateway veneer. It allows you to fix
the addresses of the secure gateway veneers such that secure code can be updated independently of non-secure
code.
Secure executable memory layout shows the memory layout of a secure executable.
func1:
BX lr
entry1:
__acle_se_entry1:
PUSH {r11, lr}
BL func1
POP {r11, lr}
BXNS lr
entry2:
__acle_se_entry2:
PUSH {r11, lr}
BL entry1
POP {r11, lr}
BXNS lr
.weak entry1, entry2
An entry function starts with two symbols labelling its start; it does not start with an SG instruction. This indicates
an entry function to the linker. Note: alternatively, the compiler can use the __acle_se_entry1 symbol rather than
the entry1 symbol in function entry2. This would make the function call skip the secure gateway veneer.
When the relocatable file corresponding to this assembly code is linked into an executable file, the linker creates
the following veneers in a section containing only entry veneers:
entry1:
SG
B.W __acle_se_entry1
entry2:
SG
B.W __acle_se_entry2
Note: the section with the veneers is aligned on a 32-byte boundary and padded to a 32-byte boundary. Placement
of the section with the veneers is under your control, but must be in an NSC region.
In addition to the final executable, our example linker also produces the import library for non-secure code. As-
suming the section with veneers is placed at address 0x100, the import library consists of a relocatable file which
contains only a symbol table with the following entries:
Finally, the secure executable file can be pre-loaded on the device. The device with pre-loaded executable, the
import library, and the header file can be delivered to a party who develops non-secure code for this device.
Requirement 15
5. TT INSTRUCTION SUPPORT
This chapter defines the language extension that provides C applications access to the TT instruction. Support for
the TT instruction described here is generic to the Armv8-M architecture, and is not part of CMSE, but is closely
related.
Requirement 16
The <arm_cmse.h> header must be included before using the TT instruction support.
Requirement 17
Requirement 18
All undefined bits of macro __ARM_FEATURE_CMSE are reserved for future use and must be unset.
The flags defined by __ARM_FEATURE_CMSE as described here and in 9 result in the following values for this macro:
Value Meaning
3 Toolchain targets the secure state of CMSE (implies the availability of the TT instruction)
5.2 TT intrinsics
The result of the TT instruction is described by a C type containing bit-fields. This type is used as the return type
of the TT intrinsics.
As specified by [AAPCS], the endianness of a system affects the bit-offsets of bit-fields, but the result of the TT
instruction is not influenced by endianness.
Requirement 19
If __ARM_BIG_ENDIAN is unset and bit 0 of macro __ARM_FEATURE_CMSE is set, the following type must be
declared:
typedef union {
struct cmse_address_info {
unsigned mpu_region:8;
unsigned :8;
unsigned mpu_region_valid:1;
unsigned :1;
unsigned read_ok:1;
unsigned readwrite_ok:1;
unsigned :12;
} flags;
unsigned value;
} cmse_address_info_t;
Requirement 20
If __ARM_BIG_ENDIAN is set, the bit-fields in the type defined by requirement 19 are reversed such that they
have the same bit-offset as on little-endian systems following the rules specified by [AAPCS].
Requirement 21
Requirement 22
Intrinsic Semantics
Arm recommends that a toolchain behaves as if these intrinsics would write the pointed-to memory. That prevents
subsequent accesses to this memory being scheduled before this intrinsic.
The exact type signatures for cmse_TT_fptr() and cmse_TTT_fptr() are implementation-defined because there
is no type defined by [ISOC] that can hold all function pointers. Arm recommends implementing these intrinsics as
Copyright 2019, 2021-2024 Arm Limited and/or its affiliates open-source-offi[email protected].
Page 21 of 44
Arm®v8-M Security Extensions Requirements on Development Tools Version: 1.4
TT INSTRUCTION SUPPORT
macros.
Requirement 23
The address range check intrinsic must be available if bit 0 of macro __ARM_FEATURE_CMSE is set. It has
the following type signature: void *cmse_check_address_range(void *p, size_t size, int flags)
Requirement 24
The address range check intrinsic checks the address range from p to p + size – 1.
Requirement 25
Some SAU, IDAU and MPU configurations block the efficient implementation of an address range check. This
intrinsic operates under the assumption that the configuration of the SAU, IDAU, and MPU is constrained as follows:
• An object is allocated in a single region.
• A stack is allocated in a single region.
These points imply that a region does not overlap other regions.
An SAU, IDAU and MPU region number is returned by the TT instruction. When the region numbers of the start
and end of the address range match, the complete range is contained in one SAU, IDAU, and MPU region. In this
case two TT instructions are executed to check the address range.
Regions are aligned at 32-byte boundaries. If the address range fits in one 32-byte address line, a single TT instruc-
tion suffices. This is the case when the following constraint holds:
(p mod 32) + size <= 32
Requirement 26
The address range check intrinsic fails if the range crosses any MPU region boundary.
The SAU and IDAU support for this intrinsic is defined in Address range check intrinsics for CMSE.
The rest of the semantics of the address range check intrinsic depend on its flags parameter. This parameter can
be constructed using a bitwise OR operator.
Requirement 27
The flags parameter of the address range check consists of a set of values. Each value must have a macro
defined for it, with the name and semantic effects as defined in the following table:
Requirement 28
The address range check must fail if the flags parameter contains a value that cannot be constructed using
a bitwise OR operator on the values defined by requirement 27.
Requirement 29
The address range check intrinsic returns NULL on a failed check, and p on a successful check.
Arm recommends that you to use the returned pointer to access the checked memory range. This generates a data
dependency between the checked memory and all its subsequent accesses and prevents these accesses from being
scheduled before the check.
Requirement 30
Intrinsic Semantics
6. CMSE SUPPORT
This chapter defines the language extension that provides support for secure executable files written in the C
language. Non-secure executable files do not require any additional toolchain support.
Requirement 31
The <arm_cmse.h> header must be included before using CMSE support, except for using the
__ARM_FEATURE_CMSE macro.
Requirement 32
Bits 0 and 1 of feature macro __ARM_FEATURE_CMSE are set if CMSE support for secure executable files is
available.
Requirement 33
The storage of any object declared in a translation unit must be a register or secure memory.
The security implications of accessing non-secure memory through a pointer are your responsibility. Any other
access to non-secure memory by secure code is called a “generated non-secure memory access” and is the respon-
sibility of the C language translation system.
Requirement 34
A generated non-secure memory read (or write) must check that the non-secure state can read (or write)
this memory before accessing it.
Requirement 35
Any attempted generated non-secure memory read (or write) to memory that is not readable (or writable)
by the non-secure state must result in a call to the cmse_abort() function. The programmer handles the
case where a generated non-secure memory access fails the compiler-generated check, by defining the
cmse_abort() function. This function should never return.
The following pseudocode describes the general code sequence for a generated non-secure memory write access
at address nsaddr and of size SIZE. An implementation is not required to use this particular code sequence.
addr = cmse_check_address_range(nsaddr, SIZE, CMSE_MPU_READWRITE | CMSE_NONSECURE)
if addr == 0 then
Copyright 2019, 2021-2024 Arm Limited and/or its affiliates open-source-offi[email protected].
Page 24 of 44
Arm®v8-M Security Extensions Requirements on Development Tools Version: 1.4
CMSE SUPPORT
cmse_abort()
//access to [addr, addr+SIZE-1] is now permitted
The macros CMSE_MPU_READWRITE and CMSE_NONSECURE are defined in Address range check intrinsics for CMSE. The
cmse_check_address_range intrinsic is defined in Address range check intrinsics and extended in Address range
check intrinsics for CMSE.
As mentioned in Address range check intrinsics, the address range check can be done efficiently if the non-secure
stack does not cross the boundary of any memory region defined by the MPU, SAU, and IDAU.
Requirement 36
A C language translation system must generate code to handle a generated non-secure memory access in
each of the following situations:
• An entry function called from non-secure state assigns an argument written to memory by the non-
secure state to its corresponding parameter (as defined by §6.5.2.2 paragraph 4 of [ISOC]);
• An entry function returns control to its non-secure caller and writes its return value to memory (as
defined by §6.8.6.4 paragraph 3 of [ISOC]);
• A function call that targets the non-secure state assigns an argument to the corresponding parameter
(as defined by §6.5.2.2 paragraph 4 of [ISOC]);
• A return value of a function call that targets the non-secure state is read from memory (as defined by
§6.8.6.4 paragraph 3 of [ISOC]).
This is explained in more detail in 9.4 Entry functions, and 9.5 Non-secure function call.
Requirement 37
If __ARM_BIG_ENDIAN is unset and bit 1 of macro __ARM_FEATURE_CMSE is set, the following type must be
declared:
typedef union {
struct cmse_address_info {
unsigned mpu_region:8;
**unsigned sau_region:8;**
unsigned mpu_region_valid:1;
**unsigned sau_region_valid:1;**
unsigned read_ok:1;
unsigned readwrite_ok:1;
**unsigned nonsecure_read_ok:1;**
**unsigned nonsecure_readwrite_ok:1;**
**unsigned secure:1;**
**unsigned idau_region_valid:1;**
**unsigned idau_region:8;**
} flags;
unsigned value;
} cmse_address_info_t;
Requirement 38
If __ARM_BIG_ENDIAN is set the bit-fields in the type defined by requirement 37 must be reversed such that
they have the same bit-offset as on little-endian systems following the rules specified by [AAPCS].
Requirement 39
Intrinsic Semantics
Note: the TT intrinsics defined by requirement 22 must also be provided for the CMSE support. Implementation
recommendations can be found there.
Requirement 40
The address range check must fail if the range crosses any SAU or IDAU region boundary.
Requirement 41
If bit 1 of macro __ARM_FEATURE_CMSE is set, the values accepted by the flags parameter, as defined by
requirement 27, must be extended with the values defined in the following table:
CMSE_MPU_NONSECURE 16 Sets the A flag on the TT instruction used to retrieve the permissions of an
address.
Requirement 42
Arm recommends generating a diagnostic for an entry function with static linkage.
Requirement 43
An entry function has two ELF function (STT_FUNC) symbols labelling it:
• A symbol that follows the standard naming for C entities as defined by [AAELF] labels the function’s
inline secure gateway if it has one, otherwise the function’s first instruction.
• A special symbol that prefixes the standard function name with __acle_se_ labels the function’s first
non-SG instruction.
The special symbol acts as an entry function attribute in the relocatable file. Tools that operate on relocatable files
can use this symbol to detect the need to generate a secure gateway veneer (see Secure gateway veneers) and a
symbol in the import library (see Executable files).
Requirement 44
A toolchain must generate a secure gateway veneer for an entry function that has both its symbols labelling
the same address. Otherwise a secure gateway is assumed to be present.
Requirement 45
The address of an entry function must be the address labelled by its standard symbol.
This must be the address of its associated SG instruction, usually the first instruction of its secure gateway veneer.
This veneer is labelled by the function’s standard symbol name.
Requirement 46
If a toolchain supports stack-based arguments, it must be aware of the volatile behavior of non-secure memory
(Volatility of non-secure memory) and the requirements of using non-secure memory (Non-secure memory usage),
in particular requirement 36.
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.
Code that performs this copying must check the accessibility of the non-secure memory as described by the pseu-
docode in Non-secure memory usage. An example entry function epilogue and prologue can be found in Example
entry function.
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 stack usage of an entry function is shown in Entry function’s caller stack frame.
Calls from Non-secure state follow the [AAPCS], which states that the caller is responsible for zero- or sign-
extending arguments of integral Fundamental Data Types smaller than a word to 4 bytes. An Entry function must
not assume that callers follow this rule, that is, it cannot presume that integral parameters will have been zero- or
sign-extended to 4 bytes. For example, an attacker might create code that passes arguments out of their declared
type’s range in an attempt to cause out-of-bounds memory accesses.
Requirement 47
A compiler generating code for an entry function must, for each parameter that is an integral Fundamental
Data Type smaller than a word, make no assumptions about the value of the padding bits, even when the
value of those bits are defined by the AAPCS.
__attribute__((cmse_nonsecure_entry))
int func(unsigned char idx) {
return array[idx];
}
__acle_se_func:
func:
...
@ narrow 'idx' to 8 bits before first use
uxtb r0, r0
movw r1, :lower16:array
movt r1, :upper16:array
ldr.w r0, [r1, r0, lsl #2]
...
bxns lr
We recommend that function parameters with integral types smaller than 4 bytes should be avoided. This recom-
mendation extends to underlying types of enum used as parameters.
Requirement 48
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 lr is automatically cleared by the SG instruction when it switches the state from non-secure to secure.
To prevent information leakage when an entry function returns, you must clear the registers that contain secret
information (Information leakage).
Requirement 49
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
[AAPCS].
• Restore all callee-saved registers as mandated by [AAPCS].
• Restore bits [27:0] of FPSCR (Armv8.1-M Mainline only).
You can clear the floating-point registers conditionally by checking the SFPA bit of the special-purpose CONTROL
register.
A toolchain could provide you with the means to specify that some types of variables never hold secret informa-
tion. For example, by setting the TS bit of FPCCR, CMSE assumes that floating point registers never hold secret
information.
An example entry function epilogue can be found in Example entry functions.
Because of these requirements, performing tail-calls from an entry function is difficult.
The following intrinsic function must be provided if bit 1 of macro __ARM_FEATURE_CMSE is set:
Intrinsic Semantics
Calling an entry function from the non-secure state results in a return address with its LSB unset. This can be used
to implement the intrinsic. Note: this type of implementation requires a stable location for the return address.
As a consequence of the semantics of cmse_nonsecure_caller(), it always returns zero when used outside an
entry function. A toolchain is not required to diagnose the usage of cmse_nonsecure_caller() outside an entry
function, although this might become a requirement in the future.
Requirement 51
Requirement 52
This disallows function definitions with this attribute and ensures a secure executable file only contains secure
function definitions.
Requirement 53
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 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 as described in Information leakage. 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.
Requirement 54
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].
• Save and clear bits [27:0] of FPSCR (Armv8.1-M Mainline only).
A toolchain could provide you with the means to specify that some types of variables never hold secret information.
Requirement 55
When the non-secure function call returns, caller- and callee-saved registers saved before the call must be
restored. This includes bits [27:0] of FPSCR (Armv8.1-M Mainline only). An implementation need not save
and restore a register if its value is not live across the call. Note: callee-saved registers are live across the
call in almost all situations. These requirements specify behaviour that is similar to a regular function call,
except that:
• Callee-saved registers must be saved as if they were caller-saved registers.
• Registers that are not banked and potentially contain secret information must be cleared.
The floating point registers can very efficiently be saved and cleared using the VLSTM, and restored using VLLDM
instructions.
An example instruction sequence for a non-secure call is listed in Example non-secure function call.
Requirement 56
To avoid using the non-secure stack, a toolchain may constrain the following, for a non-secure function type:
• The number of parameters.
• The type of each parameter.
• The return type.
Requirement 57
If a compiler supports stack-based arguments and results, it must be aware of the volatile behavior of non-secure
memory (Volatility of non-secure memory) and the requirements of using non-secure memory (Non-secure memory
usage), in particular requirement 36.
In practice, a toolchain might generate code that:
• Creates the caller’s stack argument area on the non-secure stack and uses this space for no other purpose.
• Copies the callee’s return value from the non-secure stack to the secure stack after the non-secure function
call returns.
Code that performs these tasks must check the non-secure memory as described by the pseudocode in Non-secure
memory usage.
If the return value is read once, a possible optimization would be to read the return value directly from the non-
secure stack at the point of use. In this case, access checks are still required.
The stack usage during a non-secure function call is shown in figure Caller’s stack frame of a non-secure function
call.
The return of values from Non-secure function calls follows the [AAPCS], which states that the callee is responsible
for zero- or sign-extending return values of integral Fundamental Data Types smaller than a word to 4 bytes. A
Secure function must not assume that Non-secure callees follow this rule, that is, it cannot presume that integral
returned values will have been zero- or sign-extended to 4 bytes. For example, an attacker might create code that
returns values out of their declared type’s range in an attempt to cause out-of-bounds memory accesses.
Requirement 58
A compiler generating code for a Non-secure function call must, for each returned value that is an integral
Fundamental Data Type smaller than a word, make no assumptions about the value of the padding bits, even
when the value of those bits are defined by the AAPCS.
Time
Non-sec ure stac k
Non-sec ure stac k
Non-sec ure stac k
Figure 6.2: Caller’s stack frame of a non-secure function call
securefunc:
...
@ r1 has the address of 'nonsecurefunc'
@ r2 has 'array'
@ non-secure function call
blxns r1
@ narrow 'idx' (returned value in r0) to a 16-bit value
uxth r0, r0
ldr.w r0, [r2, r0, lsl #2]
bl print
...
We recommend that function return values with integral types smaller than 4 bytes should be avoided. This rec-
ommendation extends to underlying types of enum used as return values.
void call_callback(void) {
fp(); // function call via pointer. It can be either secure or non-secure
}
The global variable fp is of a non-secure function type but can hold the address of a secure or non-secure function.
Arm recommends that you do not share this variable.
Since fp can hold either type of function, the compiler might generate code to save and clear registers in preparation
for a security state transition even if the function call nevers performs such transition at run-time.
To mitigate this, an nsfptr provides a way to test at run-time the security state that will be targeted when performing
a call through this pointer. By using the nsfptr related intrinsics, it is possible to check at run-time which function
call to perform and therefore avoid unnecessary register context saving and clearing.
#include <arm_cmse.h>
typedef void __attribute__((cmse_nonsecure_call)) nsfunc(void);
void default_callback(void) { . . . }
// fp can point to a secure function or a non-secure function
nsfunc *fp = (nsfunc *) default_callback; // secure function pointer
void call_callback(void) {
if (cmse_is_nsfptr(fp)) fp(); // non-secure function call.
// Context saved and cleared
else ((void (*)(void)) fp)(); // normal function call. Context untouched
}
This is just an optimisation technique and hence it is not required for the correct usage of non-secure function
pointers.
Requirement 59
Intrinsic Semantics
Note: the exact type signatures of these intrinsics are implementation-defined because there is no type defined
by [ISOC] that can hold all function pointers. Arm recommends implementing these intrinsics as macros and rec-
ommends that the return type of cmse_nsfptr_create() is identical to the type of its argument. An example
implementation is listed in Non-trivial macros.
7. FUTURE EXTENSIONS
This chapter lists possible features of a future version of this specification. It does not imply any commitment.
Requirement 60
Requirement 61
No veneer is generated as defined in Secure gateway veneers because the special symbol’s value is different to the
normal symbol’s value.
Toolchain support is needed to prevent inadvertent secure gateways from occurring (Inadverted secure gataway).
Requirement 62
A toolchain must provide a way for the programmer to guarantee that a non-secure callable function does
not contain an inadvertent SG instruction in code or data.
Arm recommends that toolchains provide a way to scan NSC regions for inadvertent SG instructions in an executable
image.
A non-secure returning function has a special epilogue, identical to that of an entry function.
// check that the range does not cross MPU, SAU, or IDAU region boundaries
if (permb.value != perme.value) return NULL;
msr APSR_nzcvqg, r2
@ perform the call to the non-secure function
bic r0, r0, #1
blxns r0
@ save the floating point result of the call
vmov r1, s0
@ unprotect the FP context and restore it if it was pushed
vlldm sp
add sp, sp, #0x88
@ restore the floating point result value
vmov s0, r1
@ restore the callee-saved registers and return
pop {r4-r12, pc}
The register r1 contains the floating point argument for the non-secure function call. This is not secret information
and does not need to be cleared.
The floating point argument to the non-secure function needs to be saved to and restored from an integer register
because the vlstm instruction saves and clears all floating point registers. The same holds for the return value from
the non-secure function because the vlldm instruction restores all floating point registers.
#include <arm_cmse.h>
int __attribute__((cmse_nonsecure_entry)) foo(int a) {
return a + 1;
}
In this example the compiler has complete knowledge of the registers used. No floating point registers are used
and there is no non-secure stack usage. This case results in a very compact instruction sequence:
.global foo
.global __acle_se_foo
foo:
__acle_se_foo:
add r0, #1
bxns lr
Since this is a leaf function, the compiler can determine that all the values in both integer and floating point registers
do not contain secure values that need to be cleared. The same reasoning holds for the status flags.
it ne
blne cmse_abort
@ 8: check bit 20 of the TT result (non-secure read flag)
tst r5, #0x100000
it eq
bleq cmse_abort
@ 9: copy arguments from non-secure stack to secure stack
ldr r5, [r4 ]
ldr r6, [r4, #4 ]
str r5, [sp, #16]
str r6, [sp, #20]
.LdoneARGS:
@10: function body
ldr r0, [sp, #16]
ldr r1, [sp, #20]
bl bar
@11: restore used callee-saved registers
pop {r4-r6, lr}
@12: if called from secure, we are done
tst lr, #1
it ne
bxne lr
@13: pop secure stack space
add sp, sp, #8
@14: check SFPA bit to see if FP is used
mrs r1, control
tst r1, #8
bne .LdoneFP
@15: clear floating point caller-saved registers
mov r1, #0
vmov s0, s1, r1, r1
vmov s2, s3, r1, r1
...
vmov s30, s31, r1, r1
@16: clear floating point flags
vmsr fpscr, r1
.LdoneFP:
@17: clear integer caller-saved registers except for return value
mov r1, #0
mov r2, #0
mov r3, #0
@18: clear other registers and the integer status flags
mov r12, #0
msr APSR_nzcvqg, r3
@19: return to non-secure state
bxns lr
#include <arm_cmse.h>
struct s { int a, int b};
struct s __attribute__((cmse_nonsecure_entry)) foo(void) {
return (struct s) { 4, 2 };
}
The function foo uses the stack to return the structure. The following T32 instruction sequence is an implementa-
tion of this function:
.global foo
.global __acle_se_foo
foo:
__acle_se_foo:
@ 1: if called from secure, memory for the result value is assumed correct
tst lr, #1
bne .LdoneRES
@ 2: calculate final address of result value
adds r1, r0, #7
@ 3: take permissions at begin and end of range
tta r2, r0
tta r3, r1
@ 4: check if range is in one region (this means identical permissions)
cmp r2, r3
it ne
blne cmse_abort
@ 5: check bit 21 of the TT result (non-secure readwrite flag)
tst r2, #0x200000
it eq
bleq cmse_abort
.LdoneRES:
@ 6: function body
movs r2, #2
movs r1, #4
str r2, [r0, #4]
str r1, [r0 ]
@ 7: clear integer caller-saved registers except for return value
movs r3, #0
@ 8: clear integer status flags
msr APSR_nzcvqg, r3
@ 9: return to secure or non-secure state (controlled by the LSB of lr)
bxns lr
All the code executed in secure state by this entry function is known. The clearing sequence can therefore be
optimized. The floating point registers are not cleared and only register r3 holds potentially secret information.