mirror of
https://github.com/RT-Thread/rt-thread.git
synced 2026-10-02 14:23:19 +08:00
实现MPU抽象层 (#8080)
- 为RT-Thread设计MPU抽象层,支持ARMV7-M,ARMV8-M架构,让用户使用MPU检测栈溢出等内存问题,实现线程内存隔离 - 在components/mp目录下提供通用的API,libcpu目录下提供各处理器架构的具体实现 - 在STM32U575 NUCLEO, STM32H75 NUCLEO开发板测试通过
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -10,6 +10,19 @@
|
||||
|
||||
#include "board.h"
|
||||
|
||||
#ifdef RT_USING_MEM_PROTECTION
|
||||
#include "mprotect.h"
|
||||
|
||||
rt_mem_region_t static_regions[NUM_STATIC_REGIONS] = {
|
||||
/* Flash region, read only */
|
||||
{
|
||||
.start = (void *)STM32_FLASH_START_ADRESS,
|
||||
.size = (rt_size_t)STM32_FLASH_SIZE,
|
||||
.attr = RT_MEM_REGION_P_RX_U_RX,
|
||||
},
|
||||
};
|
||||
#endif
|
||||
|
||||
void SystemClock_Config(void)
|
||||
{
|
||||
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
|
||||
|
||||
@@ -42,6 +42,10 @@ extern int __bss_end;
|
||||
|
||||
#define HEAP_END STM32_SRAM1_END
|
||||
|
||||
#ifdef RT_USING_MEM_PROTECTION
|
||||
#define NUM_STATIC_REGIONS 1
|
||||
#endif
|
||||
|
||||
void SystemClock_Config(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
/* RT-Thread Kernel */
|
||||
|
||||
#define RT_NAME_MAX 8
|
||||
#define RT_CPUS_NR 1
|
||||
#define RT_ALIGN_SIZE 8
|
||||
#define RT_THREAD_PRIORITY_32
|
||||
#define RT_THREAD_PRIORITY_MAX 32
|
||||
@@ -42,14 +43,12 @@
|
||||
#define RT_USING_SMALL_MEM
|
||||
#define RT_USING_SMALL_MEM_AS_HEAP
|
||||
#define RT_USING_HEAP
|
||||
|
||||
/* Kernel Device Object */
|
||||
|
||||
#define RT_USING_DEVICE
|
||||
#define RT_USING_CONSOLE
|
||||
#define RT_CONSOLEBUF_SIZE 256
|
||||
#define RT_CONSOLE_DEVICE_NAME "uart1"
|
||||
#define RT_VER_NUM 0x50002
|
||||
#define RT_VER_NUM 0x50100
|
||||
#define RT_BACKTRACE_LEVEL_MAX_NR 32
|
||||
#define RT_USING_HW_ATOMIC
|
||||
#define RT_USING_CPU_FFS
|
||||
#define ARCH_ARM
|
||||
@@ -126,6 +125,18 @@
|
||||
/* Utilities */
|
||||
|
||||
|
||||
/* Memory management */
|
||||
|
||||
|
||||
/* Memory protection */
|
||||
|
||||
#define RT_USING_MEM_PROTECTION
|
||||
#define RT_USING_HW_STACK_GUARD
|
||||
#define USE_MEM_PROTECTION_EXAMPLES
|
||||
#define NUM_MEM_REGIONS 8
|
||||
#define NUM_EXCLUSIVE_REGIONS 2
|
||||
#define NUM_CONFIGURABLE_REGIONS 3
|
||||
|
||||
/* RT-Thread Utestcases */
|
||||
|
||||
|
||||
@@ -164,6 +175,9 @@
|
||||
/* u8g2: a monochrome graphic library */
|
||||
|
||||
|
||||
/* PainterEngine: A cross-platform graphics application framework written in C language */
|
||||
|
||||
|
||||
/* tools packages */
|
||||
|
||||
|
||||
@@ -195,9 +209,6 @@
|
||||
/* AI packages */
|
||||
|
||||
|
||||
/* Signal Processing and Control Algorithm Packages */
|
||||
|
||||
|
||||
/* miscellaneous packages */
|
||||
|
||||
/* project laboratory */
|
||||
@@ -211,7 +222,7 @@
|
||||
/* Arduino libraries */
|
||||
|
||||
|
||||
/* Projects and Demos */
|
||||
/* Projects */
|
||||
|
||||
|
||||
/* Sensors */
|
||||
@@ -236,7 +247,6 @@
|
||||
|
||||
/* Other */
|
||||
|
||||
|
||||
/* Signal IO */
|
||||
|
||||
|
||||
|
||||
@@ -35,5 +35,6 @@ source "$RTT_DIR/components/net/Kconfig"
|
||||
source "$RTT_DIR/components/utilities/Kconfig"
|
||||
source "$RTT_DIR/components/vbus/Kconfig"
|
||||
source "$RTT_DIR/components/mm/Kconfig"
|
||||
source "$RTT_DIR/components/mprotect/Kconfig"
|
||||
|
||||
endmenu
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
menu "Memory protection"
|
||||
|
||||
config RT_USING_MEM_PROTECTION
|
||||
bool "Enable memory protection"
|
||||
default n
|
||||
select RT_USING_HEAP
|
||||
|
||||
config RT_USING_HW_STACK_GUARD
|
||||
bool "Enable hardware stack guard"
|
||||
default n
|
||||
select RT_USING_MEM_PROTECTION
|
||||
|
||||
if RT_USING_MEM_PROTECTION
|
||||
config USE_MEM_PROTECTION_EXAMPLES
|
||||
bool "Use memory protection examples"
|
||||
default y
|
||||
|
||||
config NUM_MEM_REGIONS
|
||||
int "Total number of memory protection regions supported by hardware"
|
||||
|
||||
config NUM_EXCLUSIVE_REGIONS
|
||||
int "Total number of exclusive memory regions added using rt_mprotect_add_exclusive_region API"
|
||||
|
||||
config NUM_CONFIGURABLE_REGIONS
|
||||
int "Maximum number of configurable memory regions for each thread, excluding stack guard and exclusive regions added using rt_mprotect_add_exclusive_region API"
|
||||
endif
|
||||
|
||||
endmenu
|
||||
@@ -0,0 +1,155 @@
|
||||
# RT-Thread MPU抽象层
|
||||
Mprotect(Memory Protection)组件是为不同处理器架构的内存保护单元提供的一套通用框架,让用户能使用这套框架解决一些常见的内存问题。
|
||||
|
||||
# 内存保护单元
|
||||
内存保护单元是一个可编程的设备,用来指定一块特定内存区域的访问权限,比如读,写,和从该区域执行代码的权限。内存保护单元可以增加系统的健壮性,预防一些黑客的攻击。ARMV7-M和ARMV8-M都提供了内存保护单元,简称MPU(Memory Protection Unit)。[论坛里的这篇文章](https://club.rt-thread.org/ask/article/610305c1379b9e5e.html)提供了ARM MPU更详细的介绍。RISC-V也提供了相似的功能,简称PMP(Physical Memory Protection),具体可参考[RISC-V架构手册](https://riscv.org/wp-content/uploads/2017/05/riscv-privileged-v1.10.pdf)。
|
||||
|
||||
# 硬件支持
|
||||
目前支持ARMV7-M和ARMV8-M架构。本目录下存放框架的通用代码和两个简单的例程。硬件相关的代码存放在`libcpu`目录。
|
||||
|
||||
# 功能简介
|
||||
RT-Thread操作系统的任务和内核使用同一个地址空间,全部运行在特权级。所有代码默认对任何内存都有读,写,和执行的权限。使用MPU框架可以给特定的内存区域设置更低的权限,如只读权限。MPU框架可以被用来实现以下的功能:
|
||||
|
||||
- 把关键数据或代码设置成只读,防止它们被破坏
|
||||
- 任务隔离,设定特定地址只能由特定的任务访问
|
||||
- 检测栈溢出
|
||||
- 把数据区域设置为不可执行,防止栈溢出攻击
|
||||
|
||||
# 使用方法
|
||||
## Menuconfig配置
|
||||
通过`menuconfig`进入`RT-Thread Components->Memory Protection`配置相关选项
|
||||
|
||||
- `RT_USING_MEM_PROTECTION`:开启MPU抽象层
|
||||
- `RT_USING_HW_STACK_GUARD`:使用MPU检测栈溢出。具体实现原理是在任务栈顶和栈底各设置一个MPU区域,权限设置为不可访问。如果发生栈溢出,代码访问了MPU保护的地址,会触发异常
|
||||
- `NUM_MEM_REGIONS`:硬件支持的MPU区域数量
|
||||
- `NUM_EXCLUSIVE_REGIONS`:使用`rt_mprotect_add_exclusive_region`函数配置的内存区域数量
|
||||
- `NUM_CONFIGURABLE_REGIONS`:各任务可以通过`rt_mprotect_add_region`函数配置的内存区域数量
|
||||
|
||||
## 内存区域配置
|
||||
MPU抽象层提供了以下的API来配置任务对内存区域的权限:
|
||||
|
||||
- `rt_err_t rt_mprotect_add_region(rt_thread_t thread, rt_mem_region_t *region)`:添加内存区域
|
||||
- `rt_err_t rt_mprotect_delete_region(rt_thread_t thread, rt_mem_region_t *region)`:删除内存区域
|
||||
- `rt_err_t rt_mprotect_update_region(rt_thread_t thread, rt_mem_region_t *region)`:更新内存区域配置
|
||||
|
||||
内存区域的特性由`rt_mem_region_t`结构体定义:
|
||||
```
|
||||
typedef struct {
|
||||
void *start; /* 起始地址 */
|
||||
rt_size_t size; /* 区域大小 */
|
||||
rt_mem_attr_t attr; /* 区域特性 */
|
||||
} rt_mem_region_t;
|
||||
```
|
||||
其中`attr`可通过以下宏来定义,使用这样定义的代码在任何处理器架构下都是通用的:
|
||||
|
||||
- `RT_MEM_REGION_P_RW_U_RW`:可读写
|
||||
- `RT_MEM_REGION_P_RO_U_RO`: 只读
|
||||
- `RT_MEM_REGION_P_NA_U_NA`:不可访问
|
||||
- `RT_MEM_REGION_P_RWX_U_RWX`:可读写,执行
|
||||
- `RT_MEM_REGION_P_RX_U_RX`:只读,可执行
|
||||
|
||||
通常程序需要定义一块内存区域只能由一个特定的任务访问。允许访问该内存区域的任务可以调用以下函数实现这个功能:
|
||||
|
||||
- `rt_err_t rt_mprotect_add_exclusive_region(void *start, rt_size_t size)`:添加内存区域
|
||||
- `rt_err_t rt_mprotect_delete_exclusive_region(void *start, rt_size_t size)`:删除内存区域
|
||||
|
||||
调用了`rt_mprotect_add_exclusive_region`的任务在退出前必须调用`rt_mprotect_delete_exclusive_region`删除内存区域。
|
||||
|
||||
## 初始化
|
||||
使用MPU抽象层之前需要在`board.h`文件定义固定的MPU区域数量:
|
||||
```
|
||||
#define NUM_STATIC_REGIONS 2
|
||||
```
|
||||
在`board.c`文件定义固定的MPU区域特性:
|
||||
```
|
||||
rt_mem_region_t static_regions[NUM_STATIC_REGIONS] = {
|
||||
/* Flash region, read only */
|
||||
{
|
||||
.start = (void *)STM32_FLASH_START_ADRESS,
|
||||
.size = (rt_size_t)STM32_FLASH_SIZE,
|
||||
.attr = RT_MEM_REGION_P_RX_U_RX,
|
||||
},
|
||||
/* SRAM regin, no execute */
|
||||
{
|
||||
.start = (void *)STM32_SRAM_START_ADDRESS,
|
||||
.size = (rt_size_t)STM32_SRAM_SIZE,
|
||||
.attr = RT_MEM_REGION_P_RW_U_RW,
|
||||
},
|
||||
};
|
||||
```
|
||||
任何代码进行内存访问,都要遵守这些区域的配置。可以用固定的MPU区域,把代码段配置为只读,可执行,把数据段配置成可读写,不可执行。
|
||||
|
||||
另外必须确保配置的MPU区域数量满足以下的关系:
|
||||
- 如果开启了`RT_USING_HW_STACK_GUARD`:`NUM_STATIC_REGIONS` + `NUM_CONFIGURABLE_REGIONS` + `NUM_EXCLUSIVE_REGIONS` + 2 <= `NUM_MEM_REGIONS`
|
||||
- 如果没有开启`RT_USING_HW_STACK_GUARD`:`NUM_STATIC_REGIONS` + `NUM_CONFIGURABLE_REGIONS` + `NUM_EXCLUSIVE_REGIONS` <= `NUM_MEM_REGIONS`
|
||||
|
||||
## 异常检测
|
||||
程序可以注册钩子函数,用来检测内存异常:
|
||||
```
|
||||
rt_err_t rt_hw_mpu_exception_set_hook(rt_hw_mpu_exception_hook_t hook)
|
||||
```
|
||||
`hook`函数会在发生内存异常时被调用。函数声明如下:
|
||||
```
|
||||
typedef void (*rt_hw_mpu_exception_hook_t)(rt_mem_exception_info_t *)
|
||||
```
|
||||
`rt_mem_exception_info_t`结构体根据处理器机构定义,对于ARM架构,提供以下用来诊断内存异常的信息:
|
||||
```
|
||||
typedef struct {
|
||||
rt_thread_t thread; /* 触发异常的线程 */
|
||||
void *addr; /* 发生异常的地址 */
|
||||
rt_mem_region_t region; /* 地址对应的内存区域 */
|
||||
rt_uint8_t mmfsr; /* MemManage Status寄存器的值 */
|
||||
} rt_mem_exception_info_t;
|
||||
```
|
||||
|
||||
# 对RT-Thread内核的影响
|
||||
## 线程内存区域的保存
|
||||
Mprotect组件在`rt_thread_t`结构体添加了`mem_regions`成员变量,用于保存线程内存区域的配置。
|
||||
```
|
||||
struct rt_thread
|
||||
{
|
||||
......
|
||||
#ifdef RT_USING_MEM_PROTECTION
|
||||
void *mem_regions;
|
||||
#endif
|
||||
......
|
||||
}
|
||||
```
|
||||
`mem_regions`的内存采用动态分配,并在删除线程时释放。
|
||||
在切换线程时调用`rt_hw_mpu_table_switch`,切换线程的内存区域配置。
|
||||
```
|
||||
#if defined (RT_USING_MEM_PROTECTION)
|
||||
PUSH {r0-r3, r12, lr}
|
||||
LDR r1, =rt_current_thread
|
||||
LDR r0, [r1]
|
||||
BL rt_hw_mpu_table_switch
|
||||
POP {r0-r3, r12, lr}
|
||||
#endif
|
||||
```
|
||||
|
||||
## 栈溢出检测的实现原理
|
||||
线程创建时内核会根据用户指定的参数为栈分配内存,之后调用`rt_hw_stack_guard_init`配置栈溢出检测。栈溢出检测的实现原理是在线程栈底和栈顶分配两块不可读写的内存区域,如果代码访问这块内存,就会触发异常。
|
||||

|
||||
这种方法会改变内核代码可以操作的栈的起始地址和大小。因此`rt_hw_stack_guard_init`会调整`rt_thread_t->stack_addr`,指向允许访问的栈内存的起始地址,调整`rt_thread_t->stack_size`反映允许操作的内存大小,并在`rt_thread_t`添加成员变量`stack_buf`,指向原本为栈分配的内存的起始地址。这样,内核代码可以对栈进行正常操作,无需改动。
|
||||
|
||||
应用程序需要注意,如果开启了栈溢出检测,线程实际可以使用的栈空间会比分配的内存更小。因此在创建线程时,需要考虑增加`stack_size`参数。
|
||||
|
||||
在删除线程时要使用`stack_buf`变量,正确释放为栈分配的内存。
|
||||
```
|
||||
static void rt_defunct_execute(void)
|
||||
{
|
||||
......
|
||||
if (object_is_systemobject == RT_FALSE)
|
||||
{
|
||||
/* release thread's stack */
|
||||
#ifdef RT_USING_HW_STACK_GUARD
|
||||
RT_KERNEL_FREE(thread->stack_buf);
|
||||
#else
|
||||
RT_KERNEL_FREE(thread->stack_addr);
|
||||
#endif
|
||||
/* delete thread object */
|
||||
rt_object_delete((rt_object_t)thread);
|
||||
}
|
||||
......
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,11 @@
|
||||
from building import *
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
src = Glob('*.c')
|
||||
if GetDepend("USE_MEM_PROTECTION_EXAMPLES"):
|
||||
src += Glob('examples/*.c')
|
||||
CPPPATH = [cwd]
|
||||
|
||||
group = DefineGroup('mprotect', src, depend = ['RT_USING_MEM_PROTECTION'], CPPPATH = CPPPATH)
|
||||
|
||||
Return('group')
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2023-9-25 tangzz98 the first version
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <mprotect.h>
|
||||
|
||||
void mprotect_example_exception_hook(rt_mem_exception_info_t *info)
|
||||
{
|
||||
rt_kprintf("Memory manage exception\n");
|
||||
rt_kprintf("Faulting thread: %s\n", info->thread->parent.name);
|
||||
rt_kprintf("Faulting address: %p\n", info->addr);
|
||||
rt_kprintf("Faulting region: %p - %p", info->region.start, (void *)((rt_size_t)info->region.start + info->region.size));
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2023-09-25 tangzz98 the first version
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <mprotect.h>
|
||||
|
||||
#define THREAD_PRIORITY 25
|
||||
#define THREAD_STACK_SIZE 512
|
||||
#define THREAD_TIMESLICE 5
|
||||
|
||||
rt_align(MPU_MIN_REGION_SIZE) rt_uint8_t thread1_private_data[MPU_MIN_REGION_SIZE];
|
||||
|
||||
static void thread1_entry(void *parameter)
|
||||
{
|
||||
(void)parameter;
|
||||
/* Thread 1 configures thread1_private_data for exclusive access */
|
||||
rt_kprintf("Thread 1 configures private data\n");
|
||||
rt_mprotect_add_exclusive_region((void *)thread1_private_data, MPU_MIN_REGION_SIZE);
|
||||
rt_kprintf("Thread 1 private data address: %p - %p\n", &thread1_private_data[0], &thread1_private_data[MPU_MIN_REGION_SIZE]);
|
||||
rt_kprintf("Thread 1 reads and writes to its private data\n");
|
||||
for (int i = 0; i < MPU_MIN_REGION_SIZE; i++)
|
||||
{
|
||||
/* Thread 1 has access to its private data */
|
||||
thread1_private_data[i] = i;
|
||||
rt_kprintf("thread1_private_data[%d] = %d\n", i, thread1_private_data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void thread2_entry(void *parameter)
|
||||
{
|
||||
(void)parameter;
|
||||
rt_kprintf("Thread 2 writes to thread 1's private data\n");
|
||||
for (int i = 0; i < MPU_MIN_REGION_SIZE; i++)
|
||||
{
|
||||
/*
|
||||
* Thread 2 does not have access to thread 1's private data.
|
||||
* Access generates an exception.
|
||||
*/
|
||||
thread1_private_data[i] = i;
|
||||
}
|
||||
}
|
||||
|
||||
int mprotect_example_exclusive_region()
|
||||
{
|
||||
extern void mprotect_example_exception_hook(rt_mem_exception_info_t *info);
|
||||
rt_hw_mpu_exception_set_hook(mprotect_example_exception_hook);
|
||||
rt_thread_t tid1 = RT_NULL;
|
||||
tid1 = rt_thread_create("thread1",
|
||||
thread1_entry, RT_NULL,
|
||||
THREAD_STACK_SIZE,
|
||||
THREAD_PRIORITY - 1,
|
||||
THREAD_TIMESLICE);
|
||||
if (tid1 != RT_NULL)
|
||||
rt_thread_startup(tid1);
|
||||
|
||||
rt_thread_t tid2 = RT_NULL;
|
||||
tid2 = rt_thread_create("thread2",
|
||||
thread2_entry, RT_NULL,
|
||||
THREAD_STACK_SIZE,
|
||||
THREAD_PRIORITY,
|
||||
THREAD_TIMESLICE);
|
||||
if (tid2 != RT_NULL)
|
||||
rt_thread_startup(tid2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
MSH_CMD_EXPORT(mprotect_example_exclusive_region, Memory protection example (exclusive_region));
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2023-09-25 tangzz98 the first version
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <mprotect.h>
|
||||
|
||||
#define THREAD_PRIORITY 25
|
||||
#define THREAD_STACK_SIZE 512
|
||||
#define THREAD_TIMESLICE 5
|
||||
|
||||
rt_align(MPU_MIN_REGION_SIZE) rt_uint8_t ro_data[MPU_MIN_REGION_SIZE];
|
||||
|
||||
static void thread1_entry(void *parameter)
|
||||
{
|
||||
(void)parameter;
|
||||
rt_kprintf("ro_data address: %p - %p\n", &ro_data[0], &ro_data[MPU_MIN_REGION_SIZE]);
|
||||
/* Thread 1 can write ro_data before configuring memory protection. */
|
||||
rt_kprintf("Thread 1 writes to ro_data before configuring memory protection\n");
|
||||
for (int i = 0; i < MPU_MIN_REGION_SIZE; i++)
|
||||
{
|
||||
ro_data[i] = i;
|
||||
rt_kprintf("ro_data[%d] = %d\n", i, ro_data[i]);
|
||||
}
|
||||
rt_mem_region_t ro_region =
|
||||
{
|
||||
.start = (void *)ro_data,
|
||||
.size = MPU_MIN_REGION_SIZE,
|
||||
.attr = RT_MEM_REGION_P_RO_U_RO,
|
||||
};
|
||||
/* Thread 1 configures ro_data as read only. */
|
||||
rt_kprintf("Thread 1 configures ro_data for read-only access for thread 1\n");
|
||||
rt_mprotect_add_region(RT_NULL, &ro_region);
|
||||
rt_kprintf("Thread 1 reads ro_data\n");
|
||||
for (int i = 0; i < MPU_MIN_REGION_SIZE; i++)
|
||||
{
|
||||
rt_kprintf("ro_data[%d] = %d\n", i, ro_data[i]);
|
||||
}
|
||||
rt_thread_delay(RT_TICK_PER_SECOND * 1);
|
||||
/* Thread 1 cannot write ro_data. */
|
||||
rt_kprintf("Thread 1 writes to ro_data\n");
|
||||
for (int i = 0; i < MPU_MIN_REGION_SIZE; i++)
|
||||
{
|
||||
ro_data[i] = i;
|
||||
}
|
||||
}
|
||||
|
||||
static void thread2_entry(void *parameter)
|
||||
{
|
||||
(void)parameter;
|
||||
rt_kprintf("Thread 2 writes to ro_data\n");
|
||||
for (int i = 0; i < MPU_MIN_REGION_SIZE; i++)
|
||||
{
|
||||
/* Thread 2 can write ro_data. */
|
||||
ro_data[i] = i;
|
||||
rt_kprintf("ro_data[%d] = %d\n", i, ro_data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
int mprotect_example_ro_data()
|
||||
{
|
||||
extern void mprotect_example_exception_hook(rt_mem_exception_info_t *info);
|
||||
rt_hw_mpu_exception_set_hook(mprotect_example_exception_hook);
|
||||
rt_thread_t tid1 = RT_NULL;
|
||||
tid1 = rt_thread_create("thread1",
|
||||
thread1_entry, RT_NULL,
|
||||
THREAD_STACK_SIZE,
|
||||
THREAD_PRIORITY - 1,
|
||||
THREAD_TIMESLICE);
|
||||
rt_thread_startup(tid1);
|
||||
rt_thread_t tid2 = RT_NULL;
|
||||
tid2 = rt_thread_create("thread2",
|
||||
thread2_entry, RT_NULL,
|
||||
THREAD_STACK_SIZE,
|
||||
THREAD_PRIORITY,
|
||||
THREAD_TIMESLICE);
|
||||
rt_thread_startup(tid2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
MSH_CMD_EXPORT(mprotect_example_ro_data, Memory protection example (read-only data));
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 53 KiB |
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2023-09-25 tangzz98 the first version
|
||||
*/
|
||||
|
||||
#ifndef __MPROTECT_H__
|
||||
#define __MPROTECT_H__
|
||||
|
||||
#include <rtdef.h>
|
||||
#include <mputype.h>
|
||||
|
||||
#define ADDR_IN_REGION(addr, region) (((rt_size_t)(addr) >= (rt_size_t)((region)->start)) && ((rt_size_t)(addr) < (rt_size_t)((region)->start) + (region)->size))
|
||||
|
||||
typedef struct
|
||||
{
|
||||
void *start;
|
||||
rt_size_t size;
|
||||
rt_mem_attr_t attr;
|
||||
} rt_mem_region_t;
|
||||
|
||||
#include <mpu.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
rt_mem_region_t region;
|
||||
rt_thread_t owner;
|
||||
} rt_mem_exclusive_region_t;
|
||||
|
||||
int rt_mprotect_init(void);
|
||||
rt_err_t rt_mprotect_add_region(rt_thread_t thread, rt_mem_region_t *region);
|
||||
rt_err_t rt_mprotect_delete_region(rt_thread_t thread, rt_mem_region_t *region);
|
||||
rt_err_t rt_mprotect_update_region(rt_thread_t thread, rt_mem_region_t *region);
|
||||
rt_err_t rt_mprotect_add_exclusive_region(void *start, rt_size_t size);
|
||||
rt_err_t rt_mprotect_delete_exclusive_region(void *start, rt_size_t size);
|
||||
|
||||
#endif /* __MPROTECT_H__ */
|
||||
@@ -997,6 +997,14 @@ struct rt_thread
|
||||
int *clear_child_tid;
|
||||
#endif /* ARCH_MM_MMU */
|
||||
#endif /* RT_USING_SMART */
|
||||
|
||||
#ifdef RT_USING_MEM_PROTECTION
|
||||
void *mem_regions;
|
||||
#ifdef RT_USING_HW_STACK_GUARD
|
||||
void *stack_buf;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
rt_atomic_t ref_count;
|
||||
struct rt_spinlock spinlock;
|
||||
rt_ubase_t user_data; /**< private user data beyond this thread */
|
||||
|
||||
@@ -99,6 +99,10 @@ rt_uint8_t *rt_hw_stack_init(void *entry,
|
||||
rt_uint8_t *stack_addr,
|
||||
void *exit);
|
||||
|
||||
#ifdef RT_USING_HW_STACK_GUARD
|
||||
void rt_hw_stack_guard_init(rt_thread_t thread);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Interrupt handler definition
|
||||
*/
|
||||
|
||||
@@ -18,6 +18,9 @@ if rtconfig.PLATFORM in ['gcc']:
|
||||
if rtconfig.PLATFORM in ['iccarm']:
|
||||
src += Glob('*_iar.S')
|
||||
|
||||
if not GetDepend('RT_USING_MEM_PROTECTION') and not GetDepend('RT_USING_HW_STACK_GUARD'):
|
||||
SrcRemove(src, 'mpu.c')
|
||||
|
||||
group = DefineGroup('CPU', src, depend = [''], CPPPATH = CPPPATH)
|
||||
|
||||
Return('group')
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
*/
|
||||
/*@{*/
|
||||
|
||||
#include <rtconfig.h>
|
||||
|
||||
.cpu cortex-m4
|
||||
.syntax unified
|
||||
.thumb
|
||||
@@ -192,6 +194,14 @@ contex_ns_load:
|
||||
VLDMIAEQ r1!, {d8 - d15} /* pop FPU register s16~s31 */
|
||||
#endif
|
||||
|
||||
#if defined (RT_USING_MEM_PROTECTION)
|
||||
PUSH {r0-r3, r12, lr}
|
||||
LDR r1, =rt_current_thread
|
||||
LDR r0, [r1]
|
||||
BL rt_hw_mpu_table_switch
|
||||
POP {r0-r3, r12, lr}
|
||||
#endif
|
||||
|
||||
pendsv_exit:
|
||||
MSR psp, r1 /* update stack pointer */
|
||||
/* restore interrupt */
|
||||
|
||||
@@ -18,6 +18,9 @@
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#ifdef RT_USING_HW_STACK_GUARD
|
||||
#include <mprotect.h>
|
||||
#endif
|
||||
|
||||
#if /* ARMCC */ ( (defined ( __CC_ARM ) && defined ( __TARGET_FPU_VFP )) \
|
||||
/* Clang */ || (defined ( __clang__ ) && defined ( __VFP_FP__ ) && !defined(__SOFTFP__)) \
|
||||
@@ -233,6 +236,28 @@ rt_uint8_t *rt_hw_stack_init(void *tentry,
|
||||
return stk;
|
||||
}
|
||||
|
||||
#ifdef RT_USING_HW_STACK_GUARD
|
||||
void rt_hw_stack_guard_init(rt_thread_t thread)
|
||||
{
|
||||
rt_mem_region_t stack_top_region, stack_bottom_region;
|
||||
rt_ubase_t stack_bottom = (rt_ubase_t)thread->stack_addr;
|
||||
rt_ubase_t stack_top = (rt_ubase_t)((rt_uint8_t *)thread->stack_addr + thread->stack_size);
|
||||
rt_ubase_t stack_bottom_region_start = RT_ALIGN(stack_bottom, MPU_MIN_REGION_SIZE);
|
||||
rt_ubase_t stack_top_region_start = RT_ALIGN_DOWN(stack_top - MPU_MIN_REGION_SIZE, MPU_MIN_REGION_SIZE);
|
||||
stack_top_region.start = (void *)stack_top_region_start;
|
||||
stack_top_region.size = MPU_MIN_REGION_SIZE;
|
||||
stack_top_region.attr = RT_MEM_REGION_P_RO_U_NA;
|
||||
stack_bottom_region.start = (void *)stack_bottom_region_start;
|
||||
stack_bottom_region.size = MPU_MIN_REGION_SIZE;
|
||||
stack_bottom_region.attr = RT_MEM_REGION_P_RO_U_NA;
|
||||
rt_mprotect_add_region(thread, &stack_top_region);
|
||||
rt_mprotect_add_region(thread, &stack_bottom_region);
|
||||
thread->stack_buf = thread->stack_addr;
|
||||
thread->stack_addr = (void *)(stack_bottom_region_start + MPU_MIN_REGION_SIZE);
|
||||
thread->stack_size = (rt_uint32_t)(stack_top_region_start - (rt_ubase_t)thread->stack_addr);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* This function set the hook, which is invoked on fault exception handling.
|
||||
*
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2023-09-25 tangzz98 the first version
|
||||
*/
|
||||
|
||||
#ifndef __MPU_H__
|
||||
#define __MPU_H__
|
||||
|
||||
#ifdef RT_USING_MEM_PROTECTION
|
||||
|
||||
#include <board.h>
|
||||
#include <mprotect.h>
|
||||
|
||||
#define MPU_MIN_REGION_SIZE 32U
|
||||
|
||||
#define RT_ARM_DEFAULT_MAIR_ATTR (0xF0U)
|
||||
|
||||
/* MPU attributes for configuring data region permission*/
|
||||
/* Privileged Read Write, Unprivileged No Access */
|
||||
#define P_RW_U_NA_NON_SHAREABLE (((0x0 << MPU_RBAR_SH_Pos) & MPU_RBAR_SH_Msk) | ((0x0 << MPU_RBAR_AP_Pos) & MPU_RBAR_AP_Msk) | MPU_RBAR_XN_Msk)
|
||||
#define P_RW_U_NA_OUTER_SHAREABLE (((0x2 << MPU_RBAR_SH_Pos) & MPU_RBAR_SH_Msk) | ((0x0 << MPU_RBAR_AP_Pos) & MPU_RBAR_AP_Msk) | MPU_RBAR_XN_Msk)
|
||||
#define P_RW_U_NA_INNER_SHAREABLE (((0x3 << MPU_RBAR_SH_Pos) & MPU_RBAR_SH_Msk) | ((0x0 << MPU_RBAR_AP_Pos) & MPU_RBAR_AP_Msk) | MPU_RBAR_XN_Msk)
|
||||
/* Privileged Read Write, Unprivileged Read Write */
|
||||
#define P_RW_U_RW_NON_SHAREABLE (((0x0 << MPU_RBAR_SH_Pos) & MPU_RBAR_SH_Msk) | ((0x1 << MPU_RBAR_AP_Pos) & MPU_RBAR_AP_Msk) | MPU_RBAR_XN_Msk)
|
||||
#define P_RW_U_RW_OUTER_SHAREABLE (((0x2 << MPU_RBAR_SH_Pos) & MPU_RBAR_SH_Msk) | ((0x1 << MPU_RBAR_AP_Pos) & MPU_RBAR_AP_Msk) | MPU_RBAR_XN_Msk)
|
||||
#define P_RW_U_RW_INNER_SHAREABLE (((0x3 << MPU_RBAR_SH_Pos) & MPU_RBAR_SH_Msk) | ((0x1 << MPU_RBAR_AP_Pos) & MPU_RBAR_AP_Msk) | MPU_RBAR_XN_Msk)
|
||||
/* Privileged Read Only, Unprivileged No Access */
|
||||
#define P_RO_U_NA_NON_SHAREABLE (((0x0 << MPU_RBAR_SH_Pos) & MPU_RBAR_SH_Msk) | ((0x2 << MPU_RBAR_AP_Pos) & MPU_RBAR_AP_Msk) | MPU_RBAR_XN_Msk)
|
||||
#define P_RO_U_NA_OUTER_SHAREABLE (((0x2 << MPU_RBAR_SH_Pos) & MPU_RBAR_SH_Msk) | ((0x2 << MPU_RBAR_AP_Pos) & MPU_RBAR_AP_Msk) | MPU_RBAR_XN_Msk)
|
||||
#define P_RO_U_NA_INNER_SHAREABLE (((0x3 << MPU_RBAR_SH_Pos) & MPU_RBAR_SH_Msk) | ((0x2 << MPU_RBAR_AP_Pos) & MPU_RBAR_AP_Msk) | MPU_RBAR_XN_Msk)
|
||||
/* Privileged Read Only, Unprivileged Read Only */
|
||||
#define P_RO_U_RO_NON_SHAREABLE (((0x0 << MPU_RBAR_SH_Pos) & MPU_RBAR_SH_Msk) | ((0x3 << MPU_RBAR_AP_Pos) & MPU_RBAR_AP_Msk) | MPU_RBAR_XN_Msk)
|
||||
#define P_RO_U_RO_OUTER_SHAREABLE (((0x2 << MPU_RBAR_SH_Pos) & MPU_RBAR_SH_Msk) | ((0x3 << MPU_RBAR_AP_Pos) & MPU_RBAR_AP_Msk) | MPU_RBAR_XN_Msk)
|
||||
#define P_RO_U_RO_INNER_SHAREABLE (((0x3 << MPU_RBAR_SH_Pos) & MPU_RBAR_SH_Msk) | ((0x3 << MPU_RBAR_AP_Pos) & MPU_RBAR_AP_Msk) | MPU_RBAR_XN_Msk)
|
||||
|
||||
/* MPU attributes for configuring code region permission */
|
||||
#define P_RWX_U_NA_NON_SHAREABLE (((0x0 << MPU_RBAR_SH_Pos) & MPU_RBAR_SH_Msk) | ((0x0 << MPU_RBAR_AP_Pos) & MPU_RBAR_AP_Msk))
|
||||
#define P_RWX_U_NA_OUTER_SHAREABLE (((0x2 << MPU_RBAR_SH_Pos) & MPU_RBAR_SH_Msk) | ((0x0 << MPU_RBAR_AP_Pos) & MPU_RBAR_AP_Msk))
|
||||
#define P_RWX_U_NA_INNER_SHAREABLE (((0x3 << MPU_RBAR_SH_Pos) & MPU_RBAR_SH_Msk) | ((0x0 << MPU_RBAR_AP_Pos) & MPU_RBAR_AP_Msk))
|
||||
|
||||
/* Privileged Read Write Execute, Unprivileged Read Write Execute */
|
||||
#define P_RWX_U_RWX_NON_SHAREABLE (((0x0 << MPU_RBAR_SH_Pos) & MPU_RBAR_SH_Msk) | ((0x1 << MPU_RBAR_AP_Pos) & MPU_RBAR_AP_Msk))
|
||||
#define P_RWX_U_RWX_OUTER_SHAREABLE (((0x2 << MPU_RBAR_SH_Pos) & MPU_RBAR_SH_Msk) | ((0x1 << MPU_RBAR_AP_Pos) & MPU_RBAR_AP_Msk))
|
||||
#define P_RWX_U_RWX_INNER_SHAREABLE (((0x3 << MPU_RBAR_SH_Pos) & MPU_RBAR_SH_Msk) | ((0x1 << MPU_RBAR_AP_Pos) & MPU_RBAR_AP_Msk))
|
||||
|
||||
/* Privileged Read Execute, Unprivileged No Access */
|
||||
#define P_RX_U_NA_NON_SHAREABLE (((0x0 << MPU_RBAR_SH_Pos) & MPU_RBAR_SH_Msk) | ((0x2 << MPU_RBAR_AP_Pos) & MPU_RBAR_AP_Msk))
|
||||
#define P_RX_U_NA_OUTER_SHAREABLE (((0x2 << MPU_RBAR_SH_Pos) & MPU_RBAR_SH_Msk) | ((0x2 << MPU_RBAR_AP_Pos) & MPU_RBAR_AP_Msk))
|
||||
#define P_RX_U_NA_INNER_SHAREABLE (((0x3 << MPU_RBAR_SH_Pos) & MPU_RBAR_SH_Msk) | ((0x2 << MPU_RBAR_AP_Pos) & MPU_RBAR_AP_Msk))
|
||||
|
||||
/* Privileged Read Execute, Unprivileged Read Execute */
|
||||
#define P_RX_U_RX_NON_SHAREABLE (((0x0 << MPU_RBAR_SH_Pos) & MPU_RBAR_SH_Msk) | ((0x3 << MPU_RBAR_AP_Pos) & MPU_RBAR_AP_Msk))
|
||||
#define P_RX_U_RX_OUTER_SHAREABLE (((0x2 << MPU_RBAR_SH_Pos) & MPU_RBAR_SH_Msk) | ((0x3 << MPU_RBAR_AP_Pos) & MPU_RBAR_AP_Msk))
|
||||
#define P_RX_U_RX_INNER_SHAREABLE (((0x3 << MPU_RBAR_SH_Pos) & MPU_RBAR_SH_Msk) | ((0x3 << MPU_RBAR_AP_Pos) & MPU_RBAR_AP_Msk))
|
||||
|
||||
typedef struct
|
||||
{
|
||||
rt_thread_t thread; /* Thread that triggered exception */
|
||||
void *addr; /* Address of faulting memory access */
|
||||
rt_mem_region_t region; /* Configurations of the memory region containing the address */
|
||||
rt_uint8_t mmfsr; /* Content of MemManage Status Register */
|
||||
} rt_mem_exception_info_t;
|
||||
|
||||
typedef void (*rt_hw_mpu_exception_hook_t)(rt_mem_exception_info_t *);
|
||||
|
||||
#define RT_ARM_MEM_ATTR(perm, type) ((rt_mem_attr_t){ .rbar = (perm), .mair_attr = (type) })
|
||||
|
||||
/* Convenient macros for configuring data region attributes with default memory type */
|
||||
#define RT_MEM_REGION_P_RW_U_NA RT_ARM_MEM_ATTR(P_RW_U_NA_NON_SHAREABLE, RT_ARM_DEFAULT_MAIR_ATTR)
|
||||
#define RT_MEM_REGION_P_RW_U_RW RT_ARM_MEM_ATTR(P_RW_U_RW_NON_SHAREABLE, RT_ARM_DEFAULT_MAIR_ATTR)
|
||||
#define RT_MEM_REGION_P_RO_U_NA RT_ARM_MEM_ATTR(P_RO_U_NA_NON_SHAREABLE, RT_ARM_DEFAULT_MAIR_ATTR)
|
||||
#define RT_MEM_REGION_P_RO_U_RO RT_ARM_MEM_ATTR(P_RO_U_RO_NON_SHAREABLE, RT_ARM_DEFAULT_MAIR_ATTR)
|
||||
/* ARM-V8M does not support P_NA_U_NA.
|
||||
For compatibility with rt_mprotect_add_exclusive_region,
|
||||
define RT_MEM_REGION_P_NA_U_NA as the lowest privilege supported.
|
||||
*/
|
||||
#define RT_MEM_REGION_P_NA_U_NA RT_MEM_REGION_P_RO_U_NA
|
||||
|
||||
/* Convenient macros for configuring code region attributes with default memory type and shareability */
|
||||
#define RT_MEM_REGION_P_RWX_U_NA RT_ARM_MEM_ATTR(P_RWX_U_NA_NON_SHAREABLE, RT_ARM_DEFAULT_MAIR_ATTR)
|
||||
#define RT_MEM_REGION_P_RWX_U_RWX RT_ARM_MEM_ATTR(P_RWX_U_RWX_NON_SHAREABLE, RT_ARM_DEFAULT_MAIR_ATTR)
|
||||
#define RT_MEM_REGION_P_RX_U_NA RT_ARM_MEM_ATTR(P_RX_U_NA_NON_SHAREABLE, RT_ARM_DEFAULT_MAIR_ATTR)
|
||||
#define RT_MEM_REGION_P_RX_U_RX RT_ARM_MEM_ATTR(P_RX_U_RX_NON_SHAREABLE, RT_ARM_DEFAULT_MAIR_ATTR)
|
||||
|
||||
rt_bool_t rt_hw_mpu_region_valid(rt_mem_region_t *region);
|
||||
rt_err_t rt_hw_mpu_init(void);
|
||||
rt_err_t rt_hw_mpu_add_region(rt_thread_t thread, rt_mem_region_t *region);
|
||||
rt_err_t rt_hw_mpu_delete_region(rt_thread_t thread, rt_mem_region_t *region);
|
||||
rt_err_t rt_hw_mpu_update_region(rt_thread_t thread, rt_mem_region_t *region);
|
||||
rt_err_t rt_hw_mpu_exception_set_hook(rt_hw_mpu_exception_hook_t hook);
|
||||
|
||||
#endif /* RT_USING_MEM_PROTECTION */
|
||||
|
||||
#endif /* __MPU_H__ */
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2023-09-25 tangzz98 the first version
|
||||
*/
|
||||
|
||||
#ifndef __MPUTYPE_H__
|
||||
#define __MPUTYPE_H__
|
||||
|
||||
#ifdef RT_USING_MEM_PROTECTION
|
||||
|
||||
#ifdef RT_USING_HW_STACK_GUARD
|
||||
#define NUM_DYNAMIC_REGIONS (2 + NUM_CONFIGURABLE_REGIONS)
|
||||
#else
|
||||
#define NUM_DYNAMIC_REGIONS (NUM_CONFIGURABLE_REGIONS)
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
rt_uint32_t rbar;
|
||||
union
|
||||
{
|
||||
rt_uint32_t mair_attr;
|
||||
rt_uint32_t rlar;
|
||||
};
|
||||
} rt_mem_attr_t;
|
||||
|
||||
#endif /* RT_USING_MEM_PROTECTION */
|
||||
|
||||
#endif /* __MPUTYPE_H__ */
|
||||
@@ -18,6 +18,9 @@ if rtconfig.PLATFORM in ['gcc']:
|
||||
if rtconfig.PLATFORM in ['iccarm']:
|
||||
src += Glob('*_iar.S')
|
||||
|
||||
if not GetDepend('RT_USING_MEM_PROTECTION') and not GetDepend('RT_USING_HW_STACK_GUARD'):
|
||||
SrcRemove(src, 'mpu.c')
|
||||
|
||||
group = DefineGroup('CPU', src, depend = [''], CPPPATH = CPPPATH)
|
||||
|
||||
Return('group')
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
*/
|
||||
/*@{*/
|
||||
|
||||
#include <rtconfig.h>
|
||||
|
||||
.cpu cortex-m4
|
||||
.syntax unified
|
||||
.thumb
|
||||
@@ -152,6 +154,14 @@ switch_to_thread:
|
||||
BICNE lr, lr, #0x10 /* lr &= ~(1 << 4), set FPCA. */
|
||||
#endif
|
||||
|
||||
#if defined (RT_USING_MEM_PROTECTION)
|
||||
PUSH {r0-r3, r12, lr}
|
||||
LDR r1, =rt_current_thread
|
||||
LDR r0, [r1]
|
||||
BL rt_hw_mpu_table_switch
|
||||
POP {r0-r3, r12, lr}
|
||||
#endif
|
||||
|
||||
pendsv_exit:
|
||||
/* restore interrupt */
|
||||
MSR PRIMASK, r2
|
||||
|
||||
@@ -18,6 +18,9 @@
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#ifdef RT_USING_HW_STACK_GUARD
|
||||
#include <mprotect.h>
|
||||
#endif
|
||||
|
||||
#if /* ARMCC */ ( (defined ( __CC_ARM ) && defined ( __TARGET_FPU_VFP )) \
|
||||
/* Clang */ || (defined ( __clang__ ) && defined ( __VFP_FP__ ) && !defined(__SOFTFP__)) \
|
||||
@@ -175,6 +178,28 @@ rt_uint8_t *rt_hw_stack_init(void *tentry,
|
||||
return stk;
|
||||
}
|
||||
|
||||
#ifdef RT_USING_HW_STACK_GUARD
|
||||
void rt_hw_stack_guard_init(rt_thread_t thread)
|
||||
{
|
||||
rt_mem_region_t stack_top_region, stack_bottom_region;
|
||||
rt_ubase_t stack_bottom = (rt_ubase_t)thread->stack_addr;
|
||||
rt_ubase_t stack_top = (rt_ubase_t)((rt_uint8_t *)thread->stack_addr + thread->stack_size);
|
||||
rt_ubase_t stack_bottom_region_start = RT_ALIGN(stack_bottom, MPU_MIN_REGION_SIZE);
|
||||
rt_ubase_t stack_top_region_start = RT_ALIGN_DOWN(stack_top - MPU_MIN_REGION_SIZE, MPU_MIN_REGION_SIZE);
|
||||
stack_top_region.start = (void *)stack_top_region_start;
|
||||
stack_top_region.size = MPU_MIN_REGION_SIZE;
|
||||
stack_top_region.attr = RT_MEM_REGION_P_NA_U_NA;
|
||||
stack_bottom_region.start = (void *)stack_bottom_region_start;
|
||||
stack_bottom_region.size = MPU_MIN_REGION_SIZE;
|
||||
stack_bottom_region.attr = RT_MEM_REGION_P_NA_U_NA;
|
||||
rt_mprotect_add_region(thread, &stack_top_region);
|
||||
rt_mprotect_add_region(thread, &stack_bottom_region);
|
||||
thread->stack_buf = thread->stack_addr;
|
||||
thread->stack_addr = (void *)(stack_bottom_region_start + MPU_MIN_REGION_SIZE);
|
||||
thread->stack_size = (rt_uint32_t)(stack_top_region_start - stack_bottom_region_start - MPU_MIN_REGION_SIZE);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* This function set the hook, which is invoked on fault exception handling.
|
||||
*
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2023-09-25 tangzz98 the first version
|
||||
*/
|
||||
|
||||
#ifndef __MPU_H__
|
||||
#define __MPU_H__
|
||||
|
||||
#ifdef RT_USING_MEM_PROTECTION
|
||||
|
||||
#include <board.h>
|
||||
|
||||
#define MPU_MIN_REGION_SIZE 32U
|
||||
|
||||
/* MPU attributes for configuring data region permission */
|
||||
/* Privileged No Access, Unprivileged No Access */
|
||||
#define P_NA_U_NA ((0x0 << MPU_RASR_AP_Pos) & MPU_RASR_AP_Msk | MPU_RASR_XN_Msk)
|
||||
/* Privileged Read Write, Unprivileged No Access */
|
||||
#define P_RW_U_NA ((0x1 << MPU_RASR_AP_Pos) & MPU_RASR_AP_Msk | MPU_RASR_XN_Msk)
|
||||
/* Privileged Read Write, Unprivileged Read Only */
|
||||
#define P_RW_U_RO ((0x2 << MPU_RASR_AP_Pos) & MPU_RASR_AP_Msk | MPU_RASR_XN_Msk)
|
||||
/* Privileged Read Write, Unprivileged Read Write */
|
||||
#define P_RW_U_RW ((0x3 << MPU_RASR_AP_Pos) & MPU_RASR_AP_Msk | MPU_RASR_XN_Msk)
|
||||
/* Privileged Read Only, Unprivileged No Access */
|
||||
#define P_RO_U_NA ((0x5 << MPU_RASR_AP_Pos) & MPU_RASR_AP_Msk | MPU_RASR_XN_Msk)
|
||||
/* Privileged Read Only, Unprivileged Read Only */
|
||||
#define P_RO_U_RO ((0x6 << MPU_RASR_AP_Pos) & MPU_RASR_AP_Msk | MPU_RASR_XN_Msk)
|
||||
|
||||
/* MPU attributes for configuring code region permission */
|
||||
/* Privileged Read Write Execute, Unprivileged Read Write Execute */
|
||||
#define P_RWX_U_RWX ((0x3 << MPU_RASR_AP_Pos) & MPU_RASR_AP_Msk)
|
||||
/* Privileged Read Write Execute, Unprivileged Read Execute */
|
||||
#define P_RWX_U_RX ((0x2 << MPU_RASR_AP_Pos) & MPU_RASR_AP_Msk)
|
||||
/* Privileged Read Write Execute, Unprivileged No Access */
|
||||
#define P_RWX_U_NA ((0x1 << MPU_RASR_AP_Pos) & MPU_RASR_AP_Msk)
|
||||
/* Privileged Read Execute, Unprivileged Read Execute */
|
||||
#define P_RX_U_RX ((0x6 << MPU_RASR_AP_Pos) & MPU_RASR_AP_Msk)
|
||||
/* Privileged Read Execute, Unprivileged No Access */
|
||||
#define P_RX_U_NA ((0x5 << MPU_RASR_AP_Pos) & MPU_RASR_AP_Msk)
|
||||
|
||||
/* MPU attributes for configuring memory type, cacheability and shareability */
|
||||
#define STRONGLY_ORDERED_SHAREABLE MPU_RASR_S_Msk
|
||||
#define DEVICE_SHAREABLE (MPU_RASR_B_Msk | MPU_RASR_S_Msk)
|
||||
#define NORMAL_OUTER_INNER_WRITE_THROUGH_SHAREABLE \
|
||||
(MPU_RASR_C_Msk | MPU_RASR_S_Msk)
|
||||
#define NORMAL_OUTER_INNER_WRITE_THROUGH_NON_SHAREABLE MPU_RASR_C_Msk
|
||||
#define NORMAL_OUTER_INNER_WRITE_BACK_SHAREABLE \
|
||||
(MPU_RASR_C_Msk | MPU_RASR_B_Msk | MPU_RASR_S_Msk)
|
||||
#define NORMAL_OUTER_INNER_WRITE_BACK_NON_SHAREABLE \
|
||||
(MPU_RASR_C_Msk | MPU_RASR_B_Msk)
|
||||
#define NORMAL_OUTER_INNER_NON_CACHEABLE_SHAREABLE \
|
||||
((1 << MPU_RASR_TEX_Pos) | MPU_RASR_S_Msk)
|
||||
#define NORMAL_OUTER_INNER_NON_CACHEABLE_NON_SHAREABLE \
|
||||
(1 << MPU_RASR_TEX_Pos)
|
||||
#define NORMAL_OUTER_INNER_WRITE_BACK_WRITE_READ_ALLOCATE_SHAREABLE \
|
||||
((1 << MPU_RASR_TEX_Pos) |\
|
||||
MPU_RASR_C_Msk | MPU_RASR_B_Msk | MPU_RASR_S_Msk)
|
||||
#define NORMAL_OUTER_INNER_WRITE_BACK_WRITE_READ_ALLOCATE_NON_SHAREABLE \
|
||||
((1 << MPU_RASR_TEX_Pos) | MPU_RASR_C_Msk | MPU_RASR_B_Msk)
|
||||
#define DEVICE_NON_SHAREABLE (2 << MPU_RASR_TEX_Pos)
|
||||
#define RESERVED ((2 << MPU_RASR_TEX_Pos) | MPU_RASR_B_Msk)
|
||||
|
||||
typedef struct
|
||||
{
|
||||
rt_thread_t thread; /* Thread that triggered exception */
|
||||
void *addr; /* Address of faulting memory access */
|
||||
rt_mem_region_t region; /* Configurations of the memory region containing the address */
|
||||
rt_uint8_t mmfsr; /* Content of MemManage Status Register */
|
||||
} rt_mem_exception_info_t;
|
||||
|
||||
typedef void (*rt_hw_mpu_exception_hook_t)(rt_mem_exception_info_t *);
|
||||
|
||||
#define RT_ARM_MEM_ATTR(perm, type) ((rt_mem_attr_t){ (perm) | (type)})
|
||||
|
||||
/* Convenient macros for configuring data region attributes with default memory type */
|
||||
#define RT_MEM_REGION_P_NA_U_NA RT_ARM_MEM_ATTR(P_NA_U_NA, RESERVED)
|
||||
#define RT_MEM_REGION_P_RW_U_RW RT_ARM_MEM_ATTR(P_RW_U_RW, RESERVED)
|
||||
#define RT_MEM_REGION_P_RW_U_RO RT_ARM_MEM_ATTR(P_RW_U_RO, RESERVED)
|
||||
#define RT_MEM_REGION_P_RW_U_NA RT_ARM_MEM_ATTR(P_RW_U_NA, RESERVED)
|
||||
#define RT_MEM_REGION_P_RO_U_RO RT_ARM_MEM_ATTR(P_RO_U_RO, RESERVED)
|
||||
#define RT_MEM_REGION_P_RO_U_NA RT_ARM_MEM_ATTR(P_RO_U_NA, RESERVED)
|
||||
|
||||
/* Convenient macros for configuring code region attributes with default memory type */
|
||||
#define RT_MEM_REGION_P_RWX_U_RWX RT_ARM_MEM_ATTR(P_RWX_U_RWX, RESERVED)
|
||||
#define RT_MEM_REGION_P_RWX_U_RX RT_ARM_MEM_ATTR(P_RWX_U_RX, RESERVED)
|
||||
#define RT_MEM_REGION_P_RWX_U_NA RT_ARM_MEM_ATTR(P_RWX_U_NA, RESERVED)
|
||||
#define RT_MEM_REGION_P_RX_U_RX RT_ARM_MEM_ATTR(P_RX_U_RX, RESERVED)
|
||||
#define RT_MEM_REGION_P_RX_U_NA RT_ARM_MEM_ATTR(P_RX_U_NA, RESERVED)
|
||||
|
||||
rt_bool_t rt_hw_mpu_region_valid(rt_mem_region_t *region);
|
||||
rt_err_t rt_hw_mpu_init(void);
|
||||
rt_err_t rt_hw_mpu_add_region(rt_thread_t thread, rt_mem_region_t *region);
|
||||
rt_err_t rt_hw_mpu_delete_region(rt_thread_t thread, rt_mem_region_t *region);
|
||||
rt_err_t rt_hw_mpu_update_region(rt_thread_t thread, rt_mem_region_t *region);
|
||||
rt_err_t rt_hw_mpu_exception_set_hook(rt_hw_mpu_exception_hook_t hook);
|
||||
|
||||
#endif /* RT_USING_MEM_PROTECTION */
|
||||
|
||||
#endif /* __MPU_H__ */
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2023-09-25 tangzz98 the first version
|
||||
*/
|
||||
|
||||
#ifndef __MPUTYPE_H__
|
||||
#define __MPUTYPE_H__
|
||||
|
||||
#ifdef RT_USING_MEM_PROTECTION
|
||||
|
||||
#ifdef RT_USING_HW_STACK_GUARD
|
||||
#define NUM_DYNAMIC_REGIONS (2 + NUM_CONFIGURABLE_REGIONS)
|
||||
#else
|
||||
#define NUM_DYNAMIC_REGIONS (NUM_CONFIGURABLE_REGIONS)
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
rt_uint32_t rasr;
|
||||
} rt_mem_attr_t;
|
||||
|
||||
#endif /* RT_USING_MEM_PROTECTION */
|
||||
|
||||
#endif /* __MPUTYPE_H__ */
|
||||
+10
@@ -233,11 +233,21 @@ static void rt_defunct_execute(void)
|
||||
}
|
||||
|
||||
#ifdef RT_USING_HEAP
|
||||
#ifdef RT_USING_MEM_PROTECTION
|
||||
if (thread->mem_regions != RT_NULL)
|
||||
{
|
||||
RT_KERNEL_FREE(thread->mem_regions);
|
||||
}
|
||||
#endif
|
||||
/* if need free, delete it */
|
||||
if (object_is_systemobject == RT_FALSE)
|
||||
{
|
||||
/* release thread's stack */
|
||||
#ifdef RT_USING_HW_STACK_GUARD
|
||||
RT_KERNEL_FREE(thread->stack_buf);
|
||||
#else
|
||||
RT_KERNEL_FREE(thread->stack_addr);
|
||||
#endif
|
||||
/* delete thread object */
|
||||
rt_object_delete((rt_object_t)thread);
|
||||
}
|
||||
|
||||
@@ -107,6 +107,7 @@ static void _scheduler_stack_check(struct rt_thread *thread)
|
||||
#endif /* not defined ARCH_MM_MMU */
|
||||
#endif /* RT_USING_SMART */
|
||||
|
||||
#ifndef RT_USING_HW_STACK_GUARD
|
||||
#ifdef ARCH_CPU_STACK_GROWS_UPWARD
|
||||
if (*((rt_uint8_t *)((rt_ubase_t)thread->stack_addr + thread->stack_size - 1)) != '#' ||
|
||||
#else
|
||||
@@ -124,14 +125,23 @@ static void _scheduler_stack_check(struct rt_thread *thread)
|
||||
rt_spin_lock(&_spinlock);
|
||||
while (level);
|
||||
}
|
||||
#endif
|
||||
#ifdef ARCH_CPU_STACK_GROWS_UPWARD
|
||||
#ifndef RT_USING_HW_STACK_GUARD
|
||||
else if ((rt_ubase_t)thread->sp > ((rt_ubase_t)thread->stack_addr + thread->stack_size))
|
||||
#else
|
||||
if ((rt_ubase_t)thread->sp > ((rt_ubase_t)thread->stack_addr + thread->stack_size))
|
||||
#endif
|
||||
{
|
||||
rt_kprintf("warning: %s stack is close to the top of stack address.\n",
|
||||
thread->parent.name);
|
||||
}
|
||||
#else
|
||||
#ifndef RT_USING_HW_STACK_GUARD
|
||||
else if ((rt_ubase_t)thread->sp <= ((rt_ubase_t)thread->stack_addr + 32))
|
||||
#else
|
||||
if ((rt_ubase_t)thread->sp <= ((rt_ubase_t)thread->stack_addr + 32))
|
||||
#endif
|
||||
{
|
||||
rt_kprintf("warning: %s stack is close to end of stack address.\n",
|
||||
thread->parent.name);
|
||||
|
||||
@@ -110,6 +110,7 @@ static void _scheduler_stack_check(struct rt_thread *thread)
|
||||
#endif /* not defined ARCH_MM_MMU */
|
||||
#endif /* RT_USING_SMART */
|
||||
|
||||
#ifndef RT_USING_HW_STACK_GUARD
|
||||
#ifdef ARCH_CPU_STACK_GROWS_UPWARD
|
||||
if (*((rt_uint8_t *)((rt_ubase_t)thread->stack_addr + thread->stack_size - 1)) != '#' ||
|
||||
#else
|
||||
@@ -126,14 +127,23 @@ static void _scheduler_stack_check(struct rt_thread *thread)
|
||||
level = rt_hw_interrupt_disable();
|
||||
while (level);
|
||||
}
|
||||
#endif
|
||||
#ifdef ARCH_CPU_STACK_GROWS_UPWARD
|
||||
#ifndef RT_USING_HW_STACK_GUARD
|
||||
else if ((rt_ubase_t)thread->sp > ((rt_ubase_t)thread->stack_addr + thread->stack_size))
|
||||
#else
|
||||
if ((rt_ubase_t)thread->sp > ((rt_ubase_t)thread->stack_addr + thread->stack_size))
|
||||
#endif
|
||||
{
|
||||
rt_kprintf("warning: %s stack is close to the top of stack address.\n",
|
||||
thread->parent.name);
|
||||
}
|
||||
#else
|
||||
#ifndef RT_USING_HW_STACK_GUARD
|
||||
else if ((rt_ubase_t)thread->sp <= ((rt_ubase_t)thread->stack_addr + 32))
|
||||
#else
|
||||
if ((rt_ubase_t)thread->sp <= ((rt_ubase_t)thread->stack_addr + 32))
|
||||
#endif
|
||||
{
|
||||
rt_kprintf("warning: %s stack is close to end of stack address.\n",
|
||||
thread->parent.name);
|
||||
|
||||
@@ -157,6 +157,10 @@ static rt_err_t _thread_init(struct rt_thread *thread,
|
||||
rt_list_init(&(thread->tlist));
|
||||
rt_list_init(&(thread->tlist_schedule));
|
||||
|
||||
#ifdef RT_USING_MEM_PROTECTION
|
||||
thread->mem_regions = RT_NULL;
|
||||
#endif
|
||||
|
||||
#ifdef RT_USING_SMART
|
||||
thread->wakeup.func = RT_NULL;
|
||||
#endif
|
||||
@@ -170,6 +174,9 @@ static rt_err_t _thread_init(struct rt_thread *thread,
|
||||
|
||||
/* init thread stack */
|
||||
rt_memset(thread->stack_addr, '#', thread->stack_size);
|
||||
#ifdef RT_USING_HW_STACK_GUARD
|
||||
rt_hw_stack_guard_init(thread);
|
||||
#endif
|
||||
#ifdef ARCH_CPU_STACK_GROWS_UPWARD
|
||||
thread->sp = (void *)rt_hw_stack_init(thread->entry, thread->parameter,
|
||||
(void *)((char *)thread->stack_addr),
|
||||
|
||||
Reference in New Issue
Block a user