282 lines
6.6 KiB
C
282 lines
6.6 KiB
C
|
/***************************************************************************
|
||
|
*
|
||
|
* Copyright 2015-2019 BES.
|
||
|
* All rights reserved. All unpublished rights reserved.
|
||
|
*
|
||
|
* No part of this work may be used or reproduced in any form or by any
|
||
|
* means, or stored in a database or retrieval system, without prior written
|
||
|
* permission of BES.
|
||
|
*
|
||
|
* Use of this work is governed by a license granted by BES.
|
||
|
* This work contains confidential and proprietary information of
|
||
|
* BES. which is protected by copyright, trade secret,
|
||
|
* trademark and other intellectual property rights.
|
||
|
*
|
||
|
****************************************************************************/
|
||
|
#ifndef __ARM_ARCH_ISA_ARM
|
||
|
|
||
|
#include "mpu.h"
|
||
|
#include "cmsis.h"
|
||
|
#include "hal_trace.h"
|
||
|
|
||
|
#define NORM_MEM_WT_RA_ATTR ARM_MPU_ATTR_MEMORY_(1, 0, 1, 0)
|
||
|
#define NORM_MEM_WB_WA_ATTR ARM_MPU_ATTR_MEMORY_(1, 1, 1, 1)
|
||
|
#define DEV_MEM_ATTR_OUTER ARM_MPU_ATTR_MEMORY_(0, 0, 0, 0)
|
||
|
|
||
|
static void init_mair_attr(void)
|
||
|
{
|
||
|
ARM_MPU_SetMemAttr(MAIR_ATTR_FLASH, ARM_MPU_ATTR(NORM_MEM_WT_RA_ATTR, NORM_MEM_WT_RA_ATTR));
|
||
|
ARM_MPU_SetMemAttr(MAIR_ATTR_INT_SRAM, ARM_MPU_ATTR(NORM_MEM_WT_RA_ATTR, NORM_MEM_WT_RA_ATTR));
|
||
|
ARM_MPU_SetMemAttr(MAIR_ATTR_EXT_SRAM, ARM_MPU_ATTR(NORM_MEM_WB_WA_ATTR, NORM_MEM_WB_WA_ATTR));
|
||
|
ARM_MPU_SetMemAttr(MAIR_ATTR_DEVICE, ARM_MPU_ATTR(DEV_MEM_ATTR_OUTER, ARM_MPU_ATTR_DEVICE_nGnRnE));
|
||
|
}
|
||
|
|
||
|
static int mpu_enable(void)
|
||
|
{
|
||
|
int flags = 0;
|
||
|
|
||
|
if (get_cpu_id()) {
|
||
|
/*
|
||
|
* if cpu is CP, we will use different mpu maps, that is, every map needed by CP will
|
||
|
* be mapped, and the memory is not mapped will issue abort when access
|
||
|
*/
|
||
|
flags = MPU_CTRL_HFNMIENA_Msk;
|
||
|
} else {
|
||
|
/*
|
||
|
* mpu maps use default map designed by arm, that is, if the memory is not mapped,
|
||
|
* the mpu attibutes will use the default setting by ARM.
|
||
|
*/
|
||
|
flags = MPU_CTRL_PRIVDEFENA_Msk;
|
||
|
}
|
||
|
ARM_MPU_Enable(flags);
|
||
|
__DSB();
|
||
|
__ISB();
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int mpu_disable(void)
|
||
|
{
|
||
|
__DMB();
|
||
|
ARM_MPU_Disable();
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int mpu_open(void)
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
if ((MPU->TYPE & MPU_TYPE_DREGION_Msk) == 0) {
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
for (i = 0; i < MPU_ID_QTY; i++) {
|
||
|
ARM_MPU_ClrRegion(i);
|
||
|
}
|
||
|
|
||
|
init_mair_attr();
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int mpu_close(void)
|
||
|
{
|
||
|
ARM_MPU_Disable();
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int mpu_set_armv8(enum MPU_ID_T id, uint32_t addr, uint32_t len,
|
||
|
enum MPU_ATTR_T ap_attr, enum MAIR_ATTR_TYPE_T mem_attr)
|
||
|
{
|
||
|
uint32_t rbar;
|
||
|
uint32_t rlar;
|
||
|
uint8_t xn;
|
||
|
uint8_t ro;
|
||
|
uint32_t lock;
|
||
|
|
||
|
if (id >= MPU_ID_QTY) {
|
||
|
return 2;
|
||
|
}
|
||
|
if (len < 32) {
|
||
|
return 3;
|
||
|
}
|
||
|
if (addr & 0x1F) {
|
||
|
return 4;
|
||
|
}
|
||
|
if (ap_attr >= MPU_ATTR_QTY) {
|
||
|
return 5;
|
||
|
}
|
||
|
|
||
|
if (ap_attr == MPU_ATTR_READ_WRITE_EXEC || ap_attr == MPU_ATTR_READ_EXEC ||
|
||
|
ap_attr == MPU_ATTR_EXEC) {
|
||
|
xn = 0;
|
||
|
} else {
|
||
|
xn = 1;
|
||
|
}
|
||
|
|
||
|
if (ap_attr == MPU_ATTR_READ_WRITE_EXEC || ap_attr == MPU_ATTR_READ_WRITE) {
|
||
|
ro = 0;
|
||
|
} else if (ap_attr == MPU_ATTR_READ_EXEC || ap_attr == MPU_ATTR_READ || ap_attr == MPU_ATTR_EXEC) {
|
||
|
ro = 1;
|
||
|
} else {
|
||
|
// Cannot support no access
|
||
|
return 6;
|
||
|
}
|
||
|
|
||
|
// Sharebility: Outer Shareable
|
||
|
// Non-privilege Access: Enabled
|
||
|
rbar = ARM_MPU_RBAR(addr, 2, ro, 1, xn);
|
||
|
/* rlar = ARM_MPU_RLAR((addr + len - 1), MAIR_ATTR_INT_SRAM); */
|
||
|
rlar = ARM_MPU_RLAR((addr + len - 1), mem_attr);
|
||
|
|
||
|
lock = int_lock();
|
||
|
|
||
|
ARM_MPU_SetRegion(id, rbar, rlar);
|
||
|
int_unlock(lock);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static inline int mpu_fram_protect_armv8(uint32_t fr_start, uint32_t fr_end)
|
||
|
{
|
||
|
uint32_t len = fr_end - fr_start;
|
||
|
int ret;
|
||
|
|
||
|
if ((fr_start % 32 != 0) || (len % 32 != 0))
|
||
|
ASSERT(0, "fr_start %x and len %d must be aligned to 32", fr_start, len);
|
||
|
|
||
|
mpu_disable();
|
||
|
ret = mpu_set_armv8(MPU_ID_FRAM_TEXT1, fr_start, len, MPU_ATTR_EXEC, MAIR_ATTR_INT_SRAM);
|
||
|
mpu_enable();
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
static int mpu_code_region_protect(void)
|
||
|
{
|
||
|
uint32_t code_start = RAMX_BASE;
|
||
|
uint32_t len = RAM_SIZE;
|
||
|
|
||
|
return mpu_set(MPU_ID_CODE, code_start, len, 0, MPU_ATTR_EXEC);
|
||
|
}
|
||
|
|
||
|
extern uint32_t __sram_text_data_start__[];
|
||
|
extern uint32_t __sram_text_end__[];
|
||
|
static int mpu_sram_text_protect(void)
|
||
|
{
|
||
|
int ret;
|
||
|
uint32_t start = (uint32_t)__sram_text_data_start__;
|
||
|
uint32_t end = RAMX_TO_RAM((uint32_t)__sram_text_end__);
|
||
|
uint32_t len = end - start;
|
||
|
|
||
|
TRACE(1,"sram start %x size %x", start, len);
|
||
|
if ((start % 32 != 0) || (len % 32 != 0))
|
||
|
ASSERT(0, "sram start %x and len %d must be aligned to 32", start, len);
|
||
|
|
||
|
ret = mpu_set(MPU_ID_SRAM_TEXT, start, len, 0, MPU_ATTR_READ_EXEC);
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
|
||
|
int mpu_set(enum MPU_ID_T id, uint32_t addr, uint32_t len, int srd_bits,
|
||
|
enum MPU_ATTR_T attr)
|
||
|
{
|
||
|
int ret = -1;
|
||
|
uint32_t lock;
|
||
|
|
||
|
lock = int_lock();
|
||
|
|
||
|
mpu_disable();
|
||
|
ret = mpu_set_armv8(id, addr, len, attr, MAIR_ATTR_INT_SRAM);
|
||
|
mpu_enable();
|
||
|
|
||
|
int_unlock(lock);
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
int mpu_clear(enum MPU_ID_T id)
|
||
|
{
|
||
|
uint32_t lock;
|
||
|
|
||
|
if (id >= MPU_ID_QTY) {
|
||
|
return 2;
|
||
|
}
|
||
|
|
||
|
lock = int_lock();
|
||
|
|
||
|
mpu_disable();
|
||
|
ARM_MPU_ClrRegion(id);
|
||
|
__DSB();
|
||
|
__ISB();
|
||
|
mpu_enable();
|
||
|
|
||
|
int_unlock(lock);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int mpu_null_check_enable(void)
|
||
|
{
|
||
|
return mpu_set(MPU_ID_NULL_POINTER, 0, 0x800, 0, MPU_ATTR_EXEC);
|
||
|
}
|
||
|
|
||
|
extern uint32_t __fast_sram_text_exec_start__[];
|
||
|
extern uint32_t __fast_sram_text_exec_end__[];
|
||
|
|
||
|
static int mpu_fast_ram_protect(void)
|
||
|
{
|
||
|
uint32_t ramx_start = (uint32_t)__fast_sram_text_exec_start__;
|
||
|
uint32_t ramx_end = (uint32_t)__fast_sram_text_exec_end__;
|
||
|
uint32_t ram_start = RAMX_TO_RAM(ramx_start);
|
||
|
uint32_t ram_end = RAMX_TO_RAM(ramx_end);
|
||
|
int ret = -1;
|
||
|
|
||
|
ret = mpu_fram_protect_armv8(ram_start, ram_end);
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
int mpu_setup(void)
|
||
|
{
|
||
|
mpu_null_check_enable();
|
||
|
|
||
|
mpu_code_region_protect();
|
||
|
mpu_sram_text_protect();
|
||
|
|
||
|
mpu_fast_ram_protect();
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int mpu_setup_cp(const mpu_regions_t *mpu_table, uint32_t region_num)
|
||
|
{
|
||
|
int ret;
|
||
|
int i;
|
||
|
uint32_t lock;
|
||
|
|
||
|
ret = mpu_open();
|
||
|
if (ret) {
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
if (region_num > MPU_ID_QTY) {
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
lock = int_lock();
|
||
|
mpu_disable();
|
||
|
for (i = 0; i < region_num; i++) {
|
||
|
const mpu_regions_t *region;
|
||
|
region = &mpu_table[i];
|
||
|
ret = mpu_set_armv8(i, region->addr, region->len, region->ap_attr, region->mem_attr);
|
||
|
if (ret)
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
mpu_enable();
|
||
|
int_unlock(lock);
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
#endif
|