Unlocking the Power of ARM: Operating States, Modes and Access Levels

Unlocking the Power of ARM: Operating States, Modes and Access Levels

Published on 15/09/2024

Written by: Malek Boubahri and Khaled Dhif

Introduction

Welcome to the next installment in our series on ARM Cortex processors. In our previous articles, we explored the history of ARM, discussed fundamental concepts and components, and delved into the Instrumentation Trace Macrocell (ITM) while experimenting with printf for debugging. These foundational topics have set the stage for a deeper understanding of ARM Cortex-M processors.

In this article, we will focus on the operating modes, states, and access levels of ARM Cortex-M processors. These elements are crucial for optimizing system performance and ensuring proper operation within embedded applications. We’ll examine how these modes and states interact with the processor’s registers, with a particular emphasis on the Control register, which manages access levels and operational configurations.

By the end of this article, you will have a thorough understanding of how to configure and leverage these features to enhance your embedded systems' functionality and security.

The Armv7-M architecture is designed with two distinct operating states and two operating modes. In addition to these, the architecture incorporates two access levels: privileged and unprivileged. The privileged access level grants unrestricted access to all system resources, while the unprivileged level limits access to certain memory regions and restricts the use of specific operations. Understanding how these states, modes, and access levels work together is crucial for effectively managing system security and performance.


Operating States

The ARMv7-M architecture defines two primary operating states that the processor can operate in: Thumb state and Debug state. Each state serves a specific purpose and determines how the processor handles instructions and debugging events.

  1. Thumb State: The processor is in Thumb state when it is actively executing program code. ARMv7-M-based processors use the Thumb instruction set, which is a compact, efficient set of 16-bit and 32-bit instructions designed to optimize performance and memory usage in embedded systems. Unlike earlier ARM architectures that supported both the Arm (A32) and Thumb instruction sets, ARMv7-M only supports Thumb instructions, simplifying the instruction flow and ensuring high efficiency. Whenever the processor runs user code, it remains in the Thumb state.
  2. Debug State The processor enters Debug state when it halts program execution, typically due to external intervention like a debugger or the activation of a breakpoint. In this state, the processor stops executing instructions, allowing developers to inspect and control the system. Debug state is critical for system debugging and development, as it provides the ability to monitor program behavior, examine memory, and modify register values without affecting the rest of the system.

Note:

It's important to recognize that when the processor is stopped by a debugger, other parts of the system, such as peripherals and Direct Memory Access (DMA), continue to run. Many users expect that stopping code execution completely halts the entire microcontroller, but that is not the case. While the processor stops processing instructions, the rest of the system—such as clocks, memory systems, and peripherals—continues to function. For instance, peripherals may keep sending data, and DMA operations may continue transferring data in the background. This can result in changes to memory or peripheral registers while stepping through code or refreshing the debugger display, which can be surprising if one assumes the entire chip has stopped. This behavior reflects the System-on-Chip (SoC) nature of ARM Cortex-M processors, where different subsystems operate independently of the processor’s state.



ARM Coretx-M Operating States and Modes

These two states are fundamental to the ARM Cortex-M operation, enabling efficient code execution in Thumb state and robust debugging capabilities in Debug state, while maintaining peripheral activity during debugging.


Privileged and Unprivileged Execution

