/* * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved. * Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used * to endorse or promote products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "los_mpu.h" #include "los_config.h" #include "los_context.h" #if (LOSCFG_MPU_ENABLE == 1) #define SIZE_4G_BYTE 0x100000000 #define MPU_MAX_REGION_NUM 8 STATIC UINT8 g_regionNumBeUsed[MPU_MAX_REGION_NUM] = {0}; typedef enum { MPU_AP_FORBID_USER_FORBID = 0x0, /* Privileged:No access Unprivileged:No access */ MPU_AP_RW_USER_FORBID = 0x1, /* Privileged:Read/Write Unprivileged:No access */ MPU_AP_RW_USER_RO = 0x2, /* Privileged:Read/Write Unprivileged:Read-only */ MPU_AP_RW_USER_RW = 0x3, /* Privileged:Read/Write Unprivileged:Read/Write */ MPU_AP_NA_USER_NA = 0x4, /* Privileged:UNPREDICTABLE Unprivileged:UNPREDICTABLE */ MPU_AP_RO_USER_FORBID = 0x5, /* Privileged:Read-only Unprivileged:No access */ MPU_AP_RO_USER_RO = 0x6, /* Privileged:Read-only Unprivileged:Read-only */ } MpuApConfig; VOID ArchMpuEnable(UINT32 defaultRegionEnable) { UINT32 intSave = ArchIntLock(); MPU->CTRL = (MPU_CTRL_ENABLE_Msk | ((defaultRegionEnable << MPU_CTRL_PRIVDEFENA_Pos) & MPU_CTRL_PRIVDEFENA_Msk)); SCB->SHCSR |= SCB_SHCSR_MEMFAULTENA_Msk; __DSB(); __ISB(); ArchIntRestore(intSave); } VOID ArchMpuDisable(VOID) { UINT32 intSave = ArchIntLock(); MPU->CTRL = 0; __DSB(); __ISB(); ArchIntRestore(intSave); } STATIC VOID HalMpuRASRAddMemAttr(MPU_CFG_PARA *para, UINT32 *RASR) { BOOL cachable = 0; BOOL buffable = 0; switch (para->memType) { case MPU_MEM_ON_CHIP_ROM: case MPU_MEM_ON_CHIP_RAM: cachable = 1; buffable = 0; break; case MPU_MEM_XIP_PSRAM: cachable = 1; buffable = 1; break; case MPU_MEM_XIP_NOR_FLASH: cachable = 0; buffable = 1; break; default: break; } (*RASR) |= ((cachable << MPU_RASR_C_Pos) | (buffable << MPU_RASR_B_Pos)); } STATIC UINT32 HalMpuEncodeSize(UINT64 size) { UINT32 encodeSize = 0; if (size > SIZE_4G_BYTE) { return 0; } if ((size & 0x1F) != 0) { /* size should aligned to 32 byte at least. */ return 0; } size = (size >> 2); while (size != 0) { if (((size & 1) != 0) && ((size & 0xFFFFFFFE) != 0)) { /* size != 2^x (5 <= x <= 32) 128B - 4GB */ return 0; } size = (size >> 1); encodeSize++; } return encodeSize; } STATIC UINT32 HalMpuEncodeAP(MpuAccessPermission permission) { UINT32 ap; switch (permission) { case MPU_RW_BY_PRIVILEGED_ONLY: ap = MPU_AP_RW_USER_FORBID; break; case MPU_RW_ANY: ap = MPU_AP_RW_USER_RW; break; case MPU_RO_BY_PRIVILEGED_ONLY: ap = MPU_AP_RO_USER_FORBID; break; case MPU_RO_ANY: ap = MPU_AP_RO_USER_RO; break; default: ap = MPU_AP_RW_USER_RW; break; } return ap; } STATIC UINT32 HalMpuGetRASR(UINT32 encodeSize, MPU_CFG_PARA *para) { UINT32 RASR; UINT32 ap; ap = HalMpuEncodeAP(para->permission); RASR = MPU_RASR_ENABLE_Msk; RASR |= ((encodeSize << MPU_RASR_SIZE_Pos) & MPU_RASR_SIZE_Msk); RASR |= ((ap << MPU_RASR_AP_Pos) & MPU_RASR_AP_Msk) | ((para->executable << MPU_RASR_XN_Pos) & MPU_RASR_XN_Msk) | ((para->shareability << MPU_RASR_S_Pos) & MPU_RASR_S_Msk); HalMpuRASRAddMemAttr(para, &RASR); return RASR; } UINT32 ArchMpuSetRegion(UINT32 regionId, MPU_CFG_PARA *para) { UINT32 RASR; UINT32 RBAR; UINT32 RNR; UINT32 encodeSize; UINT32 intSave; UINT64 size; if ((regionId >= MPU_MAX_REGION_NUM) || (para == NULL)) { return LOS_NOK; } if ((MPU_TYPE_DREGION_Msk & MPU->TYPE) == 0) { return LOS_NOK; } RNR = regionId; encodeSize = HalMpuEncodeSize(para->size); if (encodeSize == 0) { return LOS_NOK; } size = para->size - 1; /* size aligned after encode check */ if ((para->baseAddr & size) != 0) { /* base addr should aligned to region size */ return LOS_NOK; } RBAR = para->baseAddr & MPU_RBAR_ADDR_Msk; RASR = HalMpuGetRASR(encodeSize, para); intSave = ArchIntLock(); if (g_regionNumBeUsed[regionId]) { ArchIntRestore(intSave); return LOS_NOK; } MPU->RNR = RNR; MPU->RBAR = RBAR; MPU->RASR = RASR; __DSB(); __ISB(); g_regionNumBeUsed[regionId] = 1; /* Set mpu region used flag */ ArchIntRestore(intSave); return LOS_OK; } UINT32 ArchMpuDisableRegion(UINT32 regionId) { volatile UINT32 type; UINT32 intSave; if (regionId >= MPU_MAX_REGION_NUM) { return LOS_NOK; } intSave = ArchIntLock(); if (!g_regionNumBeUsed[regionId]) { ArchIntRestore(intSave); return LOS_NOK; } type = MPU->TYPE; if ((MPU_TYPE_DREGION_Msk & type) != 0) { MPU->RNR = regionId; MPU->RASR = 0; __DSB(); __ISB(); } g_regionNumBeUsed[regionId] = 0; /* clear mpu region used flag */ ArchIntRestore(intSave); return LOS_OK; } INT32 ArchMpuUnusedRegionGet(VOID) { INT32 id; UINT32 intSave = ArchIntLock(); for (id = 0; id < MPU_MAX_REGION_NUM; id++) { if (!g_regionNumBeUsed[id]) { break; } } ArchIntRestore(intSave); if (id == MPU_MAX_REGION_NUM) { return -1; } else { return id; } } #endif