# Arm `rt` supports the following variants of the 32-bit Arm architecture: - `armv6-m` - `armv7-m` - `armv8-m.main` - `armv8-m.base` - `armv7-r` - `armv7-a` ## Cortex-M On Cortex-M devices, the `rt_svcall_handler` function should be configured as the handler for the SVCall exception, and `rt_pendsv_handler` should be configured as the handler for the PendSV exception. Both of these exceptions should be configured with the lowest exception priority (i.e., the largest numerical value) so they cannot preempt each other or other interrupts. The `rt_tick_advance` function should be configured as the handler for the SysTick exception, and have a priority greater than or equal to PendSV and SVCall (a lesser or equal numerical value). If desired, a different timer can be used for the tick, but it's likely a custom handler that calls `rt_tick_advance` is needed in this case if the interrupt is not automatically cleared like SysTick. Tasks use the process stack pointer (`psp`), and on `armv8-m` the `psplim` register is used to protect against stack exhaustion. Tasks run with the nPRIV bit of the control register cleared (i.e., tasks are privileged by default). Support for unprivileged tasks is limited to the MPU-enabled configuration and architecture version 7 or greater. Some Armv6-M processors have an MPU, but they don't support atomic instructions. Atomics are instead emulated with interrupt masking, which in turn requires privileged execution. Dropping privilege in this configuration would then prevent using essentially all of `rt`, and so privilege is always on in Armv6-M. For MPU-disabled configurations, there is very little additional benefit to using privilege levels, and there is higher overhead for context switch as the control register must be included in the task context, and so nPRIV is always 0 when the MPU is off on M-profile targets. In supported configurations (MPU on and Armv{7,8}-M), a task can set its nPRIV bit by calling `rt_task_drop_privilege`. ## Cortex-A/R Cortex-A and Cortex-R devices can have a variety of different interrupt controllers and different ways of triggering a software interrupt for deferred system call handling. Therefore, different devices require different code for these purposes. Implementations of the interrupt management and software interrupt code for different devices are provided in subdirectories of `arch/arm/ar`. To build `rt` with support for one of these, add the directory to the preprocessor include path when compiling. The `rt_svc_handler` function should be used as the handler for the SVC exception and the `rt_syscall_irq_handler` function should be used as the handler for the syscall IRQ when hardware-vectored IRQs are enabled. Lastly, the tick timer interrupt will need to call `rt_tick_advance`, as `rt_tick_advance` is not usable directly as an interrupt handler as it is on Cortex-M. If IRQ nesting is implemented, then the tick timer interrupt handler must mask the syscall IRQ, either explicitly or through a priority mechanism provided by the interrupt controller. Tasks start in system mode and can call `rt_task_drop_privilege` to switch to user mode. Privilege is part of the CPSR register in A/R-profile, so there's no additional overhead to tracking it like there is in M-profile, and all A/R-profile architectures support atomic instructions. Because there are no downsides, running unprivileged tasks is always supported in A/R-profile targets in `rt`. If an interrupt handler supports nesting, it should execute in supervisor mode. On A/R-profile targets with floating-point support, the floating-point unit is disabled by default for each task, using the FPEXC special-purpose register, which is saved and restored as part of each task's context. If a task is not using the floating-point unit, its floating-point state will not be saved and restored, reducing the time and stack space required to context switch. When each task first executes a floating-point instruction, it will take an undefined instruction exception, which can be caught and handled in order to enable the floating-point unit, initialize the floating-point context for that task, and re-execute the instruction. See the rt-hercules and rt-sitara projects for example handlers. Alternately, a task can directly enable floating-point by setting the appropriate bit in FPEXC while in system mode, but care must be taken to avoid inadvertently manipulating any FPU state before this has occurred, which may not be possible in general with sufficiently advanced compiler optimizations. The undefined instruction exception method is recommended, and is described in the _Arm Architecture Reference Manual_ section B1.11.3: _Context switching with the Advanced SIMD and Floating-point Extensions_. ## Memory Protection The memory protection unit available in many Cortex-M and Cortex-R devices is supported and can be used with the interface provided in [``](include/rt/arch/mpu.h). By default, `rt` assumes the MPU has 8 regions, but this can be overridden with `-DRT_MPU_NUM_REGIONS=` for processors with more. To enable per-task MPU regions, compile with `-DRT_MPU_TASK_REGIONS_ENABLE=1`. By default, `rt` reserves the 4 highest-priority regions to be reconfigured for every task, with one of those regions reserved for the task's stack that is automatically initialized along with the task itself. To change the number of per-task MPU regions, use `-DRT_MPU_NUM_TASK_REGIONS=`. The remaining lower-priority regions can be configured at startup time and will not be modified by `rt`. The MPU is never disabled at run-time, even during context switches and interrupts. The background MPU region is enabled, so privileged tasks and exceptions will have access to memory with the default permissions and attributes unless there is a region specifically configured for a given address.