The ARM Cortex-M architecture supports two distinct access levels: privileged and unprivileged, which determine the extent of a program’s control over system resources.

  1. Privileged Execution In privileged execution, software has full access to all system instructions, resources, and hardware components. Privileged software can perform critical operations, such as configuring the system’s control registers, accessing protected memory regions, and interacting with the System Timer (SysTick), Nested Vectored Interrupt Controller (NVIC), and System Control Block (SCB). This level of access is typically reserved for the operating system kernel or other trusted system components. One key feature of privileged execution is the ability to write to the CONTROL register, which allows switching from privileged to unprivileged mode in Thread mode. This provides a mechanism for the system to reduce the permissions of certain tasks after they have been initialized or when executing user-level code.
  2. Unprivileged Execution In unprivileged execution, software has limited access to system resources and is restricted from performing certain critical operations. Programs running at this level cannot access privileged memory regions, nor can they control the system’s key hardware components, such as the NVIC or System Timer. This restriction prevents untrusted or less critical code from interfering with core system functions. Importantly, unprivileged software cannot elevate itself back to privileged mode. The only way to transition from unprivileged to privileged execution is through an exception that causes the processor to switch to Handler mode, where it operates with elevated privileges. Additionally, an unprivileged task can request a transition back to privileged mode by issuing a Supervisor Call (SVC). The SVC handler, running in Handler mode with elevated privileges, can execute the necessary operations to grant the requesting task privileged access if permitted by the system design. This mechanism ensures that only trusted, system-level tasks can regain privileged status.
  3. System Design and Access Levels The separation of privileged and unprivileged execution allows system designers to assign different permissions to different parts of the software. For example, the operating system kernel and device drivers typically operate in privileged mode, while user applications run in unprivileged mode. This separation enhances security and system stability, as user-level tasks are prevented from inadvertently or maliciously modifying critical system resources. Attempting to access privileged resources or execute privileged instructions from unprivileged code may trigger a system exception (Memory management Fault, Usage Fault, Page Fault, etc) based on the type of violation. Despite these restrictions, the programmer’s model for both access levels is mostly the same. Apart from differences in memory access permissions and certain privileged instructions, the way software interacts with the processor remains consistent across both levels. This allows developers to write code that can easily switch between access levels without significant changes, while still benefiting from the security provided by the access separation.



Access Levels of an ARM Cortex-based system

Note: A page fault specifically occurs when the system’s memory management unit (MMU) cannot map a requested memory address to physical memory. This is usually the case with more complex processors like the ARM Cortex-A that implement this unit.

Operating Modes: Thread Mode and Handler Mode

ARM Cortex-M processors operate in one of two modes: Thread mode and Handler mode, which correspond to different levels of control and execution contexts.

  1. Thread Mode Thread mode is the default mode in which application code runs. Upon reset, the processor enters Thread mode in privileged access level and Thumb state, which means it has unrestricted access to system resources. The access level can later be changed to unprivileged using the CONTROL register, allowing the system to limit access to certain memory regions and operations to enhance security. In unprivileged Thread mode, application code can perform user-level tasks but is restricted from accessing critical system resources directly. Thread mode is conceptually similar to user mode in Unix-like operating systems. Just as user programs in Unix run with limited privileges to prevent unintended system-wide changes, the Cortex-M’s Thread mode restricts access to critical system functions when operating in unprivileged mode. Furthermore, in Thread mode, the processor has the option to use a separate Process Stack Pointer (PSP), in addition to the Main Stack Pointer (MSP). This allows for more flexible stack management, particularly when switching between different access levels or contexts.
  2. Handler Mode Handler mode is activated whenever the processor handles an exception, such as an interrupt or a fault. In this mode, the processor always operates at the privileged access level, granting it full access to all system resources needed to properly handle exceptions and perform system-level tasks. Handler mode is analogous to kernel mode in Unix-like systems, where the operating system core has full control over the hardware and can manage system-critical operations. In ARM Cortex-M, all exceptions cause a switch to Handler mode, allowing exception handling routines—such as Interrupt Service Routines (ISRs)—to run with elevated privileges. On completion of the exception, the processor returns to Thread mode. Additionally, the ARM Cortex-M processor’s dual-stack architecture allows the processor to switch between the Main Stack Pointer (MSP) and Process Stack Pointer (PSP). The MSP is typically used in Handler mode, while the PSP is used in Thread mode, facilitating Unix-like task separation and control. This distinction enhances the processor’s ability to manage different execution contexts efficiently, providing a flexible framework for handling both user-level tasks and critical system-level events.


ARM Cortex M Operating Modes and Access Levels


Inline Assembly and Compiler Support

