【简介】
本地集成NXP S32K3 的最新的FreeRTOS V11.1.0 版本已经适配支持了创建任务时添加MPU 的region 配置的功能,我们只需要在S32DS的FreeRTOS的配置界面下开启对应的配置即可。

针对MPU 的说明,此贴(【S32K3XX】MPU 功能验证)(【S32K3XX】Memory 访问默认权限配置)之前有过介绍。
开启配置后 S32DS 编译代码会有如下的link错误。

查看源代码文件,发现配置MPU 会将FreeRTOS 的代码和资源分配不同的属性我们需要在link 文件中添加对应的section 来支持该特性。

#if( configENABLE_MPU == 1 )
void prvSetupMPU(void) {
extern uint32_t __FreeRTOS_privileged_functions_start__[];
extern uint32_t __FreeRTOS_privileged_functions_end__[];
extern uint32_t __FreeRTOS_system_calls_start__[];
extern uint32_t __FreeRTOS_system_calls_end__[];
extern uint32_t __FreeRTOS_privileged_data_start__[];
extern uint32_t __FreeRTOS_privileged_data_end__[];
extern uint32_t __FreeRTOS_code_data_start__[];
extern uint32_t __FreeRTOS_code_data_end__[];
/* The only permitted number of regions are 8 or 16. */
configASSERT( ( configTOTAL_MPU_REGIONS == 8 ) || ( configTOTAL_MPU_REGIONS == 16 ) );
/* Ensure that the configTOTAL_MPU_REGIONS is configured correctly. */
configASSERT( portMPU_TYPE_REG == portEXPECTED_MPU_TYPE_VALUE );
/* Check the expected MPU is present. */
if( portMPU_TYPE_REG == portEXPECTED_MPU_TYPE_VALUE )
{
__asm volatile ( "dsb" );
__asm volatile ( "isb" );
/* Disable MPU before configuration */
portMPU_CTRL_REG &= ~portMPU_ENABLE;
/* portCODE_DATA_MEMORY_MAP_REGION */
portMPU_REGION_BASE_ADDRESS_REG =
( ( uint32_t ) __FreeRTOS_code_data_start__ ) |
( portMPU_REGION_VALID ) |
( portCODE_DATA_MEMORY_MAP_REGION );
portMPU_REGION_ATTRIBUTE_REG =
( prvGetMPURegionSizeSetting( ( uint32_t ) __FreeRTOS_code_data_end__ - ( uint32_t ) __FreeRTOS_code_data_start__)) |
( portMPU_REGION_READ_WRITE ) |
( ( 0x0BUL & portMPU_RASR_TEX_S_C_B_MASK ) << portMPU_RASR_TEX_S_C_B_LOCATION ) |
( portMPU_REGION_ENABLE );
/* Setup the privileged functions for privileged only access.
* This is where the kernel code is placed. */
portMPU_REGION_BASE_ADDRESS_REG =
( ( uint32_t ) __FreeRTOS_privileged_functions_start__ ) |
( portMPU_REGION_VALID ) |
( portPRIVILEGED_FUNCTIONS_REGION );
portMPU_REGION_ATTRIBUTE_REG =
( prvGetMPURegionSizeSetting( ( uint32_t ) __FreeRTOS_privileged_functions_end__
- ( uint32_t ) __FreeRTOS_privileged_functions_start__ ) ) |
( portMPU_REGION_PRIVILEGED_READ_ONLY ) |
( portMPU_REGION_ENABLE );
/* Setup the system MPU wrappers functions.
* This is where the system FreeRTOS MPU wrappers code is placed. */
portMPU_REGION_BASE_ADDRESS_REG =
( ( uint32_t ) __FreeRTOS_system_calls_start__ ) |
( portMPU_REGION_VALID ) |
( portPRIVILEGED_SYSTEM_CALLS_REGION );
portMPU_REGION_ATTRIBUTE_REG =
( prvGetMPURegionSizeSetting( ( uint32_t ) __FreeRTOS_system_calls_end__
- ( uint32_t ) __FreeRTOS_system_calls_start__ ) ) |
( portMPU_REGION_READ_WRITE ) |
( ( 0x0BUL & portMPU_RASR_TEX_S_C_B_MASK ) << portMPU_RASR_TEX_S_C_B_LOCATION ) |
( portMPU_REGION_ENABLE );
/* Setup the privileged data RAM region.
* This is where the kernel data is placed. */
portMPU_REGION_BASE_ADDRESS_REG =
( ( uint32_t ) __FreeRTOS_privileged_data_start__ ) |
( portMPU_REGION_VALID ) |
( portPRIVILEGED_DATA_REGION );
portMPU_REGION_ATTRIBUTE_REG =
( prvGetMPURegionSizeSetting( ( uint32_t ) __FreeRTOS_privileged_data_end__
- ( uint32_t ) __FreeRTOS_privileged_data_start__ ) ) |
( portMPU_REGION_PRIVILEGED_READ_WRITE ) |
( ( 0x0BUL & portMPU_RASR_TEX_S_C_B_MASK ) << portMPU_RASR_TEX_S_C_B_LOCATION ) |
( portMPU_REGION_EXECUTE_NEVER ) |
( portMPU_REGION_ENABLE );
/* Enable the memory fault exception. */
portNVIC_SYS_CTRL_STATE_REG |= portNVIC_MEM_FAULT_ENABLE;
/* Enable the MPU with the background region configured. */
portMPU_CTRL_REG |= ( portMPU_ENABLE | portMPU_BACKGROUND_ENABLE );
__asm volatile ( "dsb" );
__asm volatile ( "isb" );
}
}本地修改link文件解决上述MPU依赖问题,修改如下



