xiuos3/arch/arm/cortex-m4/mpu.c

203 lines
4.4 KiB
C

/*
* Copyright (c) 2020 AIIT XUOS Lab
* XiUOS is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
#include "stm32f4xx.h"
#include "mpu.h"
#include "board.h"
#include <xs_isolation.h>
void MpuEnable(uint32_t option)
{
MPU->CTRL = MPU_ENABLE | option;
__DSB();
__ISB();
return ;
}
void MpuDisable(void)
{
__DMB();
MPU->CTRL = 0;
return;
}
void MpuClearRegion(uint8_t region)
{
__DMB();
MPU->RNR = region;
MPU->RBAR = 0;
MPU->RASR = 0;
return;
}
void MpuClearAllRegion(void)
{
__DMB();
for (int i = 0 ; i < 8 ; i++) {
MPU->RNR = i;
MPU->RBAR = 0;
MPU->RASR = 0;
}
return;
}
int8_t MpuAllocateRegion(void *task_mpu)
{
if(task_mpu == NONE)
return -1;
struct Mpu *mpu = (struct Mpu *)task_mpu;
int8_t free_region;
if ( mpu->count < MPU_MAX_REGION_NUM - 1) {
free_region = mpu->count;
mpu->count ++;
}
else
free_region = -1;
return free_region ;
}
size_t MpuLog2Ceil(size_t size)
{
size_t csize = 0;
while (size > 0) {
size >>= 1;
csize ++;
}
return csize;
}
int8_t MpuAddRegion(void *task_mpu, x_base addr , size_t size , uint8_t type)
{
if(task_mpu == NONE)
return -1;
struct Mpu *mpu = (struct Mpu *)task_mpu;
uint32_t l2size;
int8_t region ;
region = MpuAllocateRegion(mpu);
if (region < 0 ) {
// KPrintf("MPU region full \n");
return region;
}
uint32_t flag = 0;
switch (type)
{
case REGION_TYPE_CODE:
flag = MPU_RASR_AP_RO_RO | MPU_RASR_TEX_0 | MPU_RASR_C | MPU_RASR_S;
break;
case REGION_TYPE_DATA:
flag = MPU_RASR_AP_RW_RW | MPU_RASR_TEX_0 | MPU_RASR_C | MPU_RASR_S ;
break;
case REGION_TYPE_BSS:
flag = MPU_RASR_AP_RW_RW | MPU_RASR_TEX_0 | MPU_RASR_C | MPU_RASR_S ;
break;
case REGION_TYPE_HEAP:
flag = MPU_RASR_AP_RW_RW | MPU_RASR_TEX_0 | MPU_RASR_C | MPU_RASR_S ;
break;
default:
break;
}
l2size = MpuLog2Ceil(size);
addr = MPU_ALIGN(addr , 1 << l2size );
mpu->region[region].config.rasr = flag |MPU_RASR_REGION_SIZE(l2size) | MPU_ENABLE;
mpu->region[region].config.rbar = addr | MPU_RBAR_VALID | region ; //rbar must set region number
return region;
}
x_err_t MpuInit(void **task_mpu)
{
x_base addr_start;
uint32_t addr_size;
uint32_t flag;
if (MPU->TYPE == 0) {
KPrintf("mpu not surport \n");
return -1 ;
}
// KPrintf("mpu init ...\n");
struct Mpu *mpu;
mpu = (struct Mpu *)malloc(sizeof(struct Mpu));
memset(mpu, 0, sizeof(struct Mpu));
if (mpu == NONE)
return -ENOMEMORY;
MpuDisable();
MpuClearAllRegion(); //clear
SCB->SHCSR |= SCB_SHCSR_MEMFAULTENA_Msk;
//user flash
addr_start = USER_TEXT_START;
addr_size = USER_TEXT_END - USER_TEXT_START;
MpuAddRegion(mpu, addr_start , addr_size, REGION_TYPE_CODE);
//user sram
addr_start = USER_SRAM_START;
addr_size = USER_SRAM_END - USER_SRAM_START;
MpuAddRegion(mpu, addr_start , addr_size, REGION_TYPE_HEAP);
*task_mpu = mpu;
return EOK;
}
void MpuFree(void *task_mpu)
{
if(task_mpu == NONE)
return;
MpuDisable();
MpuClearAllRegion(); //clear
x_free(task_mpu);
}
void MpuLoad(void *task_mpu)
{
// KPrintf("MPU load .. \n");
MpuDisable();
MpuClearAllRegion(); //clear
if(task_mpu == NONE)
return;
struct Mpu *mpu = (struct Mpu *)task_mpu;
uint8_t region = 0 ;
#if 0
for ( region = 0 ; region <= mpu->count -1 ; region ++ ){
KPrintf("region: %d\n",region);
KPrintf("rasr 0x%08x \n",mpu->region[region].config.rasr);
KPrintf("rbar 0x%08x \n",mpu->region[region].config.rbar);
KPrintf("\n");
}
#endif
for ( region = 0 ; region <= mpu->count -1 ; region ++ ){
MPU->RNR = region;
MPU->RBAR = mpu->region[region].config.rbar;
MPU->RASR = mpu->region[region].config.rasr;
}
__DSB();
__ISB();
MpuEnable(MPU_PRIVDEFENA);
}