rt 0.19.0

A real-time operating system capable of full preemption
Documentation
# 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
[`<rt/arch/udf_lazy_fp.S>`](include/rt/arch/udf_lazy_fp.S) for an assembly
macro that can be invoked from the undefined instruction handler to achieve
this. 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
[`<rt/arch/mpu.h>`](include/rt/arch/mpu.h). By default, `rt` assumes the MPU
has 8 regions, but this can be overridden with `-DRT_MPU_NUM_REGIONS=<number>`
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=<number>`. 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.