refactor mpu.h some more and rename RT_MPU_ENABLE to RT_MPU_TASK_REGIONS_ENABLE

This commit is contained in:
Chris Copeland 2024-03-17 02:33:17 -07:00
parent e823dc524b
commit 3cbea40dbd
Signed by: chrisnc
GPG Key ID: 14550DA72485DF30
11 changed files with 66 additions and 62 deletions

View File

@ -88,15 +88,17 @@ Extensions_.
## Memory Protection
The memory protection unit available in many Cortex-M and Cortex-R devices is
supported and can be enabled by compiling with `-DRT_MPU_ENABLE=1`. By default,
`rt` assumes the MPU has 8 regions, but this can be overridden with
`-DRT_MPU_NUM_REGIONS=<number>` for processors with more. 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.
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.

View File

@ -43,9 +43,10 @@
#endif // RT_ARM_FP
.macro mpuconfigure
#if RT_MPU_ENABLE
ldr r1, =rt_mpu_config
#if RT_MPU_TASK_REGIONS_ENABLE
ldr r1, =rt_active_task
ldr r1, [r1]
adds r1, RT_MPU_TASK_CONFIG_OFFSET
movs r2, RT_MPU_TASK_REGION_START_ID
adds r5, r2, RT_MPU_NUM_TASK_REGIONS

View File

@ -59,6 +59,12 @@ __attribute__((noreturn, weak)) void rt_trap(void)
}
}
#if RT_MPU_TASK_REGIONS_ENABLE
rt_static_assert(offsetof(struct rt_task, mpu_config) ==
RT_MPU_TASK_CONFIG_OFFSET,
"RT_MPU_TASK_CONFIG_OFFSET is incorrect");
#endif // RT_MPU_TASK_REGIONS_ENABLE
#if RT_ARM_V6M
#include "m/atomic-v6.c"
#endif

View File

