doc/hardware/arch/arm_cortex_m.rst
.. _arm_cortex_m_developer_guide:
Arm Cortex-M Developer Guide ############################
Overview
This page contains detailed information about the status of the Arm Cortex-M architecture porting in the Zephyr RTOS and describes key aspects when developing Zephyr applications for Arm Cortex-M-based platforms.
Key supported features
The table below summarizes the status of key OS features in the different Arm Cortex-M implementation variants.
+---------------------------------+-----------------------------------+-----------------+---------+--------+-----------+--------+---------+------------+------------+------------+ | | | Processor families | | +---------------------------------+-----------------------------------+-----------------+---------+--------+-----------+--------+---------+------------+------------+------------+ | Architecture variant | | Arm v6-M | Arm v7-M | Arm v8-M | Arm v8.1-M | +---------------------------------+-----------------------------------+-----------------+---------+--------+-----------+--------+---------+------------+------------+------------+ | | | M0/M1 | M0+ | M3 | M4 | M7 | M23 | M33 | M55 | M85 | +---------------------------------+-----------------------------------+-----------------+---------+--------+-----------+--------+---------+------------+------------+------------+ | OS Features | | | | +---------------------------------+-----------------------------------+-----------------+---------+--------+-----------+--------+---------+------------+------------+------------+ | Programmable fault | | | | | | | | | | | | IRQ priorities | | N | N | Y | Y | Y | N | Y | Y | Y | +---------------------------------+-----------------------------------+-----------------+---------+--------+-----------+--------+---------+------------+------------+------------+ | Single-thread kernel support | | Y | Y | Y | Y | Y | Y | Y | Y | Y | +---------------------------------+-----------------------------------+-----------------+---------+--------+-----------+--------+---------+------------+------------+------------+ | Thread local storage support | | Y | Y | Y | Y | Y | Y | Y | Y | Y | +---------------------------------+-----------------------------------+-----------------+---------+--------+-----------+--------+---------+------------+------------+------------+ | Interrupt handling | | | | +---------------------------------+-----------------------------------+-----------------+---------+--------+-----------+--------+---------+------------+------------+------------+ | | Regular interrupts | Y | Y | Y | Y | Y | Y | Y | Y | Y | +---------------------------------+-----------------------------------+-----------------+---------+--------+-----------+--------+---------+------------+------------+------------+ | | Dynamic interrupts | Y | Y | Y | Y | Y | Y | Y | Y | Y | +---------------------------------+-----------------------------------+-----------------+---------+--------+-----------+--------+---------+------------+------------+------------+ | | Direct interrupts | Y | Y | Y | Y | Y | Y | Y | Y | Y | +---------------------------------+-----------------------------------+-----------------+---------+--------+-----------+--------+---------+------------+------------+------------+ | | Zero Latency interrupts | N | N | Y | Y | Y | Y | Y | Y | Y | +---------------------------------+-----------------------------------+-----------------+---------+--------+-----------+--------+---------+------------+------------+------------+ | CPU idling | | Y | Y | Y | Y | Y | Y | Y | Y | Y | +---------------------------------+-----------------------------------+-----------------+---------+--------+-----------+--------+---------+------------+------------+------------+ | Native system timer (SysTick) | | N [#f1]_ | Y | Y | Y | Y | Y | Y | Y | Y | +---------------------------------+-----------------------------------+-----------------+---------+--------+-----------+--------+---------+------------+------------+------------+ | Memory protection | | | | +---------------------------------+-----------------------------------+-----------------+---------+--------+-----------+--------+---------+------------+------------+------------+ | | User mode | N | Y | Y | Y | Y | Y | Y | Y | Y | +---------------------------------+-----------------------------------+-----------------+---------+--------+-----------+--------+---------+------------+------------+------------+ | | HW stack protection (MPU) | N | N | Y | Y | Y | Y | Y | Y | Y | +---------------------------------+-----------------------------------+-----------------+---------+--------+-----------+--------+---------+------------+------------+------------+ | | HW-assisted stack limit checking | N | N | N | N | N |Y [#f2]_ | Y | Y | Y | +---------------------------------+-----------------------------------+-----------------+---------+--------+-----------+--------+---------+------------+------------+------------+ | | Privileged Execute Never [#f3]_ | N | N | N | N | N | N | N | Y | Y | +---------------------------------+-----------------------------------+-----------------+---------+--------+-----------+--------+---------+------------+------------+------------+ | HW-assisted Control | | | | | | | | | | | | Flow integrity | PACBTI | N | N | N | N | N | N | N | N | Y | +---------------------------------+-----------------------------------+-----------------+---------+--------+-----------+--------+---------+------------+------------+------------+ | HW-assisted null-pointer | | | | | | | | | | | | dereference detection | | N | N | Y | Y | Y | Y | Y | Y | Y | +---------------------------------+-----------------------------------+-----------------+---------+--------+-----------+--------+---------+------------+------------+------------+ | HW-assisted atomic operations | | N | N | Y | Y | Y | N | Y | Y | Y | +---------------------------------+-----------------------------------+-----------------+---------+--------+-----------+--------+---------+------------+------------+------------+ |Support for non-cacheable regions| | N | N | Y | Y | Y | N | Y | Y | Y | +---------------------------------+-----------------------------------+-----------------+---------+--------+-----------+--------+---------+------------+------------+------------+ | Execute SRAM functions | | N | N | Y | Y | Y | N | Y | Y | Y | +---------------------------------+-----------------------------------+-----------------+---------+--------+-----------+--------+---------+------------+------------+------------+ | Floating Point Services | | N | N | N | Y | Y | N | Y | Y | Y | +---------------------------------+-----------------------------------+-----------------+---------+--------+-----------+--------+---------+------------+------------+------------+ | DSP ISA | | N | N | N | Y | Y | N | Y | Y | Y | +---------------------------------+-----------------------------------+-----------------+---------+--------+-----------+--------+---------+------------+------------+------------+ | Trusted-Execution | | | +---------------------------------+-----------------------------------+-----------------+---------+--------+-----------+--------+---------+------------+------------+------------+ | | Native TrustZone-M support | N | N | N | N | N | Y | Y | Y | Y | +---------------------------------+-----------------------------------+-----------------+---------+--------+-----------+--------+---------+------------+------------+------------+ | | TF-M integration | N | N | N | N | N | N | Y | N | N | +---------------------------------+-----------------------------------+-----------------+---------+--------+-----------+--------+---------+------------+------------+------------+ | Code relocation | | Y | Y | Y | Y | Y | Y | Y | Y | Y | +---------------------------------+-----------------------------------+-----------------+---------+--------+-----------+--------+---------+------------+------------+------------+ | SW-based vector table relaying | | Y | Y | Y | Y | Y | Y | Y | Y | Y | +---------------------------------+-----------------------------------+-----------------+---------+--------+-----------+--------+---------+------------+------------+------------+ | HW-assisted timing functions | | N | N | Y | Y | Y | N | Y | Y | Y | +---------------------------------+-----------------------------------+-----------------+---------+--------+-----------+--------+---------+------------+------------+------------+
.. [#f1] SysTick is optional in Cortex-M1 .. [#f2] Stack limit checking only in Secure builds in Cortex-M23 .. [#f3] https://developer.arm.com/documentation/107655/100/RTOS-and-Secure-software-design-considerations/Secure-software-development-design-considerations/Security-and-privilege-combination/Using-PXN-bit?lang=en
OS features
Each Zephyr thread is defined with its own stack memory. By default, Cortex-M enforces a double word thread stack alignment, see
:kconfig:option:CONFIG_STACK_ALIGN_DOUBLE_WORD. If MPU-based HW-assisted stack overflow detection (:kconfig:option:CONFIG_MPU_STACK_GUARD)
is enabled, thread stacks need to be aligned with a larger value, reflected by :kconfig:option:CONFIG_ARM_MPU_REGION_MIN_ALIGN_AND_SIZE.
In Arm v6-M and Arm v7-M architecture variants, thread stacks are additionally required to align with a value equal to their size,
in applications that need to support user mode (:kconfig:option:CONFIG_USERSPACE). The thread stack sizes in that case need to be a power
of two. This is all reflected by :kconfig:option:CONFIG_MPU_REQUIRES_POWER_OF_TWO_ALIGNMENT, that is enforced in Arm v6-M and Arm v7-M
builds with user mode support.
While executing in thread mode the processor is using the Process Stack Pointer (PSP). The processor uses the Main Stack Pointer (MSP) while executing in handler mode, that is, while servicing exceptions and HW interrupts. Using PSP in thread mode facilitates thread stack pointer manipulation during thread context switching, without affecting the current execution context flow in handler mode.
In Arm Cortex-M builds a single interrupt stack memory is shared among exceptions and interrupts. The size of the interrupt stack needs
to be selected taking into consideration nested interrupts, each pushing an additional stack frame. Developers can modify the interrupt
stack size using :kconfig:option:CONFIG_ISR_STACK_SIZE.
The interrupt stack is also used during early boot so the kernel can initialize the main thread's stack before switching to the main thread.
In Arm Cortex-M builds, the PendSV exception is used in order to trigger a context switch to a different thread. PendSV exception is always present in Cortex-M implementations. PendSV is configured with the lowest possible interrupt priority level, in all Cortex-M variants. The main reasons for that design are
As a result, context switch in Cortex-M is non-atomic, i.e. it may be preempted by HW interrupts, however, a context-switch operation must be completed before a new thread context-switch may start.
Typically a thread context-switch will perform the following operations
When switching-out the current thread, the processor stores
the callee-saved registers (R4 - R11) in the thread's container for callee-saved registers, which is located in kernel memory
the thread's current operation mode
the floating point callee-saved registers (S16 - S31) in the thread's container for FP callee-saved registers, if the current thread has an active FP context
the PSP of the current thread which points to the beginning of the current thread's exception stack frame. The latter contains the caller-saved context and the return address of the switched-out thread.
When switching-in a new thread the processor
CONFIG_BUILTIN_STACK_GUARD)CONFIG_STACK_SENTINEL).PendSV exception return sequence restores the new thread's caller-saved registers and the return address, as part of unstacking the exception stack frame.
The implementation of the context-switch mechanism is present in
:file:arch/arm/core/cortex_m/swap_helper.S.
Armv8-M and Armv8.1-M variants support stack limit checking using the MSPLIM and PSPLIM
core registers. The feature is enabled when :kconfig:option:CONFIG_BUILTIN_STACK_GUARD is set.
When stack limit checking is enabled, both the thread's privileged or user stack, as well
as the interrupt stack are guarded by PSPLIM and MSPLIM registers, respectively. MSPLIM is
configured once during kernel boot, while PSLIM is re-programmed during every thread
context-switch or during system calls, when the thread switches from using its default
stack to using its privileged stack, and vice versa. PSPLIM re-programming
It is, therefore, considered as a lightweight but very efficient stack overflow detection mechanism in Cortex-M applications.
Stack overflows trigger the dedicated UsageFault exception provided by Arm v8-M.
This section describes certain aspects around exception and interrupt handling in Arm Cortex-M.
The number of available (configurable) interrupt priority levels is determined by the number of implemented interrupt priority bits in NVIC; this needs to be described for each Cortex-M platform using DeviceTree:
.. code-block:: devicetree
&nvic {
arm,num-irq-priority-bits = <#priority-bits>;
};
A number of interrupt priority levels are reserved for the OS.
By design, system fault exceptions have the highest priority level. In Baseline Cortex-M, this is actually enforced by hardware, as HardFault is the only available processor fault exception, and its priority is higher than any configurable exception priority.
In Mainline Cortex-M, the available fault exceptions (e.g. MemManageFault,
UsageFault, etc.) are assigned the highest configurable priority level.
(:kconfig:option:CONFIG_CPU_CORTEX_M_HAS_PROGRAMMABLE_FAULT_PRIOS signifies explicitly
that the Cortex-M implementation supports configurable fault priorities.)
This priority level is never shared with HW interrupts (an exception to this rule is described below). As a result, processor faults occurring in regular ISRs will be handled by the corresponding fault handler and will not escalate to a HardFault, similar to processor faults occurring in thread mode.
SVC exception is normally configured with the highest configurable priority level (an exception to this rule will be described below). SVCs are used by the Zephyr kernel to dispatch system calls, trigger runtime system errors (e.g. Kernel oops or panic), or implement IRQ offloading.
In Baseline Cortex-M the priority level of SVC may be shared with other exceptions or HW interrupts that are also given the highest configurable priority level (As a result of this, kernel runtime errors during interrupt handling will escalate to HardFault. Additional logic in the fault handling routines ensures that such runtime errors are detected successfully).
In Mainline Cortex-M, however, the SVC priority level is reserved, thus normally it is only shared with the fault exceptions of configurable priority. This simplifies the fault handling routines in Mainline Cortex-M architecture, since runtime kernel errors are serviced by the SVC handler (i.e no HardFault escalation, even if the kernel errors occur in ISR context).
HW interrupts in Mainline Cortex-M builds are allocated a priority level lower than the SVC.
One exception to the above rules is when Zephyr applications support Zero Latency Interrupts
(ZLIs). Such interrupts are designed to have a priority level higher than any HW or system
interrupt. If the ZLI feature is enabled in Mainline Cortex-M builds (see
:kconfig:option:CONFIG_ZERO_LATENCY_IRQS), then
The priority level configuration in Cortex-M is implemented in
:file:include/zephyr/arch/arm/cortex_m/exception.h.
In Baseline Cortex-M locking interrupts is implemented using the PRIMASK register.
.. code-block:: c
arch_irq_lock()
will set the PRIMASK register to 1, eventually, masking all IRQs with configurable priority. While this fulfils the OS requirement of locking interrupts, the consequence is that kernel runtime errors (triggering SVCs) will escalate to HardFault.
In Mainline Cortex-M locking interrupts is implemented using the BASEPRI register (Mainline
Cortex-M builds select :kconfig:option:CONFIG_CPU_CORTEX_M_HAS_BASEPRI to signify that BASEPRI register is
implemented.). By modifying BASEPRI (or BASEPRI_MAX) arch_irq_lock() masks all system and HW
interrupts with the exception of
This allows zero latency interrupts to be triggered inside OS critical sections. Additionally, this allows system (processor and kernel) faults to be handled by Zephyr in exactly the same way, regardless of whether IRQs have been locked or not when the error occurs. It also allows for system calls to be dispatched while IRQs are locked.
.. note::
Mainline Cortex-M fault handling is designed and configured in a way that all processor and kernel faults are handled by the corresponding exception handlers and never result in HardFault escalation. In other words, a HardFault may only occur in Zephyr applications that have modified the default fault handling configurations. The main reason for this design was to reserve the HardFault exception for handling exceptional error conditions in safety critical applications.
Cortex-M builds support the installation of direct interrupt service routines during runtime. Direct interrupts are designed for performance-critical interrupt handling and do not go through all of the common Zephyr interrupt handling code.
Direct dynamic interrupts are enabled via switching on
:kconfig:option:CONFIG_DYNAMIC_DIRECT_INTERRUPTS.
Note that enabling direct dynamic interrupts requires enabling support for
dynamic interrupts in the kernel, as well (see :kconfig:option:CONFIG_DYNAMIC_INTERRUPTS).
As described above, in Mainline Cortex-M applications, the Zephyr kernel reserves
the highest configurable interrupt priority level for its own use (SVC). SVCs will
not be masked by interrupt locking. Zero-latency interrupt can be used to set up
an interrupt at the highest interrupt priority which will not be blocked by interrupt
locking. To use the ZLI feature :kconfig:option:CONFIG_ZERO_LATENCY_IRQS needs to be enabled.
Zero latency IRQs have minimal interrupt latency, as they will always preempt regular HW or system interrupts.
Note, however, that since ZLI ISRs will run at a priority level higher than the kernel exceptions they cannot use any kernel functionality. Additionally, since the ZLI interrupt priority level is equal to processor fault priority level, faults occurring in ZLI ISRs will escalate to HardFault and will not be handled in the same way as regular processor faults. Developers need to be aware of this limitation.
The Cortex-M architecture port implements both k_cpu_idle()
and k_cpu_atomic_idle(). The implementation is present in
:file:arch/arm/core/cortex_m/cpu_idle.c.
In both implementations, the processor will attempt to put the core to low power mode. In k_cpu_idle() the processor ends up executing WFI (Wait For Interrupt) instruction, while in k_cpu_atomic_idle() the processor will execute a WFE (Wait For Event) instruction.
When using the CPU idling API in Cortex-M it is important to note the following:
The Zephyr CPU Idling mechanism is detailed in :ref:cpu_idle.
This section describes certain aspects around memory protection features in Arm Cortex-M applications.
User mode is supported in Cortex-M platforms that implement the standard (Arm) MPU
or a similar core peripheral logic for memory access policy configuration and
control, such as the NXP MPU for Kinetis platforms. (Currently,
:kconfig:option:CONFIG_ARCH_HAS_USERSPACE is selected if :kconfig:option:CONFIG_ARM_MPU is enabled
by the user in the board default Kconfig settings).
A thread performs a system call by triggering a (synchronous) SVC exception, where
The SVC Handler will branch to the system call preparation logic, which will perform the following operations
Once the system call execution is completed the system call dispatcher will restore the user's original PSP and PSPLIM and switch the CONTROL register back to unprivileged mode before returning back to the caller of the system call.
System calls execute in thread mode and can be preempted by interrupts at any time. A thread may also be context-switched-out while doing a system call; the system call will resume as soon as the thread is switched-in again.
The system call dispatcher executes at SVC priority, therefore it cannot be preempted by HW interrupts (with the exception of ZLIs), which may observe some additional interrupt latency if they occur during a system call preparation.
Cortex-M platforms with MPU may enable :kconfig:option:CONFIG_MPU_STACK_GUARD to enable the MPU-based
stack overflow detection mechanism. The following points need to be considered when enabling the
MPU stack guards
CONFIG_MPU_STACK_GUARD being set.CONFIG_MPU_STACK_GUARD will normally reserve one MPU region for programming
the stack guard (in certain Arm v8-M configurations with :kconfig:option:CONFIG_MPU_GAP_FILLING
enabled 2 MPU regions are required to implement the guard feature)CONFIG_BUILTIN_STACK_GUARD feature,
no re-programming occurs during system calls.CONFIG_HW_STACK_PROTECTION is enabled on Arm v8-M platforms the native
stack limit checking mechanism is used by default instead of the MPU-based stack overflow
detection mechanism; users may override this setting by manually enabling :kconfig:option:CONFIG_MPU_STACK_GUARD
in these scenarios.The Armv8.1-M Pointer Authentication and Branch Target Identification (PACBTI) extension is an optional extension for the Armv8.1-M architecture profile and consists of the implementation of the following control-flow integrity approaches:
When hardware support is present (e.g., Cortex-M85) and compiler support is available, PACBTI can be enabled at build time in Zephyr by selecting one of the below configs:
CONFIG_ARM_PACBTI_STANDARDCONFIG_ARM_PACBTI_PACRETCONFIG_ARM_PACBTI_PACRET_LEAFCONFIG_ARM_PACBTI_BTICONFIG_ARM_PACBTI_PACRET_BTICONFIG_ARM_PACBTI_PACRET_LEAF_BTICONFIG_ARM_PACBTI_NONEThe config options ensures that compiler flags enabling PACBTI instructions are added to the build, specifically:
-mbranch-protection= for GCC toolchains.Further, :kconfig:option:CONFIG_ARM_PAC and :kconfig:option:CONFIG_ARM_BTI are
automatically selected based on the branch protection option chosen for
:kconfig:option:CONFIG_ARM_PACBTI. These configuration options enforce PACBTI by enabling
corresponding PACBTI bits in CONTROL register and in the FVP.
To further enhance pointer authentication, Zephyr supports using cryptographically secure,
per-thread PAC keys by enabling :kconfig:option:CONFIG_ARM_PAC_PER_THREAD.
For more details on key generation sources and configuration, refer to the Kconfig help for
:kconfig:option:CONFIG_ARM_PAC_PER_THREAD.
Limitations:
this document <https://docs.zephyrproject.org/latest/develop/toolchains/index.html>_ on how to set up
toolchains.For more information about PACBTI, refer to the official Arm documentation <https://developer.arm.com/documentation/109576/latest/>_
and also Arm community blog <https://community.arm.com/arm-community-blogs/b/architectures-and-processors-blog/posts/armv8-1-m-pointer-authentication-and-branch-target-identification-extension>_
.. _arm_cortex_m_mpu_considerations:
By default, when :kconfig:option:CONFIG_ARM_MPU is enabled a set of fixed MPU regions
are programmed during system boot.
CONFIG_MPU_ALLOW_FLASH_WRITE,
which programs the flash with RWX permissions. If :kconfig:option:CONFIG_USERSPACE is
enabled unprivileged access on the entire flash area is allowed.CONFIG_MPU_GAP_FILLING is disabled (Arm v8-M only);
in that case no SRAM MPU programming is done so the access is determined by the default
Arm memory map policies, allowing for privileged-only RWX permissions on SRAM).zephyr,memory-attr defining the MPU permissions for the memory region.
See the next section for more details.The above MPU regions are defined in :file:arch/arm/core/mpu/arm_mpu_regions.c.
Alternative MPU configurations are allowed by enabling :kconfig:option:CONFIG_CPU_HAS_CUSTOM_FIXED_SOC_MPU_REGIONS.
When enabled, this option signifies that the Cortex-M SoC will define and
configure its own fixed MPU regions in the SoC definition.
When the property zephyr,memory-attr is present in a memory node, a new MPU
region will be allocated and programmed during system boot. When used with the
:dtcompatible:zephyr,memory-region devicetree compatible, it will result in a
linker section being generated associated to that MPU region.
For example, to define a new non-cacheable memory region in devicetree:
.. code-block:: devicetree
sram_no_cache: memory@20300000 { compatible = "zephyr,memory-region", "mmio-sram"; reg = <0x20300000 0x100000>; zephyr,memory-region = "SRAM_NO_CACHE"; zephyr,memory-attr = <DT_MEM_ARM_MPU_RAM_NOCACHE>; };
This will automatically create a new MPU entry in with the correct name, base,
size and attributes gathered directly from the devicetree. See :ref:cache_guide
and :ref:mem_mgmt_api for more details.
Additional static MPU regions may be programmed once during system boot. These regions
are required to enable certain features. See :ref:cache_guide for more details.
CONFIG_ARCH_HAS_RAMFUNC_SUPPORT is
enabled and users have defined functions to execute from SRAM.CONFIG_CODE_DATA_RELOCATION_SRAM is enablednocache region to allow for a non-cacheable SRAM area, when :kconfig:option:CONFIG_NOCACHE_MEMORY is enabledCONFIG_COVERAGE_GCOV is enabledCONFIG_NULL_POINTER_EXCEPTION_DETECTION_MPU is enabledThe boundaries of these static MPU regions are derived from symbols exposed by the linker, in
:file:include/linker/linker-defs.h.
Certain thread-specific MPU regions may be re-programmed dynamically, at each thread context switch:
The number of available MPU regions for a Cortex-M platform is a limited resource. Most platforms have 8 MPU regions, while some Cortex-M33 or Cortex-M7 platforms may have up to 16 MPU regions. Therefore there is a relatively strict limitation on how many fixed, static and dynamic MPU regions may be programmed simultaneously. For platforms with 8 available MPU regions it might not be possible to enable all the aforementioned features that require MPU region programming. In most practical applications, however, only a certain set of features is required and 8 MPU regions are, in many cases, sufficient.
In Arm v8-M processors the MPU architecture does not allow programmed MPU regions to
overlap. :kconfig:option:CONFIG_MPU_GAP_FILLING controls whether the fixed MPU region
covering the entire SRAM is programmed. When it does, a full SRAM area partitioning
is required, in order to program the static and the dynamic MPU regions. This increases
the total number of required MPU regions. When :kconfig:option:CONFIG_MPU_GAP_FILLING is not
enabled the fixed MPU region covering the entire SRAM is not programmed, thus, the static
and dynamic regions are simply programmed on top of the always-existing background region
(full-SRAM partitioning is not required).
Note, however, that the background SRAM region allows execution from SRAM, so when
:kconfig:option:CONFIG_MPU_GAP_FILLING is not set Zephyr is not protected against attacks
that attempt to execute malicious code from SRAM.
Both unshared and shared FP registers mode are supported in Cortex-M (see
:ref:float_v2 for more details).
When FPU support is enabled in the build
(:kconfig:option:CONFIG_FPU is enabled), the
sharing FP registers mode (:kconfig:option:CONFIG_FPU_SHARING)
is enabled by default. This is done as some compiler configurations
may activate a floating point context by generating FP instructions
for any thread, regardless of whether floating point calculations are
performed, and that context must be preserved when switching such
threads in and out.
The developers can still disable the FP sharing mode in their application projects, and switch to Unshared FP registers mode, if it is guaranteed that the image code does not generate FP instructions outside the single thread context that is allowed (and supposed) to do so.
Under FPU sharing mode, the callee-saved FPU registers are saved and restored in context-switch, if the corresponding threads have an active FP context. This adds some runtime overhead on the swap routine. In addition to the runtime overhead, the sharing FPU mode
Misc
Cortex-M applications may either be standalone images or chain-loadable, for instance,
by a bootloader. Application images chain-loadable by bootloaders (or other applications)
normally occupy a specific area in the flash denoted as their code partition.
:kconfig:option:CONFIG_USE_DT_CODE_PARTITION will ensure that a Zephyr chain-loadable image
will be linked into its code partition, specified in DeviceTree.
In order to boot properly, chain-loaded applications may require that the core Arm
hardware registers and peripherals are initialized in their reset values. Enabling
:kconfig:option:CONFIG_INIT_ARCH_HW_AT_BOOT Zephyr to force the initialization of the
internal Cortex-M architectural state during boot to the reset values as specified
by the corresponding Arm architecture manual.
In Cortex-M platforms that implement the VTOR register (see :kconfig:option:CONFIG_CPU_CORTEX_M_HAS_VTOR),
chain-loadable images relocate the Cortex-M vector table by updating the VTOR register with the offset
of the image vector table.
Baseline Cortex-M platforms without VTOR register might not be able to relocate their vector table which remains at a fixed location. Therefore, a chain-loadable image will require an alternative way to route HW interrupts and system exceptions to its own vector table; this is achieved with software vector relaying.
When a bootloader image enables :kconfig:option:CONFIG_SW_VECTOR_RELAY
it is able to relay exceptions and interrupts based on a vector table
pointer that is set by the chain-loadable application. The latter sets
the :kconfig:option:CONFIG_SW_VECTOR_RELAY_CLIENT option to instruct the boot
sequence to set the vector table pointer in SRAM so that the bootloader can
forward the exceptions and interrupts to the chain-loadable image's software
vector table.
While this feature is intended for processors without VTOR register, it may also be used in Mainline Cortex-M platforms.
Cortex-M support the code relocation feature. When
:kconfig:option:CONFIG_CODE_DATA_RELOCATION_SRAM is selected,
Zephyr will relocate .text, data and .bss sections
from the specified files and place it in SRAM. It is
possible to relocate only parts of the code sections
into SRAM, without relocating the whole image text
and data sections. More details on the code relocation
feature can be found in :ref:code_data_relocation.
Linking Cortex-M applications
Most Cortex-M platforms make use of the default Cortex-M
GCC linker script in :file:include/zephyr/arch/arm/cortex_m/scripts/linker.ld,
although it is possible for platforms to use a custom linker
script as well.
CMSIS
Cortex-M CMSIS headers are provided through standalone module repositories:
zephyrproject-rtos/cmsis <https://github.com/zephyrproject-rtos/cmsis>_zephyrproject-rtos/CMSIS_6 <https://github.com/zephyrproject-rtos/CMSIS_6>_Zephyr has begun transitioning to CMSIS 6 as the default source for Cortex-M core headers. However, at present, Zephyr includes headers from both the CMSIS 6 and legacy CMSIS 5 modules.
The legacy CMSIS 5 headers remain available primarily for compatibility with vendor HALs, while all new architecture-level development should use CMSIS 6 headers whenever possible.
:kconfig:option:CONFIG_CPU_CORTEX_M selects :kconfig:option:CONFIG_HAS_CMSIS_CORE to signify that
CMSIS headers are available for all supported Cortex-M variants.
Testing
A list of unit tests for the Cortex-M porting and miscellaneous features
is present in :file:tests/arch/arm/. The tests suites are continuously
extended and new test suites are added, in an effort to increase the coverage
of the Cortex-M architecture support in Zephyr.
QEMU
We use QEMU to verify the implemented features of the Cortex-M architecture port in Zephyr. Adequate coverage is achieved by defining and utilizing a list of QEMU targets, each with a specific architecture variant and Arm peripheral support list.
The table below lists the QEMU platform targets defined in Zephyr along with the corresponding Cortex-M implementation variant and the peripherals these targets emulate.
+---------------------------------+--------------------+--------------------+----------------+----------------------+----------------------------+ | | QEMU target | +---------------------------------+--------------------+--------------------+----------------+----------------------+----------------------------+ | Architecture variant | Arm v6-M | Arm v7-M | Arm v8-M | Arm v8.1-M | +---------------------------------+--------------------+--------------------+----------------+----------------------+----------------------------+ | | qemu_cortex_m0 | qemu_cortex_m3 | mps2/an385 | mps2/an521/cpu0 | mps3/corstone300/an547 | +---------------------------------+--------------------+--------------------+----------------+----------------------+----------------------------+ | Emulated features | | +---------------------------------+--------------------+--------------------+----------------+----------------------+----------------------------+ | NVIC | Y | Y | Y | Y | Y | +---------------------------------+--------------------+--------------------+----------------+----------------------+----------------------------+ | BASEPRI | N | Y | Y | Y | Y | +---------------------------------+--------------------+--------------------+----------------+----------------------+----------------------------+ | SysTick | N | Y | Y | Y | Y | +---------------------------------+--------------------+--------------------+----------------+----------------------+----------------------------+ | MPU | N | N | Y | Y | Y | +---------------------------------+--------------------+--------------------+----------------+----------------------+----------------------------+ | FPU | N | N | N | Y | N | +---------------------------------+--------------------+--------------------+----------------+----------------------+----------------------------+ | SPLIM | N | N | N | Y | Y | +---------------------------------+--------------------+--------------------+----------------+----------------------+----------------------------+ | TrustZone-M | N | N | N | Y | N | +---------------------------------+--------------------+--------------------+----------------+----------------------+----------------------------+
Maintainers & Collaborators
The status of the Arm Cortex-M architecture port in Zephyr is: maintained.
The updated list of maintainers and collaborators for Cortex-M can be found
in :file:MAINTAINERS.yml.