添加rtthread相关代码
This commit is contained in:
28
riscv/rtthread/components/mprotect/Kconfig
Executable file
28
riscv/rtthread/components/mprotect/Kconfig
Executable file
@@ -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
|
||||
155
riscv/rtthread/components/mprotect/README.md
Executable file
155
riscv/rtthread/components/mprotect/README.md
Executable file
@@ -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);
|
||||
}
|
||||
......
|
||||
}
|
||||
```
|
||||
11
riscv/rtthread/components/mprotect/SConscript
Executable file
11
riscv/rtthread/components/mprotect/SConscript
Executable file
@@ -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));
|
||||
88
riscv/rtthread/components/mprotect/examples/mprotect_example_ro_data.c
Executable file
88
riscv/rtthread/components/mprotect/examples/mprotect_example_ro_data.c
Executable file
@@ -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));
|
||||
BIN
riscv/rtthread/components/mprotect/image/stack_guard.png
Executable file
BIN
riscv/rtthread/components/mprotect/image/stack_guard.png
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 53 KiB |
201
riscv/rtthread/components/mprotect/mprotect.c
Executable file
201
riscv/rtthread/components/mprotect/mprotect.c
Executable file
@@ -0,0 +1,201 @@
|
||||
/*
|
||||
* 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 "mprotect.h"
|
||||
|
||||
#define DBG_ENABLE
|
||||
#define DBG_SECTION_NAME "MEMORY PROTECTION"
|
||||
#define DBG_LEVEL DBG_ERROR
|
||||
#include <rtdbg.h>
|
||||
|
||||
rt_mem_exclusive_region_t exclusive_regions[NUM_EXCLUSIVE_REGIONS] = {};
|
||||
|
||||
rt_mem_region_t *rt_mprotect_find_free_region(rt_thread_t thread)
|
||||
{
|
||||
rt_uint8_t i;
|
||||
rt_mem_region_t *free_region = RT_NULL;
|
||||
if (thread->mem_regions != RT_NULL)
|
||||
{
|
||||
for (i = 0U; i < NUM_DYNAMIC_REGIONS; i++)
|
||||
{
|
||||
if (((rt_mem_region_t *)thread->mem_regions)[i].size == 0)
|
||||
{
|
||||
free_region = &(((rt_mem_region_t *)thread->mem_regions)[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return free_region;
|
||||
}
|
||||
|
||||
rt_mem_region_t *rt_mprotect_find_region(rt_thread_t thread, rt_mem_region_t *region)
|
||||
{
|
||||
rt_uint8_t i;
|
||||
rt_mem_region_t *found_region = RT_NULL;
|
||||
if (thread->mem_regions != RT_NULL)
|
||||
{
|
||||
for (i = 0U; i < NUM_DYNAMIC_REGIONS; i++)
|
||||
{
|
||||
if ((((rt_mem_region_t *)thread->mem_regions)[i].start == region->start) && (((rt_mem_region_t *)thread->mem_regions)[i].size == region->size))
|
||||
{
|
||||
found_region = &(((rt_mem_region_t *)thread->mem_regions)[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return found_region;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function will initialize memory protection.
|
||||
*
|
||||
* @return Return the operation status. When the return value is RT_EOK, the initialization is successful.
|
||||
* When the return value is any other values, it means the initialization failed.
|
||||
*/
|
||||
int rt_mprotect_init(void)
|
||||
{
|
||||
return (int)rt_hw_mpu_init();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief The function will add a memory region configuraiton for a thread.
|
||||
*
|
||||
* @param thread is the thread that the memory region configuration will apply to.
|
||||
*
|
||||
* @param region is the configuration for the memory region to add.
|
||||
*
|
||||
* @return Return the operation status. When the return value is RT_EOK, the operation is successful.
|
||||
* If the return value is any other values, it represents the operation failed.
|
||||
*/
|
||||
rt_err_t rt_mprotect_add_region(rt_thread_t thread, rt_mem_region_t *region)
|
||||
{
|
||||
if (thread == RT_NULL)
|
||||
{
|
||||
thread = rt_thread_self();
|
||||
}
|
||||
if (thread->mem_regions == RT_NULL)
|
||||
{
|
||||
thread->mem_regions = RT_KERNEL_MALLOC(NUM_DYNAMIC_REGIONS * sizeof(rt_mem_region_t));
|
||||
if (thread->mem_regions == RT_NULL)
|
||||
{
|
||||
return RT_ERROR;
|
||||
}
|
||||
rt_memset(thread->mem_regions, 0U, sizeof(rt_mem_region_t ) * NUM_DYNAMIC_REGIONS);
|
||||
}
|
||||
return rt_hw_mpu_add_region(thread, region);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief The function will delete an existing memory region configuraiton for a thread.
|
||||
*
|
||||
* @param thread is the thread that the memory region configuration will apply to.
|
||||
*
|
||||
* @param region is the configuration for the memory region to delete.
|
||||
*
|
||||
* @return Return the operation status. When the return value is RT_EOK, the operation is successful.
|
||||
* If the return value is any other values, it represents the operation failed.
|
||||
*/
|
||||
rt_err_t rt_mprotect_delete_region(rt_thread_t thread, rt_mem_region_t *region)
|
||||
{
|
||||
if (thread == RT_NULL)
|
||||
{
|
||||
thread = rt_thread_self();
|
||||
}
|
||||
return rt_hw_mpu_delete_region(thread, region);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief The function will update an existing memory region configuraiton for a thread.
|
||||
*
|
||||
* @param thread is the thread that the memory region configuration will apply to.
|
||||
*
|
||||
* @param region is the new configuration for the memory region.
|
||||
*
|
||||
* @return Return the operation status. When the return value is RT_EOK, the operation is successful.
|
||||
* If the return value is any other values, it represents the operation failed.
|
||||
*/
|
||||
rt_err_t rt_mprotect_update_region(rt_thread_t thread, rt_mem_region_t *region)
|
||||
{
|
||||
if (thread == RT_NULL)
|
||||
{
|
||||
thread = rt_thread_self();
|
||||
}
|
||||
return rt_hw_mpu_update_region(thread, region);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief The function will add a memory region that is only accessible by the calling thread.
|
||||
*
|
||||
* @param start is the start address of the memory region.
|
||||
*
|
||||
* @param size is the size of the memory region.
|
||||
*
|
||||
* @return Return the operation status. When the return value is RT_EOK, the operation is successful.
|
||||
* If the return value is any other values, it represents the operation failed.
|
||||
*/
|
||||
rt_err_t rt_mprotect_add_exclusive_region(void *start, rt_size_t size)
|
||||
{
|
||||
rt_uint8_t i;
|
||||
rt_mem_exclusive_region_t region;
|
||||
region.owner = rt_thread_self();
|
||||
region.region.start = start;
|
||||
region.region.size = size;
|
||||
region.region.attr = RT_MEM_REGION_P_NA_U_NA;
|
||||
if (rt_hw_mpu_add_region(RT_NULL, (rt_mem_region_t *)(&(region.region))) != RT_EOK)
|
||||
{
|
||||
return RT_ERROR;
|
||||
}
|
||||
rt_enter_critical();
|
||||
for (i = 0; i < NUM_EXCLUSIVE_REGIONS; i++)
|
||||
{
|
||||
if (exclusive_regions[i].owner == RT_NULL)
|
||||
{
|
||||
rt_memcpy(&(exclusive_regions[i]), ®ion, sizeof(rt_mem_exclusive_region_t));
|
||||
rt_exit_critical();
|
||||
return RT_EOK;
|
||||
}
|
||||
}
|
||||
rt_exit_critical();
|
||||
LOG_E("Insufficient regions");
|
||||
return RT_ERROR;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief The function will delete a memory region that is only accessible by the calling thread.
|
||||
* The deleted region will be accessible by other threads.
|
||||
*
|
||||
* @param start is the start address of the memory region.
|
||||
*
|
||||
* @param size is the size of the memory region.
|
||||
*
|
||||
* @return Return the operation status. When the return value is RT_EOK, the operation is successful.
|
||||
* If the return value is any other values, it represents the operation failed.
|
||||
*/
|
||||
rt_err_t rt_mprotect_delete_exclusive_region(void *start, rt_size_t size)
|
||||
{
|
||||
rt_uint8_t i;
|
||||
rt_enter_critical();
|
||||
for (i = 0; i < NUM_EXCLUSIVE_REGIONS; i++)
|
||||
{
|
||||
if (exclusive_regions[i].owner == rt_thread_self() && exclusive_regions[i].region.start == start && exclusive_regions[i].region.size == size)
|
||||
{
|
||||
exclusive_regions[i].owner = RT_NULL;
|
||||
rt_exit_critical();
|
||||
return RT_EOK;
|
||||
}
|
||||
}
|
||||
rt_exit_critical();
|
||||
LOG_E("Region not found");
|
||||
return RT_ERROR;
|
||||
}
|
||||
|
||||
INIT_BOARD_EXPORT(rt_mprotect_init);
|
||||
41
riscv/rtthread/components/mprotect/mprotect.h
Executable file
41
riscv/rtthread/components/mprotect/mprotect.h
Executable file
@@ -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__ */
|
||||
Reference in New Issue
Block a user