@ -22,6 +22,10 @@ extern "C" {
#define RT_MPU_TASK_REGION_START_ID \
(RT_MPU_NUM_REGIONS - RT_MPU_NUM_TASK_REGIONS)
/* This value is derived from the layout of struct rt_task and checked in
* arm.c. It's provided here so it can be used in assembly. */
#define RT_MPU_TASK_CONFIG_OFFSET 32
#if !defined(__ASSEMBLER__)
#include <stddef.h>

View File

@ -8,7 +8,7 @@
extern "C" {
#endif
#if RT_MPU_ENABLE
#if RT_MPU_TASK_REGIONS_ENABLE
#define RT_STACK_ALIGN(n) RT_MPU_ALIGN(n)
@ -16,7 +16,7 @@ extern "C" {
#define RT_STACK_SIZE(n) RT_MPU_SIZE(n)
#endif
#endif // RT_MPU_ENABLE
#endif // RT_MPU_TASK_REGIONS_ENABLE
// The Arm ABI specifies a minimum stack alignment of 8 bytes.
#ifndef RT_STACK_ALIGN

View File

@ -19,12 +19,12 @@
struct context
{
#if !RT_ARM_V6M && RT_MPU_ENABLE
/* Only track per-task privilege if the MPU is enabled and the architecture
* version is 7 or greater. Dropping privilege prevents masking interrupts,
* which is required for atomic operations on v6-m. */
#if !RT_ARM_V6M && RT_MPU_TASK_REGIONS_ENABLE
/* Only track per-task privilege if per-task MPU regions are enabled and
* the architecture version is 7 or greater. Dropping privilege prevents
* masking interrupts, which is required for atomic operations on v6-m. */
uint32_t control;
#endif // (__ARM_ARCH >= 7) && RT_MPU_ENABLE
#endif // (__ARM_ARCH >= 7) && RT_MPU_TASK_REGIONS_ENABLE
#if RT_ARM_V8M
uint32_t psplim;
@ -52,12 +52,12 @@ static struct context *context_init(void *stack, size_t stack_size,
struct context *ctx = sp;
--ctx;
#if !RT_ARM_V6M && RT_MPU_ENABLE
#if !RT_ARM_V6M && RT_MPU_TASK_REGIONS_ENABLE
/* Tasks start privileged. The SPSEL bit is RAZ/WI in handler mode where
* context switches occur. The exception return value specifies which stack
* pointer is used when returning to thread mode. */
ctx->control = 0;
#endif // !RT_ARM_V6M && RT_MPU_ENABLE
#endif // !RT_ARM_V6M && RT_MPU_TASK_REGIONS_ENABLE
#if RT_ARM_V8M
ctx->psplim = (uint32_t)stack;
@ -74,14 +74,14 @@ static struct context *context_init(void *stack, size_t stack_size,
void rt_task_drop_privilege(void)
{
#if !RT_ARM_V6M && RT_MPU_ENABLE
#if !RT_ARM_V6M && RT_MPU_TASK_REGIONS_ENABLE
uint32_t control;
__asm__ __volatile__("mrs %0, control" : "=r"(control));
__asm__("dsb; msr control, %0; isb"
:
: "r"(control | CONTROL_NPRIV)
: "memory");
#endif // !RT_ARM_V6M && RT_MPU_ENABLE
#endif // !RT_ARM_V6M && RT_MPU_TASK_REGIONS_ENABLE
}
void rt_cycle_init(void)

View File

@ -12,10 +12,11 @@
.syntax unified
#if RT_MPU_ENABLE
#if RT_MPU_TASK_REGIONS_ENABLE
.macro mpuconfigure
ldr r1, =rt_mpu_config
ldr r1, =rt_active_task
ldr r1, [r1]
adds r1, RT_MPU_TASK_CONFIG_OFFSET
ldr r2, =0xE000ED98
mpuset RT_MPU_TASK_REGION_START_ID, RT_MPU_NUM_TASK_REGIONS
dsb
@ -36,22 +37,22 @@
str r5, [r2, 8]
mpuset (\r + 1), (\n - 1)
.endm
#else // !RT_MPU_ENABLE
#else // !RT_MPU_TASK_REGIONS_ENABLE
.macro mpuconfigure
.endm
#endif // RT_MPU_ENABLE
#endif // RT_MPU_TASK_REGIONS_ENABLE
#if (__ARM_ARCH >= 7) && RT_MPU_ENABLE
#if (__ARM_ARCH >= 7) && RT_MPU_TASK_REGIONS_ENABLE
#define CONTROL_SIZE 4
#define controltemp r2,
#define getcontrol mrs r2, control
#define setcontrol msr control, r2
#else // __ARM_ARCH <= 6 || !RT_MPU_ENABLE
#else // __ARM_ARCH <= 6 || !RT_MPU_TASK_REGIONS_ENABLE
#define CONTROL_SIZE 0
#define controltemp
#define getcontrol
#define setcontrol
#endif // (__ARM_ARCH >= 7) && RT_MPU_ENABLE
#endif // (__ARM_ARCH >= 7) && RT_MPU_TASK_REGIONS_ENABLE
#if __ARM_ARCH == 8
#define PSPLIM_SIZE 4

View File

@ -31,14 +31,15 @@
#define return mov r0, TASK_INITIAL_EXC_RETURN; bx r0
#endif // RT_ARM_FP
#if RT_MPU_ENABLE
#if RT_MPU_TASK_REGIONS_ENABLE
#define controltemp r2,
#define getcontrol mrs r2, control
#define setcontrol msr control, r2
.macro mpuconfigure
ldr r1, =rt_mpu_config
ldr r1, =rt_active_task
ldr r1, [r1]
adds r1, RT_MPU_TASK_CONFIG_OFFSET
ldr r2, =0xE000ED9C
mpuset RT_MPU_TASK_REGION_START_ID, RT_MPU_NUM_TASK_REGIONS
dsb
@ -89,12 +90,12 @@
.endif
.endm
#else // !RT_MPU_ENABLE
#else // !RT_MPU_TASK_REGIONS_ENABLE
#define controltemp
#define getcontrol
#define setcontrol
#define mpuconfigure
#endif // RT_MPU_ENABLE
#endif // RT_MPU_TASK_REGIONS_ENABLE
#if __ARM_ARCH == 8
#define psplimtemp r3,

View File

@ -4,17 +4,17 @@
extern "C" {
#endif
#ifndef RT_MPU_ENABLE
#define RT_MPU_ENABLE 0
#ifndef RT_MPU_TASK_REGIONS_ENABLE
#define RT_MPU_TASK_REGIONS_ENABLE 0
#endif
#if RT_MPU_ENABLE
#if RT_MPU_TASK_REGIONS_ENABLE
#include <rt/arch/mpu.h>
#endif
// This can be defined by rt/arch/mpu.h.
#ifndef RT_MPU_PRIV_SECTIONS_ENABLE
#define RT_MPU_PRIV_SECTIONS_ENABLE RT_MPU_ENABLE
#define RT_MPU_PRIV_SECTIONS_ENABLE RT_MPU_TASK_REGIONS_ENABLE
#endif
#if RT_MPU_PRIV_SECTIONS_ENABLE

View File

@ -10,16 +10,14 @@
#include <limits.h>
#ifndef RT_TASK_READY_CTZ_ENABLE
#if ((defined(__arm__) || defined(__aarch64__)) && \
defined(__ARM_FEATURE_CLZ)) || \
defined(__x86_64__)
#define RT_TASK_READY_CTZ_ENABLE 1
#else
#else // architecture detection
#define RT_TASK_READY_CTZ_ENABLE 0
#endif
#endif
#endif // !defined(RT_TASK_READY_CTZ_ENABLE)
#define RT_TASK_PRIORITY_MIN UINT32_C(0)
#define RT_TASK_PRIORITY_MAX UINT32_C(31)
@ -80,11 +78,11 @@ struct rt_task
void *ctx;
uint32_t priority;
uint32_t base_priority;
enum rt_task_state state;
unsigned long wake_tick;
#if RT_MPU_ENABLE
#if RT_MPU_TASK_REGIONS_ENABLE
struct rt_mpu_config mpu_config;
#endif
enum rt_task_state state;
union
{
struct rt_sem *sem;
@ -130,15 +128,15 @@ void rt_task_ready(struct rt_task *task);
RT_TASK_COMMON_(fn, stack_size, priority, name, ctx_init, __COUNTER__, \
__VA_ARGS__)
#if RT_MPU_ENABLE
#if RT_MPU_TASK_REGIONS_ENABLE
#define RT_TASK_MPU_CONFIG_INIT(fn, ...) \
RT_MPU_CONFIG_INIT(&fn##_task.mpu_config, \
RT_MPU_REGION(fn##_task_stack, sizeof fn##_task_stack, \
RT_MPU_ATTR_STACK), \
__VA_ARGS__);
#else
#else // !RT_MPU_TASK_REGIONS_ENABLE
#define RT_TASK_MPU_CONFIG_INIT(fn, ...)
#endif
#endif // RT_MPU_TASK_REGIONS_ENABLE
#define RT_TASK_COMMON_(fn, stack_size, priority, name, ctx_init, counter, \
...) \
@ -172,6 +170,8 @@ void rt_task_ready(struct rt_task *task);
sizeof fn##_task_stack), \
__VA_ARGS__)
extern struct rt_task *rt_active_task;
#ifdef __cplusplus
}
#endif

View File

@ -83,7 +83,7 @@ RT_TASK(rt_idle, RT_STACK_MIN, RT_TASK_PRIORITY_IDLE);
/* rt_active_task must be readable from user code.
* Task structures themselves are privileged. */
static struct rt_task *rt_active_task = NULL;
struct rt_task *rt_active_task = NULL;
void rt_task_yield(void)
{
@ -148,16 +148,12 @@ static void task_wait(struct rt_task *task, struct rt_list *list)
RT_MPU_PRIV_BSS(rt_context_prev)
void **rt_context_prev;
#if RT_MPU_ENABLE
RT_MPU_PRIV_BSS(rt_mpu_config)
struct rt_mpu_config *rt_mpu_config;
#endif
void *rt_start_context(void)
{
#if RT_CYCLE_ENABLE
rt_cycle_init();
#endif
#endif // !RT_CYCLE_ENABLE
rt_task_cycle_resume();
// Initially all tasks are ready, including the idle task.
@ -166,10 +162,6 @@ void *rt_start_context(void)
first_task->state = RT_TASK_STATE_RUNNING;
rt_active_task = first_task;
#if RT_MPU_ENABLE
rt_mpu_config = &first_task->mpu_config;
#endif
rt_logf("rt_start_context: %s with priority %u\n", first_task->name,
first_task->priority);
@ -189,9 +181,6 @@ static void *sched(void)
rt_context_prev = &rt_active_task->ctx;
rt_active_task = next_task;
#if RT_MPU_ENABLE
rt_mpu_config = &next_task->mpu_config;
#endif
rt_logf("sched: switching to %s with priority %u\n", rt_task_name(),
next_task->priority);