/*************************************************************************** * * 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