summaryrefslogtreecommitdiff
path: root/libcpu
diff options
context:
space:
mode:
authortangzz98 <[email protected]>2023-10-30 08:24:55 -0400
committerGitHub <[email protected]>2023-10-30 08:24:55 -0400
commitacc66c547999ce444b79efccd67625a1af347d5d (patch)
tree316bb953009ba0b0e9a77422d767fd7d82d50466 /libcpu
parent1554888c0b004bac7098e2a92a32603dd26b452c (diff)
实现MPU抽象层 (#8080)
- 为RT-Thread设计MPU抽象层,支持ARMV7-M,ARMV8-M架构,让用户使用MPU检测栈溢出等内存问题,实现线程内存隔离 - 在components/mp目录下提供通用的API,libcpu目录下提供各处理器架构的具体实现 - 在STM32U575 NUCLEO, STM32H75 NUCLEO开发板测试通过
Diffstat (limited to 'libcpu')
-rw-r--r--libcpu/arm/cortex-m33/SConscript3
-rw-r--r--libcpu/arm/cortex-m33/context_gcc.S10
-rw-r--r--libcpu/arm/cortex-m33/cpuport.c25
-rw-r--r--libcpu/arm/cortex-m33/mpu.c355
-rw-r--r--libcpu/arm/cortex-m33/mpu.h99
-rw-r--r--libcpu/arm/cortex-m33/mputype.h34
-rw-r--r--libcpu/arm/cortex-m7/SConscript3
-rw-r--r--libcpu/arm/cortex-m7/context_gcc.S10
-rw-r--r--libcpu/arm/cortex-m7/cpuport.c25
-rw-r--r--libcpu/arm/cortex-m7/mpu.c299
-rw-r--r--libcpu/arm/cortex-m7/mpu.h104
-rw-r--r--libcpu/arm/cortex-m7/mputype.h29
12 files changed, 996 insertions, 0 deletions
diff --git a/libcpu/arm/cortex-m33/SConscript b/libcpu/arm/cortex-m33/SConscript
index b259a94c94..8e6881ce06 100644
--- a/libcpu/arm/cortex-m33/SConscript
+++ b/libcpu/arm/cortex-m33/SConscript
@@ -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')
diff --git a/libcpu/arm/cortex-m33/context_gcc.S b/libcpu/arm/cortex-m33/context_gcc.S
index d1a4921a9d..c0bc32222e 100644
--- a/libcpu/arm/cortex-m33/context_gcc.S
+++ b/libcpu/arm/cortex-m33/context_gcc.S
@@ -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 */
diff --git a/libcpu/arm/cortex-m33/cpuport.c b/libcpu/arm/cortex-m33/cpuport.c
index 749932c609..c7cc7e4ada 100644
--- a/libcpu/arm/cortex-m33/cpuport.c
+++ b/libcpu/arm/cortex-m33/cpuport.c
@@ -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.
*
diff --git a/libcpu/arm/cortex-m33/mpu.c b/libcpu/arm/cortex-m33/mpu.c
new file mode 100644
index 0000000000..bddd60022c
--- /dev/null
+++ b/libcpu/arm/cortex-m33/mpu.c
@@ -0,0 +1,355 @@
+/*
+ * 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 <rtdef.h>
+#include <mprotect.h>
+
+#define DBG_ENABLE
+#define DBG_SECTION_NAME "MEMORY PROTECTION"
+#define DBG_LEVEL DBG_ERROR
+#include <rtdbg.h>
+
+#define MEM_REGION_TO_MPU_INDEX(thread, region) ((((rt_size_t)region - (rt_size_t)(thread->mem_regions)) / sizeof(rt_mem_region_t)) + NUM_STATIC_REGIONS)
+
+extern rt_mem_region_t *rt_mprotect_find_free_region(rt_thread_t thread);
+extern rt_mem_region_t *rt_mprotect_find_region(rt_thread_t thread, rt_mem_region_t *region);
+
+static rt_hw_mpu_exception_hook_t mem_manage_hook = RT_NULL;
+static rt_uint8_t mpu_mair[8U];
+
+rt_weak rt_uint8_t rt_hw_mpu_region_default_attr(rt_mem_region_t *region)
+{
+ static rt_uint8_t default_mem_attr[] =
+ {
+ ARM_MPU_ATTR(ARM_MPU_ATTR_MEMORY_(1U, 0U, 1U, 0U), ARM_MPU_ATTR_MEMORY_(1U, 0U, 1U, 0U)),
+ ARM_MPU_ATTR(ARM_MPU_ATTR_MEMORY_(1U, 1U, 1U, 1U), ARM_MPU_ATTR_MEMORY_(1U, 1U, 1U, 1U)),
+ ARM_MPU_ATTR_DEVICE_nGnRE,
+ ARM_MPU_ATTR(ARM_MPU_ATTR_MEMORY_(1U, 1U, 1U, 1U), ARM_MPU_ATTR_MEMORY_(1U, 1U, 1U, 1U)),
+ ARM_MPU_ATTR(ARM_MPU_ATTR_MEMORY_(1U, 0U, 1U, 0U), ARM_MPU_ATTR_MEMORY_(1U, 0U, 1U, 0U)),
+ ARM_MPU_ATTR_DEVICE_nGnRE,
+ ARM_MPU_ATTR_DEVICE_nGnRE
+ };
+ rt_uint8_t attr = 0U;
+ if ((rt_uint32_t)region->start >= 0xE0000000U)
+ {
+ attr = ((rt_uint32_t)region->start >= 0xE0100000U) ? ARM_MPU_ATTR_DEVICE_nGnRE : ARM_MPU_ATTR_DEVICE_nGnRnE;
+ }
+ else
+ {
+ attr = default_mem_attr[((rt_uint32_t)region->start & ~0xFFFFFFFU) >> 29U];
+ }
+ return attr;
+}
+
+static rt_err_t _mpu_rbar_rlar(rt_mem_region_t *region)
+{
+ rt_uint32_t rlar = 0U;
+ rt_uint8_t mair_attr;
+ rt_uint8_t index;
+ rt_uint8_t attr_indx = 0xFFU;
+ region->attr.rbar = (rt_uint32_t)region->start | (region->attr.rbar & (~MPU_RBAR_BASE_Msk));
+ rlar |= ((rt_uint32_t)region->start + region->size - 1U) & MPU_RLAR_LIMIT_Msk;
+ if (region->attr.mair_attr == RT_ARM_DEFAULT_MAIR_ATTR)
+ {
+ mair_attr = rt_hw_mpu_region_default_attr(region);
+ }
+ else
+ {
+ mair_attr = (rt_uint8_t)region->attr.mair_attr;
+ }
+ for (index = 0U; index < 8U; index++)
+ {
+ if (mpu_mair[index] == RT_ARM_DEFAULT_MAIR_ATTR)
+ {
+ break;
+ }
+ else if (mpu_mair[index] == mair_attr)
+ {
+ attr_indx = index;
+ break;
+ }
+ }
+ /*
+ * Current region's mair_attr does not match any existing region.
+ * All entries in MPU_MAIR are configured.
+ */
+ if (index == 8U)
+ {
+ return RT_ERROR;
+ }
+ /* An existing region has the same mair_attr. */
+ if (attr_indx != 0xFFU)
+ {
+ rlar |= attr_indx & MPU_RLAR_AttrIndx_Msk;
+ }
+ /* Current region's mair_attr does not match any existing region. */
+ else
+ {
+ ARM_MPU_SetMemAttr(index, mair_attr);
+ rlar |= index & MPU_RLAR_AttrIndx_Msk;
+ }
+ rlar |= MPU_RLAR_EN_Msk;
+ region->attr.rlar = rlar;
+
+ return RT_EOK;
+}
+
+rt_bool_t rt_hw_mpu_region_valid(rt_mem_region_t *region)
+{
+ if (region->size < MPU_MIN_REGION_SIZE)
+ {
+ LOG_E("Region size is too small");
+ return RT_FALSE;
+ }
+ if (region->size & (~(MPU_MIN_REGION_SIZE - 1U)) != region->size)
+ {
+ LOG_E("Region size is not a multiple of 32 bytes");
+ return RT_FALSE;
+ }
+ if ((rt_uint32_t)region->start & (MPU_MIN_REGION_SIZE - 1U) != 0U)
+ {
+ LOG_E("Region is not aligned by 32 bytes");
+ return RT_FALSE;
+ }
+ return RT_TRUE;
+}
+
+rt_err_t rt_hw_mpu_init(void)
+{
+ extern rt_mem_region_t static_regions[NUM_STATIC_REGIONS];
+ rt_uint8_t num_mpu_regions;
+ rt_uint8_t num_dynamic_regions;
+ rt_uint8_t index;
+ num_mpu_regions = (rt_uint8_t)((MPU->TYPE & MPU_TYPE_DREGION_Msk) >> MPU_TYPE_DREGION_Pos);
+ if (num_mpu_regions == 0U)
+ {
+ LOG_E("Hardware does not support MPU");
+ return RT_ERROR;
+ }
+ if (num_mpu_regions != NUM_MEM_REGIONS)
+ {
+ LOG_E("Incorrect setting of NUM_MEM_REGIONS");
+ LOG_E("NUM_MEM_REGIONS = %d, hardware support %d MPU regions", NUM_MEM_REGIONS, num_mpu_regions);
+ return RT_ERROR;
+ }
+
+ num_dynamic_regions = NUM_DYNAMIC_REGIONS + NUM_EXCLUSIVE_REGIONS;
+ if (num_dynamic_regions + NUM_STATIC_REGIONS > num_mpu_regions)
+ {
+ LOG_E("Insufficient MPU regions: %d hardware MPU regions", num_mpu_regions);
+#ifdef RT_USING_HW_STACK_GUARD
+ LOG_E("Current configuration requires %d static regions + %d configurable regions + %d exclusive regions + %d stack guard regions", NUM_STATIC_REGIONS, NUM_CONFIGURABLE_REGIONS, NUM_EXCLUSIVE_REGIONS, 1);
+#else
+ LOG_E("Current configuration requires %d static regions + %d configurable regions + %d exclusive regions", NUM_STATIC_REGIONS, NUM_CONFIGURABLE_REGIONS, NUM_EXCLUSIVE_REGIONS);
+#endif
+ return RT_ERROR;
+ }
+ for (index = 0U; index < 8U; index++)
+ {
+ mpu_mair[index] = RT_ARM_DEFAULT_MAIR_ATTR;
+ }
+
+ ARM_MPU_Disable();
+ for (index = 0U; index < NUM_STATIC_REGIONS; index++)
+ {
+ if (rt_hw_mpu_region_valid(&(static_regions[index])) == RT_FALSE)
+ {
+ return RT_ERROR;
+ }
+ if (_mpu_rbar_rlar(&(static_regions[index])) == RT_ERROR)
+ {
+ LOG_E("Number of different mair_attr configurations exceeds 8");
+ return RT_ERROR;
+ }
+ ARM_MPU_SetRegion(index, static_regions[index].attr.rbar, static_regions[index].attr.rlar);
+ }
+ /* Enable background region. */
+ ARM_MPU_Enable(MPU_CTRL_PRIVDEFENA_Msk);
+
+ return RT_EOK;
+}
+
+rt_err_t rt_hw_mpu_add_region(rt_thread_t thread, rt_mem_region_t *region)
+{
+ rt_uint8_t index;
+ rt_mem_region_t *free_region;
+ if (rt_hw_mpu_region_valid(region) == RT_FALSE)
+ {
+ return RT_ERROR;
+ }
+ rt_enter_critical();
+ if (_mpu_rbar_rlar(region) == RT_ERROR)
+ {
+ rt_exit_critical();
+ LOG_E("Number of different mair_attr configurations exceeds 8");
+ return RT_ERROR;
+ }
+ if (thread == RT_NULL)
+ {
+ rt_exit_critical();
+ return RT_EOK;
+ }
+ free_region = rt_mprotect_find_free_region(thread);
+ if (free_region == RT_NULL)
+ {
+ rt_exit_critical();
+ LOG_E("Insufficient regions");
+ return RT_ERROR;
+ }
+ rt_memcpy(free_region, region, sizeof(rt_mem_region_t));
+ if (thread == rt_thread_self())
+ {
+ index = MEM_REGION_TO_MPU_INDEX(thread, free_region);
+ ARM_MPU_SetRegion(index, region->attr.rbar, region->attr.rlar);
+ }
+ rt_exit_critical();
+ return RT_EOK;
+}
+
+rt_err_t rt_hw_mpu_delete_region(rt_thread_t thread, rt_mem_region_t *region)
+{
+ rt_uint8_t index;
+ rt_enter_critical();
+ rt_mem_region_t *found_region = rt_mprotect_find_region(thread, region);
+ if (found_region == RT_NULL)
+ {
+ rt_exit_critical();
+ LOG_E("Region not found");
+ return RT_ERROR;
+ }
+ rt_memset(found_region, 0, sizeof(rt_mem_region_t));
+ if (thread == rt_thread_self())
+ {
+ index = MEM_REGION_TO_MPU_INDEX(thread, found_region);
+ ARM_MPU_ClrRegion(index);
+ }
+ rt_exit_critical();
+ return RT_EOK;
+}
+
+rt_err_t rt_hw_mpu_update_region(rt_thread_t thread, rt_mem_region_t *region)
+{
+ rt_uint8_t index;
+ if (rt_hw_mpu_region_valid(region) == RT_FALSE)
+ {
+ return RT_ERROR;
+ }
+ rt_enter_critical();
+ if (_mpu_rbar_rlar(region) == RT_ERROR)
+ {
+ rt_exit_critical();
+ LOG_E("Number of different mair_attr configurations exceeds 8");
+ return RT_ERROR;
+ }
+ rt_mem_region_t *old_region = rt_mprotect_find_region(thread, region);
+ if (old_region == RT_NULL)
+ {
+ rt_exit_critical();
+ LOG_E("Region not found");
+ return RT_ERROR;
+ }
+ rt_memcpy(old_region, region, sizeof(rt_mem_region_t));
+ if (thread == rt_thread_self())
+ {
+ index = MEM_REGION_TO_MPU_INDEX(thread, old_region);
+ ARM_MPU_SetRegion(index, region->attr.rbar, region->attr.rlar);
+ }
+ rt_exit_critical();
+ return RT_EOK;
+}
+
+rt_err_t rt_hw_mpu_exception_set_hook(rt_hw_mpu_exception_hook_t hook)
+{
+ mem_manage_hook = hook;
+ return RT_EOK;
+}
+
+void rt_hw_mpu_table_switch(rt_thread_t thread)
+{
+ extern rt_mem_exclusive_region_t exclusive_regions[NUM_EXCLUSIVE_REGIONS];
+ rt_uint8_t i;
+ rt_uint8_t index = NUM_STATIC_REGIONS;
+ if (thread->mem_regions != RT_NULL)
+ {
+ for (i = 0U; i < NUM_DYNAMIC_REGIONS; i++)
+ {
+ if (((rt_mem_region_t *)thread->mem_regions)[i].size != 0U)
+ {
+ ARM_MPU_SetRegion(index, ((rt_mem_region_t *)thread->mem_regions)[i].attr.rbar, ((rt_mem_region_t *)thread->mem_regions)[i].attr.rlar);
+ index += 1U;
+ }
+ }
+ }
+ for (i = 0U; i < NUM_EXCLUSIVE_REGIONS; i++)
+ {
+ if ((exclusive_regions[i].owner != RT_NULL) && (exclusive_regions[i].owner != thread))
+ {
+ ARM_MPU_SetRegion(index, exclusive_regions[i].region.attr.rbar, exclusive_regions[i].region.attr.rlar);
+ index += 1U;
+ }
+ }
+ for ( ; index < NUM_MEM_REGIONS; index++)
+ {
+ ARM_MPU_ClrRegion(index);
+ }
+}
+
+void MemManage_Handler(void)
+{
+ extern rt_mem_region_t static_regions[NUM_STATIC_REGIONS];
+ extern rt_mem_exclusive_region_t exclusive_regions[NUM_EXCLUSIVE_REGIONS];
+ rt_mem_exception_info_t info;
+ rt_int8_t i;
+ rt_memset(&info, 0, sizeof(rt_mem_exception_info_t));
+ info.thread = rt_thread_self();
+ if (SCB->CFSR & SCB_CFSR_MMARVALID_Msk)
+ {
+ info.addr = (void *)(SCB->MMFAR);
+ for (i = NUM_EXCLUSIVE_REGIONS - 1; i >= 0; i--)
+ {
+ if ((exclusive_regions[i].owner != RT_NULL) && ((exclusive_regions[i].owner != rt_thread_self())) && ADDR_IN_REGION(info.addr, (rt_mem_region_t *)&(exclusive_regions[i])))
+ {
+ rt_memcpy(&(info.region), &(exclusive_regions[i]), sizeof(rt_mem_region_t));
+ break;
+ }
+ }
+ if (info.region.size == 0U)
+ {
+ if (info.thread->mem_regions != RT_NULL)
+ {
+ for (i = NUM_DYNAMIC_REGIONS - 1; i >= 0; i--)
+ {
+ if ((((rt_mem_region_t *)info.thread->mem_regions)[i].size != 0U) && ADDR_IN_REGION(info.addr, &(((rt_mem_region_t *)info.thread->mem_regions)[i])))
+ {
+ rt_memcpy(&(info.region), &(((rt_mem_region_t *)info.thread->mem_regions)[i]), sizeof(rt_mem_region_t));
+ break;
+ }
+ }
+ }
+ if (info.region.size == 0U)
+ {
+ for (i = NUM_STATIC_REGIONS - 1; i >= 0; i--)
+ {
+ if (ADDR_IN_REGION(info.addr, &(static_regions[i])))
+ {
+ rt_memcpy(&(info.region), &(static_regions[i]), sizeof(rt_mem_region_t));
+ break;
+ }
+ }
+ }
+ }
+ }
+ info.mmfsr = (SCB->CFSR & SCB_CFSR_MEMFAULTSR_Msk) >> SCB_CFSR_MEMFAULTSR_Pos;
+ if (mem_manage_hook != RT_NULL)
+ {
+ mem_manage_hook(&info);
+ }
+ while (1);
+}
diff --git a/libcpu/arm/cortex-m33/mpu.h b/libcpu/arm/cortex-m33/mpu.h
new file mode 100644
index 0000000000..896d0df596
--- /dev/null
+++ b/libcpu/arm/cortex-m33/mpu.h
@@ -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__ */
diff --git a/libcpu/arm/cortex-m33/mputype.h b/libcpu/arm/cortex-m33/mputype.h
new file mode 100644
index 0000000000..728aaa1d78
--- /dev/null
+++ b/libcpu/arm/cortex-m33/mputype.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__ */
diff --git a/libcpu/arm/cortex-m7/SConscript b/libcpu/arm/cortex-m7/SConscript
index b259a94c94..8e6881ce06 100644
--- a/libcpu/arm/cortex-m7/SConscript
+++ b/libcpu/arm/cortex-m7/SConscript
@@ -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')
diff --git a/libcpu/arm/cortex-m7/context_gcc.S b/libcpu/arm/cortex-m7/context_gcc.S
index 8475d33f5f..14fd3711b3 100644
--- a/libcpu/arm/cortex-m7/context_gcc.S
+++ b/libcpu/arm/cortex-m7/context_gcc.S
@@ -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
diff --git a/libcpu/arm/cortex-m7/cpuport.c b/libcpu/arm/cortex-m7/cpuport.c
index d4a14decc9..bcae6b1558 100644
--- a/libcpu/arm/cortex-m7/cpuport.c
+++ b/libcpu/arm/cortex-m7/cpuport.c
@@ -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.
*
diff --git a/libcpu/arm/cortex-m7/mpu.c b/libcpu/arm/cortex-m7/mpu.c
new file mode 100644
index 0000000000..63fde3d352
--- /dev/null
+++ b/libcpu/arm/cortex-m7/mpu.c
@@ -0,0 +1,299 @@
+/*
+ * 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 <rtdef.h>
+#include <mprotect.h>
+
+#define DBG_ENABLE
+#define DBG_SECTION_NAME "MEMORY PROTECTION"
+#define DBG_LEVEL DBG_ERROR
+#include <rtdbg.h>
+
+#define MEM_REGION_TO_MPU_INDEX(thread, region) ((((rt_size_t)region - (rt_size_t)(thread->mem_regions)) / sizeof(rt_mem_region_t)) + NUM_STATIC_REGIONS)
+
+extern rt_mem_region_t *rt_mprotect_find_free_region(rt_thread_t thread);
+extern rt_mem_region_t *rt_mprotect_find_region(rt_thread_t thread, rt_mem_region_t *region);
+
+static rt_hw_mpu_exception_hook_t mem_manage_hook = RT_NULL;
+
+rt_weak rt_uint32_t rt_hw_mpu_region_default_attr(rt_mem_region_t *region)
+{
+ static rt_uint32_t default_mem_attr[] =
+ {
+ NORMAL_OUTER_INNER_WRITE_THROUGH_NON_SHAREABLE,
+ NORMAL_OUTER_INNER_WRITE_BACK_WRITE_READ_ALLOCATE_NON_SHAREABLE,
+ DEVICE_NON_SHAREABLE,
+ NORMAL_OUTER_INNER_WRITE_BACK_WRITE_READ_ALLOCATE_NON_SHAREABLE,
+ NORMAL_OUTER_INNER_WRITE_THROUGH_NON_SHAREABLE,
+ DEVICE_SHAREABLE,
+ DEVICE_NON_SHAREABLE
+ };
+ rt_uint32_t attr = 0U;
+ if ((rt_uint32_t)region->start >= 0xE0000000U)
+ {
+ attr = ((rt_uint32_t)region->start >= 0xE0100000U) ? STRONGLY_ORDERED_SHAREABLE : DEVICE_SHAREABLE;
+ }
+ else
+ {
+ attr = default_mem_attr[((rt_uint32_t)region->start & ~0xFFFFFFFU) >> 29U];
+ }
+ return attr;
+}
+
+static rt_uint32_t _mpu_rasr(rt_mem_region_t *region)
+{
+ rt_uint32_t rasr = 0U;
+ if ((region->attr.rasr & RESERVED) == RESERVED)
+ {
+ rasr |= rt_hw_mpu_region_default_attr(region);
+ rasr |= region->attr.rasr & (MPU_RASR_XN_Msk | MPU_RASR_AP_Msk);
+ }
+ else
+ {
+ rasr |= region->attr.rasr & MPU_RASR_ATTRS_Msk;
+ }
+ rasr |= ((32U - __builtin_clz(region->size - 1U) - 2U + 1U) << MPU_RASR_SIZE_Pos) & MPU_RASR_SIZE_Msk;
+ rasr |= MPU_RASR_ENABLE_Msk;
+ return rasr;
+}
+
+rt_bool_t rt_hw_mpu_region_valid(rt_mem_region_t *region)
+{
+ if (region->size < MPU_MIN_REGION_SIZE)
+ {
+ LOG_E("Region size is too small");
+ return RT_FALSE;
+ }
+ if (region->size & (region->size - 1U) != 0U)
+ {
+ LOG_E("Region size is not power of 2");
+ return RT_FALSE;
+ }
+ if ((rt_uint32_t)region->start & (region->size - 1U) != 0U)
+ {
+ LOG_E("Region is not naturally aligned");
+ return RT_FALSE;
+ }
+ return RT_TRUE;
+}
+
+rt_err_t rt_hw_mpu_init(void)
+{
+ extern rt_mem_region_t static_regions[NUM_STATIC_REGIONS];
+ rt_uint8_t num_mpu_regions;
+ rt_uint8_t num_dynamic_regions;
+ rt_uint8_t index;
+ num_mpu_regions = (rt_uint8_t)((MPU->TYPE & MPU_TYPE_DREGION_Msk) >> MPU_TYPE_DREGION_Pos);
+ if (num_mpu_regions == 0U)
+ {
+ LOG_E("Hardware does not support MPU");
+ return RT_ERROR;
+ }
+ if (num_mpu_regions != NUM_MEM_REGIONS)
+ {
+ LOG_E("Incorrect setting of NUM_MEM_REGIONS");
+ LOG_E("NUM_MEM_REGIONS = %d, hardware support %d MPU regions", NUM_MEM_REGIONS, num_mpu_regions);
+ return RT_ERROR;
+ }
+
+ num_dynamic_regions = NUM_DYNAMIC_REGIONS + NUM_EXCLUSIVE_REGIONS;
+ if (num_dynamic_regions + NUM_STATIC_REGIONS > num_mpu_regions)
+ {
+ LOG_E("Insufficient MPU regions: %d hardware MPU regions", num_mpu_regions);
+#ifdef RT_USING_HW_STACK_GUARD
+ LOG_E("Current configuration requires %d static regions + %d configurable regions + %d exclusive regions + %d stack guard regions", NUM_STATIC_REGIONS, NUM_CONFIGURABLE_REGIONS, NUM_EXCLUSIVE_REGIONS, 2);
+#else
+ LOG_E("Current configuration requires %d static regions + %d configurable regions + %d exclusive regions", NUM_STATIC_REGIONS, NUM_CONFIGURABLE_REGIONS, NUM_EXCLUSIVE_REGIONS);
+#endif
+ return RT_ERROR;
+ }
+
+ ARM_MPU_Disable();
+ for (index = 0U; index < NUM_STATIC_REGIONS; index++)
+ {
+ if (rt_hw_mpu_region_valid(&(static_regions[index])) == RT_FALSE)
+ {
+ return RT_ERROR;
+ }
+ static_regions[index].attr.rasr = _mpu_rasr(&(static_regions[index]));
+ ARM_MPU_SetRegion(ARM_MPU_RBAR(index, (rt_uint32_t)static_regions[index].start), static_regions[index].attr.rasr);
+ }
+ /* Enable background region. */
+ ARM_MPU_Enable(MPU_CTRL_PRIVDEFENA_Msk);
+
+ return RT_EOK;
+}
+
+rt_err_t rt_hw_mpu_add_region(rt_thread_t thread, rt_mem_region_t *region)
+{
+ rt_uint8_t index;
+ rt_mem_region_t *free_region;
+ if (rt_hw_mpu_region_valid(region) == RT_FALSE)
+ {
+ return RT_ERROR;
+ }
+ region->attr.rasr = _mpu_rasr(region);
+ if (thread == RT_NULL)
+ {
+ return RT_EOK;
+ }
+ rt_enter_critical();
+ free_region = rt_mprotect_find_free_region(thread);
+ if (free_region == RT_NULL)
+ {
+ rt_exit_critical();
+ LOG_E("Insufficient regions");
+ return RT_ERROR;
+ }
+ rt_memcpy(free_region, region, sizeof(rt_mem_region_t));
+ if (thread == rt_thread_self())
+ {
+ index = MEM_REGION_TO_MPU_INDEX(thread, free_region);
+ ARM_MPU_SetRegion(ARM_MPU_RBAR(index, (rt_uint32_t)region->start), region->attr.rasr);
+ }
+ rt_exit_critical();
+ return RT_EOK;
+}
+
+rt_err_t rt_hw_mpu_delete_region(rt_thread_t thread, rt_mem_region_t *region)
+{
+ rt_uint8_t index;
+ rt_enter_critical();
+ rt_mem_region_t *found_region = rt_mprotect_find_region(thread, region);
+ if (found_region == RT_NULL)
+ {
+ rt_exit_critical();
+ LOG_E("Region not found");
+ return RT_ERROR;
+ }
+ rt_memset(found_region, 0, sizeof(rt_mem_region_t));
+ if (thread == rt_thread_self())
+ {
+ index = MEM_REGION_TO_MPU_INDEX(thread, found_region);
+ ARM_MPU_ClrRegion(index);
+ }
+ rt_exit_critical();
+ return RT_EOK;
+}
+
+rt_err_t rt_hw_mpu_update_region(rt_thread_t thread, rt_mem_region_t *region)
+{
+ rt_uint8_t index;
+ if (rt_hw_mpu_region_valid(region) == RT_FALSE)
+ {
+ return RT_ERROR;
+ }
+ region->attr.rasr = _mpu_rasr(region);
+ rt_enter_critical();
+ rt_mem_region_t *old_region = rt_mprotect_find_region(thread, region);
+ if (old_region == RT_NULL)
+ {
+ rt_exit_critical();
+ LOG_E("Region not found");
+ return RT_ERROR;
+ }
+ rt_memcpy(old_region, region, sizeof(rt_mem_region_t));
+ if (thread == rt_thread_self())
+ {
+ index = MEM_REGION_TO_MPU_INDEX(thread, old_region);
+ ARM_MPU_SetRegion(ARM_MPU_RBAR(index, (rt_uint32_t)region->start), region->attr.rasr);
+ }
+ rt_exit_critical();
+ return RT_EOK;
+}
+
+rt_err_t rt_hw_mpu_exception_set_hook(rt_hw_mpu_exception_hook_t hook)
+{
+ mem_manage_hook = hook;
+ return RT_EOK;
+}
+
+void rt_hw_mpu_table_switch(rt_thread_t thread)
+{
+ extern rt_mem_exclusive_region_t exclusive_regions[NUM_EXCLUSIVE_REGIONS];
+ rt_uint8_t i;
+ rt_uint8_t index = NUM_STATIC_REGIONS;
+ if (thread->mem_regions != RT_NULL)
+ {
+ for (i = 0U; i < NUM_DYNAMIC_REGIONS; i++)
+ {
+ if (((rt_mem_region_t *)thread->mem_regions)[i].size != 0U)
+ {
+ ARM_MPU_SetRegion(ARM_MPU_RBAR(index, (rt_uint32_t)(((rt_mem_region_t *)thread->mem_regions)[i].start)), ((rt_mem_region_t *)thread->mem_regions)[i].attr.rasr);
+ index += 1U;
+ }
+ }
+ }
+ for (i = 0U; i < NUM_EXCLUSIVE_REGIONS; i++)
+ {
+ if ((exclusive_regions[i].owner != RT_NULL) && (exclusive_regions[i].owner != thread))
+ {
+ ARM_MPU_SetRegion(ARM_MPU_RBAR(index, (rt_uint32_t)(exclusive_regions[i].region.start)), exclusive_regions[i].region.attr.rasr);
+ index += 1U;
+ }
+ }
+ for ( ; index < NUM_MEM_REGIONS; index++)
+ {
+ ARM_MPU_ClrRegion(index);
+ }
+}
+
+void MemManage_Handler(void)
+{
+ extern rt_mem_region_t static_regions[NUM_STATIC_REGIONS];
+ extern rt_mem_exclusive_region_t exclusive_regions[NUM_EXCLUSIVE_REGIONS];
+ rt_mem_exception_info_t info;
+ rt_int8_t i;
+ rt_memset(&info, 0, sizeof(rt_mem_exception_info_t));
+ info.thread = rt_thread_self();
+ if (SCB->CFSR & SCB_CFSR_MMARVALID_Msk)
+ {
+ info.addr = (void *)(SCB->MMFAR);
+ for (i = NUM_EXCLUSIVE_REGIONS - 1; i >= 0; i--)
+ {
+ if ((exclusive_regions[i].owner != RT_NULL) && ((exclusive_regions[i].owner != rt_thread_self())) && ADDR_IN_REGION(info.addr, (rt_mem_region_t *)&(exclusive_regions[i])))
+ {
+ rt_memcpy(&(info.region), &(exclusive_regions[i]), sizeof(rt_mem_region_t));
+ break;
+ }
+ }
+ if (info.region.size == 0U)
+ {
+ if (info.thread->mem_regions != RT_NULL)
+ {
+ for (i = NUM_DYNAMIC_REGIONS - 1; i >= 0; i--)
+ {
+ if ((((rt_mem_region_t *)info.thread->mem_regions)[i].size != 0U) && ADDR_IN_REGION(info.addr, &(((rt_mem_region_t *)info.thread->mem_regions)[i])))
+ {
+ rt_memcpy(&(info.region), &(((rt_mem_region_t *)info.thread->mem_regions)[i]), sizeof(rt_mem_region_t));
+ break;
+ }
+ }
+ }
+ if (info.region.size == 0U)
+ {
+ for (i = NUM_STATIC_REGIONS - 1; i >= 0; i--)
+ {
+ if (ADDR_IN_REGION(info.addr, &(static_regions[i])))
+ {
+ rt_memcpy(&(info.region), &(static_regions[i]), sizeof(rt_mem_region_t));
+ break;
+ }
+ }
+ }
+ }
+ }
+ info.mmfsr = (SCB->CFSR & SCB_CFSR_MEMFAULTSR_Msk) >> SCB_CFSR_MEMFAULTSR_Pos;
+ if (mem_manage_hook != RT_NULL)
+ {
+ mem_manage_hook(&info);
+ }
+ while (1);
+}
diff --git a/libcpu/arm/cortex-m7/mpu.h b/libcpu/arm/cortex-m7/mpu.h
new file mode 100644
index 0000000000..e03d9f32ec
--- /dev/null
+++ b/libcpu/arm/cortex-m7/mpu.h
@@ -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__ */
diff --git a/libcpu/arm/cortex-m7/mputype.h b/libcpu/arm/cortex-m7/mputype.h
new file mode 100644
index 0000000000..bc34b32673
--- /dev/null
+++ b/libcpu/arm/cortex-m7/mputype.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__ */