Several modern compilers support the use of inline assembly, allowing developers to embed low-level assembly instructions directly into high-level C or C++ code. This feature is especially useful for hardware-specific operations or optimizing critical sections of code. Common compilers that support inline assembly include:

- GCC (GNU Compiler Collection): Supports the GNU inline assembly syntax, widely used for ARM processors.

- ARM Compiler: Also supports GNU-style inline assembly, offering flexibility for developers targeting ARM architectures.

- Clang/LLVM: Provides compatibility with GCC-style inline assembly.

IDEs Supporting Inline Assembly for ARM Cortex-based MCUs:

For ARM Cortex-M based MCUs, several Integrated Development Environments (IDEs) provide support for inline assembly in C/C++ projects, such as:

- Keil MDK (Microcontroller Development Kit): A popular IDE for ARM Cortex-M development, featuring a built-in compiler that supports inline assembly.

- STM32CubeIDE: Developed by STMicroelectronics, it combines the power of Eclipse and GCC for developing STM32-based applications, supporting inline assembly.

- IAR Embedded Workbench: Another widely-used IDE for ARM Cortex development, with support for inline assembly and advanced debugging tools.

- Atollic TrueSTUDIO: Now part of STM32CubeIDE, this IDE also supports inline assembly through the GNU ARM toolchain.

These IDEs offer debugging features, project management, and code completion tools, making them excellent platforms for developers working on ARM Cortex-M microcontrollers.


Core Registers and Access Levels

ARM Cortex-M processors have a well-defined set of core registers that include general-purpose registers, special-purpose registers, and status registers. These registers are crucial for controlling the behavior of the processor, accessing memory, and managing execution states. Unlike memory-mapped peripherals, these core registers are not memory-mapped and thus cannot be accessed using traditional pointer-based methods. Instead, they must be accessed through assembly code instructions or specific compiler intrinsics designed for manipulating these registers directly.

General-Purpose Registers

The Cortex-M processor features R0 through R12 as general-purpose registers, which are primarily used for holding variables and intermediate values during execution. These registers can be accessed directly by both C/C++ code and inline assembly.

Special-Purpose Registers

In addition to general-purpose registers, there are several special-purpose registers critical for controlling the processor's state and behavior:

- Program Counter (PC): Holds the address of the next instruction to be executed.

- Stack Pointer (SP): Two stack pointers exist — the Main Stack Pointer (MSP) and the Process Stack Pointer (PSP), used in different execution modes.

- Link Register (LR): Holds the return address when a function call is made.

- Program Status Register (PSR): Holds the current state of the processor, including condition flags (e.g., zero, negative).

Among these, the CONTROL register is of particular interest when dealing with access levels in ARM Cortex-M processors.

ARM Cortex M-7 Core registers

The CONTROL Register

The CONTROL register is a special-purpose register that defines whether the processor is operating in privileged or unprivileged mode. It also controls which stack pointer (MSP or PSP) is used in Thread mode.

- CONTROL[0]: Defines the current privileged or unprivileged state.

??- 0: Privileged access level.

??- 1: Unprivileged access level.

- CONTROL[1]: Selects the stack pointer.

??- 0: Uses the Main Stack Pointer (MSP).

??- 1: Uses the Process Stack Pointer (PSP).

On reset, the processor starts in privileged Thread mode with the MSP stack pointer by default. To switch between privileged and unprivileged modes, software can modify the CONTROL register using inline assembly, since this register is not memory-mapped and cannot be accessed directly by normal C code.


Conclusion

In this article, we examined the operating modes and access levels of ARM Cortex-M processors. We covered the Thumb and Debug states, the significance of privileged and unprivileged execution, and the role of the CONTROL register in managing access levels. Understanding these elements is crucial for optimizing system performance and security in embedded applications.

Stay tuned for our hands-on video tutorial, where we'll demonstrate how to configure these settings on an ARM Cortex-M based MCU, offering a practical look at applying these concepts in real-world scenarios.


要查看或添加评论,请登录

社区洞察

其他会员也浏览了