修改后之前的link 错误已经得到解决。
本地添加如下的测试代码,来验证MPU 保护的功能。
#define main_TASK_PRIORITY ( tskIDLE_PRIORITY + 2 )
#define SHARED_MEMORY_SIZE 128
/* restricted variable */
PRIVILEGED_DATA volatile BaseType_t testResult = 0x33U;
/* Task function prototypes */
static void vPrivilegedTask(void *pvParameters);
static void vUnprivilegedTask(void *pvParameters);
/* Stack and TCB for static allocation (optional) */
PRIVILEGED_DATA StackType_t xPrivilegedStack[configMINIMAL_STACK_SIZE];
StackType_t xUnprivilegedStack[configMINIMAL_STACK_SIZE];
/* MPU region settings (example: allow access to a buffer) */
uint8_t ucSharedMemory[SHARED_MEMORY_SIZE] __attribute__((aligned(32)));
/* Privileged task parameters */
static const TaskParameters_t xPrivilegedTaskParams = { .pvTaskCode = vPrivilegedTask, .pcName = "Privileged", .usStackDepth = configMINIMAL_STACK_SIZE, .pvParameters = NULL,
.uxPriority = (main_TASK_PRIORITY + 1) | portPRIVILEGE_BIT, // Run in privileged mode
.puxStackBuffer = xPrivilegedStack, // Privileged stack
.xRegions = {
{ ucSharedMemory, SHARED_MEMORY_SIZE, portMPU_REGION_READ_WRITE | portMPU_REGION_EXECUTE_NEVER },
{ 0 }
},
};
/* Unprivileged task parameters */
static const TaskParameters_t xUnprivilegedTaskParams = { .pvTaskCode = vUnprivilegedTask, .pcName = "Unprivileged", .usStackDepth = configMINIMAL_STACK_SIZE, .pvParameters = NULL,
.uxPriority = main_TASK_PRIORITY, // Run in unprivileged mode
.puxStackBuffer = xUnprivilegedStack, // UnPrivileged stack
.xRegions = {
{ ucSharedMemory, sizeof(ucSharedMemory), portMPU_REGION_READ_WRITE | portMPU_REGION_EXECUTE_NEVER },
{ 0 }
},
};
void vPrivilegedTask(void *pvParameters) {
(void) pvParameters;
static uint32_t taskCntPrivileged = 0;
static uint32_t i = 0;
for (;;) {
/* Can access all memory region assigned to current task */
for (i = 0; i < SHARED_MEMORY_SIZE; i++) {
/* fill the restricted memory arrays */
ucSharedMemory[i] += 1;
//PRINTF("1\\r\n");
}
taskCntPrivileged++;
vTaskDelay(pdMS_TO_TICKS(500));
}
}
void vUnprivilegedTask(void *pvParameters) {
(void) pvParameters;
static uint32_t taskCntUnprivileged = 0;
static uint32_t i = 0;
for (;;) {
/* Can access all memory region assigned to current task */
for (i = 0; i< SHARED_MEMORY_SIZE ; i++) {
ucSharedMemory[i] += 2;
//PRINTF("2\r\n");
}
taskCntUnprivileged++;
if (taskCntUnprivileged > 100) {
/* try to access privileged variable */
testResult++;
}
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
mian
{
/* create 2 restricted tasks: privileged and unprivileged */
xTaskCreateRestricted(&xPrivilegedTaskParams, NULL);
xTaskCreateRestricted(&xUnprivilegedTaskParams, NULL);
vTaskStartScheduler();
}上述代码分别配置任务访问资源的特权等级为特权级和非特权级。

本地运行在非特权级别的任务中访问特权级的变量会触发MPU的异常。

本地在特权级和非特权的任务中断点查看对应任务运行时的特权等级。
非特权级访问的任务运行时对应的nPRIV = 1(非特权)

特权级访问的任务运行时对应的nPRIV = 0(特权)

我要赚赏金
