The Cortex-M3 processor from ARM offers several features for memory protection and isolation to help developers build more robust and secure embedded systems. This includes features like memory protection units (MPUs), privileged execution levels, and domain access control that allow separating trusted and untrusted code and data in memory.
Cortex-M3 Memory Architecture Overview
The Cortex-M3 is based on the ARMv7-M architecture and has a Von Neumann memory model meaning it does not separate instruction and data memory. The processor has a unified memory map and uses a single set of load/store instructions to access both code and data. The memory map consists of up to 4 gigabytes of memory divided into different regions.
The main regions in the Cortex-M3 memory map are:
- Code region for program code and constants
- SRAM region for data variables
- Peripheral region for registers of on-chip peripherals
- System region for system control registers including MPU and debug
The processor accesses memory via the AHB-Lite bus interface which connects to external memories and peripherals. This bus provides a 32-bit data bus and up to 32-bit memory addresses.
Memory Protection Unit (MPU)
The Cortex-M3 includes an optional Memory Protection Unit (MPU) to enforce access permissions in memory. The MPU allows configuring access permissions for up to 8 regions of memory defined by a start address, end address, and access permissions.
Each MPU region can be configured as:
- No access
The MPU checks every memory access against the configured regions and generates a fault if an access violates the permissions. This allows protecting memory areas from accidental writes or execution. For example, code memory can be made read-only to prevent corruption. The MPU also improves system robustness by detecting invalid memory accesses that could crash the system.
MPU Region Priority
The 8 MPU regions are checked in a fixed priority order from 7 (highest) to 0 (lowest). The highest priority region matching the access address is used to determine the access permissions. This allows higher priority regions to override lower priority ones.
Overlapping regions are also supported. In that case, the region with the highest priority in the overlap range will determine the access permissions. This provides flexibility to combine regions for complex memory maps.
The Cortex-M3 MPU has some limitations developers should be aware of:
- Only 8 regions are supported which may not cover complex memory maps
- Regions can only use power-of-two sizes between 32 bytes and 4GB
- No support for executing code from RAM
- Not designed to protect against malicious security attacks
Due to these limitations, the MPU is best suited to creating a coarse memory map for separating trusted embedded code from untrusted contents like external data. Additional mechanisms like domain access control can complement the MPU for finer-grained security.
Privileged Execution Levels
The Cortex-M3 provides two privilege levels to separate trusted system code from less trusted application code:
- Privilege level 0 – Thread mode used by applications
- Privilege level 1 – Handler mode used by OS/system code
Threads always execute at privilege level 0. Exception handlers triggered by interrupts or faults will execute at privilege level 1. This allows system code to access protected system resources like the MPU configuration while limiting application code access.
Some key capabilities at privilege level 1 include:
- Access system memory map region with control registers
- Configure and control MPU regions
- Set up stack pointer for privilege level 0 threads
- Return to privilege level 0 using special instructions
Hardware faults are generated if privilege level 0 code attempts to access these protected system resources. This prevents application tampering with the system configuration.
Processor Mode Control
The processor mode is controlled using the IPSR and CONTROL registers:
- IPSR – Holds exception number of current Privilege Level 1 handler
- CONTROL – CONFIG bit controls thread (0) vs handler (1) mode
These registers are used by exception entry/exit sequences to switch between privilege levels.
Unaligned Access Faults
Another use of the privilege levels is to enforce aligned memory accesses. The Cortex-M3 generates a fault on unaligned loads and stores by default. This improves performance by avoiding multi-cycle unaligned accesses.
However, privilege level 1 handlers have the ability to enable unaligned access permissions to supportLegacy software that expects unaligned access support. Thus, aligned access is enforced on untrusted application code while system code can still perform unaligned accesses.
Domain Access Control
Domain access control provides a finer-grained mechanism to partition memory for security critical applications. It works by splitting memory into up to 16 domains and assigning each bus master to a domain.
Each domain can be configured with individual access permissions to each memory region. This allows granting bus masters access only to the memory regions required for their operation and preventing access to all other regions.
Domain access control provides whitelisting of allowed memory regions for each bus master. Some examples of how it could be used:
- Isolate core CPU into its own domain
- Isolate security critical peripherals into separate domains
- Allow read-only access to code region for DMA controllers
This provides strong spatial and temporal separation between software components in the system that need to be isolated. Domain access control scales better than the MPU when fine-grained isolation is needed.
To use domain access control, the system must:
- Assign each bus master in the system to a domain
- Configure domain access permission rules for each memory region
This is typically done in privilege level 1 system initialization code to prevent tampering by applications.
Domain access control has some limitations to consider:
- Software overhead to manage domains and access rules
- Must be configured for the memory map of the specific system
- Only controls external memory accesses, not internal CPU accesses
So it should be used selectively for security critical software components and not applied broadly across the entire system.
Cortex-M3 Memory Map
Let’s look at how the Cortex-M3 memory regions can be mapped using the memory protection features:
Some key points about this memory map:
- Code region is read-only to prevent corruption
- SRAM region split into secure and non-secure areas
- Peripheral registers protected using domain access control
- System region access controlled by privilege level
This demonstrates how the Cortex-M3 capabilities allow building a robust memory map tailored for an embedded application.
Some example use cases where the Cortex-M3 memory protection features are useful:
Isolating Functional Software Components
Use domain access control to isolate components like a Real Time Operating System (RTOS) into their own domains. This prevents interference between components for more robust operation.
Protecting Critical System Resources
Use the MPU or domain access control to make registers for security peripherals like encryption engines read-only or accessible only to trusted software components.
Securing Embedded Firmware Updates
Configure code memory as read-only while firmware updates are applied. This prevents partially updated code from executing incorrectly.
Limiting Access to Sensitive Data
Configure MPU or domains to allow only trusted portions of software to access regions containing sensitive data like encryption keys or user data.
In summary, the Cortex-M3 provides several useful features to help developers implement robust embedded systems:
- MPU allows simple region based memory access control
- Privilege levels separate trusted system and untrusted application code
- Domain access control enables fine-grained partitioning for security
- Configurable memory map tailored for application requirements
Used appropriately, these features can isolate software components, establish secure data access policies, and generally improve system reliability against bugs or errors. The end result is more secure and robust embedded software on the Cortex-M3 processor.