635 lines
20 KiB
C
635 lines
20 KiB
C
/*
|
|
* Copyright (c) CompanyNameMagicTag 2021-2022. All rights reserved.
|
|
*/
|
|
|
|
#include "FreeRTOS.h"
|
|
#include "print.h"
|
|
#include "hwi.h"
|
|
#include "encoding.h"
|
|
#include "print.h"
|
|
#include "pmp.h"
|
|
|
|
#ifdef __cplusplus
|
|
#if __cplusplus
|
|
extern "C" {
|
|
#endif /* __cplusplus */
|
|
#endif /* __cplusplus */
|
|
|
|
static inline uint32_t Ctz32(uint32_t val)
|
|
{
|
|
if (val == 0)
|
|
{
|
|
return 32; /* The number of preamble 0 of zero is 32. */
|
|
}
|
|
|
|
return __builtin_ctz(val);
|
|
}
|
|
|
|
/**
|
|
* Related instructions of registers are specified in register_config.h and they are not explained here.
|
|
*/
|
|
#define PMP_ADDR_ALIGN_SIZE 4
|
|
#define PMP_TOR_MIN_SIZE 4
|
|
#define PMP_NAPOT_MIN_SIZE 8
|
|
|
|
#define GET_PMPREG_NUM(pmpIdx) ((uint8_t)((uint8_t)(pmpIdx) & 0x3) << 3)
|
|
#define CLEAR_PMPCFG_BIT(pmpIdx, cfgValue) ((uint32_t)(cfgValue) & \
|
|
~((0xff << GET_PMPREG_NUM(pmpIdx)) & UINT32_CUT_MASK))
|
|
#define GET_PMPCFG_VALID_VALUE(pmpIdx, cfgOldValue, cfgValue) (((uint32_t)(cfgValue) << GET_PMPREG_NUM(pmpIdx)) | \
|
|
CLEAR_PMPCFG_BIT(pmpIdx, cfgOldValue))
|
|
#define GET_PMPCFG_NUM(pmpIdx) ((uint8_t)(pmpIdx) >> 2)
|
|
|
|
#define GET_SECTL_PMP_NUM(secIndx) ((uint8_t)(secIndx) << 1)
|
|
#define CLEAR_SECTL_BIT(secIdx) (~((0x3U << GET_SECTL_PMP_NUM(secIdx)) & UINT32_CUT_MASK))
|
|
|
|
#define GET_MEMATTRREG_NUM(memAttrIndx) ((uint8_t)(memAttrIndx) >> 3)
|
|
#define GET_MEMATTR_PMP_NUM(memAttrIndx) (((uint8_t)(memAttrIndx) & 0x7) << 2)
|
|
#define CLEAR_MEMATTR_BIT(memAttrIndx) (~((0xfU << GET_MEMATTR_PMP_NUM(memAttrIndx)) & UINT32_CUT_MASK))
|
|
|
|
#define GET_PMP_NAPOT_SIZE(value) (((uint32_t)(value) >> 1) - 1)
|
|
#define SET_PMP_PROT_ADDR(value) ((uint32_t)(value) >> 2)
|
|
#define GET_PMP_PROT_ADDR(value) (((uint32_t)(value) << 2) & UINT32_CUT_MASK)
|
|
|
|
#define GET_NAPOT_PMP_REG_PROT_SIZE(value) (1U << (Ctz32((value) + 1) + 3))
|
|
#define IS_ALIGN(addr, boundary) ((uint32_t)(addr) & ((uint32_t)(boundary) - 1))
|
|
|
|
uint64_t g_pmpMaxAddr = PMP_MAX_ADDRESS;
|
|
uint64_t g_pmpMinAddr = PMP_MIN_ADDRESS;
|
|
static BaseType_t g_pmpTopFlag = pdFALSE;
|
|
|
|
/*****************************************************************************
|
|
Function : PmpCfgRead
|
|
Description: Read pmp config register.
|
|
Input : number -- pmp config serial number.
|
|
Return : Pmp config register value.
|
|
*****************************************************************************/
|
|
static uint8_t PmpCfgRead(uint8_t number)
|
|
{
|
|
uint32_t pmpCfgRegVal = 0;
|
|
|
|
switch (GET_PMPCFG_NUM(number))
|
|
{
|
|
case 0: /* PMP memory R/W/X property sets register number register 0 */
|
|
pmpCfgRegVal = read_csr(pmpcfg0);
|
|
break;
|
|
case 1: /* PMP memory R/W/X property sets register number register 1 */
|
|
pmpCfgRegVal = read_csr(pmpcfg1);
|
|
break;
|
|
case 2: /* PMP memory R/W/X property sets register number register 2 */
|
|
pmpCfgRegVal = read_csr(pmpcfg2);
|
|
break;
|
|
case 3: /* PMP memory R/W/X property sets register number register 3 */
|
|
pmpCfgRegVal = read_csr(pmpcfg3);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return (uint8_t)(pmpCfgRegVal >> GET_PMPREG_NUM(number)) & UINT8_CUT_MASK;
|
|
}
|
|
|
|
static uint32_t PmpIsLocked(uint8_t number)
|
|
{
|
|
uint8_t pmpCfg;
|
|
|
|
pmpCfg = PmpCfgRead(number);
|
|
if (pmpCfg & PMP_RGN_LOCK)
|
|
{
|
|
return pdTRUE;
|
|
}
|
|
return pdFALSE;
|
|
}
|
|
|
|
static uint32_t PmpAddrRead(uint8_t pmpAddrIdx)
|
|
{
|
|
switch (pmpAddrIdx)
|
|
{
|
|
case 0: /* Pmpaddr registers numbered 0 */
|
|
return read_csr(pmpaddr0);
|
|
case 1: /* Pmpaddr registers numbered 1 */
|
|
return read_csr(pmpaddr1);
|
|
case 2: /* Pmpaddr registers numbered 2 */
|
|
return read_csr(pmpaddr2);
|
|
case 3: /* Pmpaddr registers numbered 3 */
|
|
return read_csr(pmpaddr3);
|
|
case 4: /* Pmpaddr registers numbered 4 */
|
|
return read_csr(pmpaddr4);
|
|
case 5: /* Pmpaddr registers numbered 5 */
|
|
return read_csr(pmpaddr5);
|
|
case 6: /* Pmpaddr registers numbered 6 */
|
|
return read_csr(pmpaddr6);
|
|
case 7: /* Pmpaddr registers numbered 7 */
|
|
return read_csr(pmpaddr7);
|
|
case 8: /* Pmpaddr registers numbered 8 */
|
|
return read_csr(pmpaddr8);
|
|
case 9: /* Pmpaddr registers numbered 9 */
|
|
return read_csr(pmpaddr9);
|
|
case 10: /* Pmpaddr registers numbered 10 */
|
|
return read_csr(pmpaddr10);
|
|
case 11: /* Pmpaddr registers numbered 11 */
|
|
return read_csr(pmpaddr11);
|
|
case 12: /* Pmpaddr registers numbered 12 */
|
|
return read_csr(pmpaddr12);
|
|
case 13: /* Pmpaddr registers numbered 13 */
|
|
return read_csr(pmpaddr13);
|
|
case 14: /* Pmpaddr registers numbered 14 */
|
|
return read_csr(pmpaddr14);
|
|
case 15: /* Pmpaddr registers numbered 15 */
|
|
return read_csr(pmpaddr15);
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static void PmpAddrWrite(uint8_t pmpAddrIdx, uint32_t pmpAddrVal)
|
|
{
|
|
switch (pmpAddrIdx)
|
|
{
|
|
case 0: /* Pmpaddr registers numbered 0 */
|
|
write_csr(pmpaddr0, pmpAddrVal);
|
|
break;
|
|
case 1: /* Pmpaddr registers numbered 1 */
|
|
write_csr(pmpaddr1, pmpAddrVal);
|
|
break;
|
|
case 2: /* Pmpaddr registers numbered 2 */
|
|
write_csr(pmpaddr2, pmpAddrVal);
|
|
break;
|
|
case 3: /* Pmpaddr registers numbered 3 */
|
|
write_csr(pmpaddr3, pmpAddrVal);
|
|
break;
|
|
case 4: /* Pmpaddr registers numbered 4 */
|
|
write_csr(pmpaddr4, pmpAddrVal);
|
|
break;
|
|
case 5: /* Pmpaddr registers numbered 5 */
|
|
write_csr(pmpaddr5, pmpAddrVal);
|
|
break;
|
|
case 6: /* Pmpaddr registers numbered 6 */
|
|
write_csr(pmpaddr6, pmpAddrVal);
|
|
break;
|
|
case 7: /* Pmpaddr registers numbered 7 */
|
|
write_csr(pmpaddr7, pmpAddrVal);
|
|
break;
|
|
case 8: /* Pmpaddr registers numbered 8 */
|
|
write_csr(pmpaddr8, pmpAddrVal);
|
|
break;
|
|
case 9: /* Pmpaddr registers numbered 9 */
|
|
write_csr(pmpaddr9, pmpAddrVal);
|
|
break;
|
|
case 10: /* Pmpaddr registers numbered 10 */
|
|
write_csr(pmpaddr10, pmpAddrVal);
|
|
break;
|
|
case 11: /* Pmpaddr registers numbered 11 */
|
|
write_csr(pmpaddr11, pmpAddrVal);
|
|
break;
|
|
case 12: /* Pmpaddr registers numbered 12 */
|
|
write_csr(pmpaddr12, pmpAddrVal);
|
|
break;
|
|
case 13: /* Pmpaddr registers numbered 13 */
|
|
write_csr(pmpaddr13, pmpAddrVal);
|
|
break;
|
|
case 14: /* Pmpaddr registers numbered 14 */
|
|
write_csr(pmpaddr14, pmpAddrVal);
|
|
break;
|
|
case 15: /* Pmpaddr registers numbered 15 */
|
|
write_csr(pmpaddr15, pmpAddrVal);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
static uint32_t PmpTorLowerBoundRead(uint8_t pmpAddrIdx)
|
|
{
|
|
uint8_t pmpAddrMatch;
|
|
uint32_t pmpPreAddrVal;
|
|
uint32_t pmpPreSize;
|
|
uint32_t pmpPreBaseAddr;
|
|
uint32_t napotSize;
|
|
|
|
if (pmpAddrIdx == 0)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
pmpAddrMatch = PmpCfgRead(pmpAddrIdx - 1) & PMP_RGN_ADDR_MATCH_MASK;
|
|
switch (pmpAddrMatch)
|
|
{
|
|
case PMP_RGN_ADDR_MATCH_OFF:
|
|
/* FALLTHROUGH */
|
|
case PMP_RGN_ADDR_MATCH_TOR:
|
|
pmpPreAddrVal = PmpAddrRead(pmpAddrIdx - 1);
|
|
return GET_PMP_PROT_ADDR(pmpPreAddrVal);
|
|
case PMP_RGN_ADDR_MATCH_NAPOT:
|
|
{
|
|
pmpPreAddrVal = PmpAddrRead(pmpAddrIdx - 1);
|
|
PRINTK(ePrintkErr, "pre region addr value = 0x%x\n", pmpPreAddrVal);
|
|
pmpPreSize = GET_NAPOT_PMP_REG_PROT_SIZE(pmpPreAddrVal);
|
|
PRINTK(ePrintkErr, "pre region size = 0x%x\n", pmpPreSize);
|
|
napotSize = GET_PMP_NAPOT_SIZE(pmpPreSize); /* get the pre-region size */
|
|
pmpPreBaseAddr = GET_PMP_PROT_ADDR(pmpPreAddrVal) & (~napotSize); /* get the pre-region base address */
|
|
PRINTK(ePrintkErr, "pre region base address = 0x%x\n", pmpPreBaseAddr);
|
|
/* get the pre-region end address, i.e. the lower bound of this TOR region */
|
|
return (pmpPreBaseAddr + pmpPreSize);
|
|
}
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static uint32_t PmpCheckNextPmpEntry(const PMP_ENTRY_INFO *pmpInfo)
|
|
{
|
|
uint8_t pmpcfgMode = PmpCfgRead(pmpInfo->ucNumber) & PMP_RGN_ADDR_MATCH_MASK;
|
|
if ((pmpcfgMode == PMP_RGN_ADDR_MATCH_OFF) || (pmpcfgMode == PMP_RGN_ADDR_MATCH_TOR))
|
|
{
|
|
if (pmpInfo->ucAddressMatch == PMP_RGN_ADDR_MATCH_NAPOT)
|
|
{
|
|
return errPMP_TOR_INVALID_MATCH_MODE;
|
|
}
|
|
}
|
|
else if (pmpcfgMode == PMP_RGN_ADDR_MATCH_NAPOT)
|
|
{
|
|
if (pmpInfo->ucAddressMatch != PMP_RGN_ADDR_MATCH_NAPOT)
|
|
{
|
|
return errPMP_NAPOT_INVALID_MATCH_MODE;
|
|
}
|
|
}
|
|
|
|
return pdPASS;
|
|
}
|
|
|
|
static uint32_t PmpBaseAddrAndRegionSizeCheck(uint8_t number,
|
|
uint8_t addrMatch,
|
|
const char baseAddr,
|
|
uint32_t regionSize )
|
|
{
|
|
uint32_t prevAddr;
|
|
/* Base address is not in the range of [PMP_MIN_ADDRESS, PMP_MAX_ADDRESS] */
|
|
if ((baseAddr < g_pmpMinAddr) || (baseAddr > g_pmpMaxAddr))
|
|
{
|
|
return errPMP_BASE_ADDRESS_NOT_IN_RANGE;
|
|
}
|
|
|
|
/* the PMP region start address and end address must be 4 aligned. */
|
|
if (IS_ALIGN(baseAddr, PMP_ADDR_ALIGN_SIZE) != 0)
|
|
{
|
|
return errPMP_INVALID_BASE_ADDRESS;
|
|
}
|
|
|
|
if (addrMatch == PMP_RGN_ADDR_MATCH_NAPOT)
|
|
{
|
|
if ((regionSize < PMP_NAPOT_MIN_SIZE) && ((baseAddr + regionSize) > g_pmpMaxAddr))
|
|
{
|
|
return errPMP_NAPOT_ENCODING_NON_MATCHED;
|
|
}
|
|
|
|
/* check the naturally aligned power-of-2 regions (NAPOT) size */
|
|
if (((regionSize - 1) & regionSize) != 0)
|
|
{
|
|
return errPMP_INVALID_CAPACITY;
|
|
}
|
|
|
|
/* the NAPOT type and size should be matched in NAPOT range encoding. */
|
|
if (((regionSize - 1) & baseAddr) != 0)
|
|
{
|
|
return errPMP_NAPOT_ENCODING_NON_MATCHED;
|
|
}
|
|
}
|
|
|
|
/* check TOR base address equals to the pre-region end address */
|
|
if (addrMatch == PMP_RGN_ADDR_MATCH_TOR)
|
|
{
|
|
prevAddr = PmpTorLowerBoundRead(number);
|
|
if (baseAddr < (prevAddr + PMP_TOR_MIN_SIZE))
|
|
{
|
|
return errPMP_TOR_LOWER_BOUND_NONMATCHED;
|
|
}
|
|
}
|
|
|
|
return pdPASS;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Function : PmpCheckParame
|
|
Description: check parame
|
|
Input : pmpInfo -- PMP info
|
|
Return : Error Information or pdPASS
|
|
*****************************************************************************/
|
|
static uint32_t PmpAttrAndSectlCheck(PMP_ENTRY_INFO *pmpInfo)
|
|
{
|
|
if ((pmpInfo->memAttr != MEM_ATTR_DEV_NON_BUF) && (pmpInfo->memAttr != MEM_ATTR_NORM_NON_CA_NON_BUF) &&
|
|
(pmpInfo->memAttr != MEM_ATTR_NORM_NON_CA_BUF) && (pmpInfo->memAttr != MEM_ATTR_WB_RD_ALLOC) &&
|
|
(pmpInfo->memAttr != MEM_ATTR_WB_WR_ALLOC) && (pmpInfo->memAttr != MEM_ATTR_WB_RW_ALLOC))
|
|
{
|
|
return errPMP_ATTR_INVALID;
|
|
}
|
|
|
|
if ((pmpInfo->seCtl != SEC_CONTRLO_SECURE_NOMMU) && (pmpInfo->seCtl != SEC_CONTRLO_NOSECURE_NOMMU) &&
|
|
(pmpInfo->seCtl != SEC_CONTRLO_SECURE_MMU) && (pmpInfo->seCtl != SEC_CONTRLO_NOSECURE_MMU))
|
|
{
|
|
return errPMP_SECTL_INVALID;
|
|
}
|
|
return pdPASS;
|
|
}
|
|
|
|
static uint32_t PmpCheckParame(PMP_ENTRY_INFO *pmpInfo)
|
|
{
|
|
uint32_t ret;
|
|
uint8_t pmpcfgNext;
|
|
|
|
if (pmpInfo == NULL)
|
|
{
|
|
return errPMP_PTR_NULL;
|
|
}
|
|
|
|
if (pmpInfo->ucAddressMatch == PMP_RGN_ADDR_MATCH_NA4)
|
|
{
|
|
return errPMP_INVALID_MATCH;
|
|
}
|
|
|
|
/* Number exceeds the maximum value supported by PMO */
|
|
if (pmpInfo->ucNumber >= PMP_MAX_SUPPORT)
|
|
{
|
|
return errPMP_INVALID_NUMBER;
|
|
}
|
|
|
|
/* Check the entry whether locked or not */
|
|
if (PmpIsLocked(pmpInfo->ucNumber) == pdTRUE)
|
|
{
|
|
return errPMP_ENTRY_IS_LOCKED;
|
|
}
|
|
|
|
g_pmpTopFlag = pdFALSE;
|
|
/* If address matching mode equals to TOR, check the next PMP entry */
|
|
if ((pmpInfo->ucNumber + 1) < PMP_MAX_SUPPORT)
|
|
{
|
|
pmpcfgNext = PmpCfgRead(pmpInfo->ucNumber + 1);
|
|
if ((pmpcfgNext & PMP_RGN_LOCK) && ((pmpcfgNext & PMP_RGN_ADDR_MATCH_MASK) == PMP_RGN_ADDR_MATCH_TOR))
|
|
{
|
|
ret = PmpCheckNextPmpEntry(pmpInfo);
|
|
if (ret != pdPASS)
|
|
{
|
|
return ret;
|
|
}
|
|
g_pmpTopFlag = pdTRUE;
|
|
}
|
|
}
|
|
|
|
if (g_pmpTopFlag != pdTRUE)
|
|
{
|
|
ret = PmpBaseAddrAndRegionSizeCheck(pmpInfo->ucNumber, pmpInfo->ucAddressMatch,
|
|
pmpInfo->uwBaseAddress, pmpInfo->uwRegionSize);
|
|
if (ret != pdPASS)
|
|
{
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
if (pmpInfo->ucAddressMatch != PMP_RGN_ADDR_MATCH_OFF)
|
|
{
|
|
return PmpAttrAndSectlCheck(pmpInfo);
|
|
}
|
|
else
|
|
{
|
|
pmpInfo->memAttr = MEM_ATTR_DEV_NON_BUF;
|
|
pmpInfo->seCtl = SEC_CONTRLO_SECURE_NOMMU;
|
|
}
|
|
return pdPASS;
|
|
}
|
|
|
|
static uint8_t PmpAccpGet(PmpAccInfo accPermission)
|
|
{
|
|
uint8_t pmpCfgAcc = 0;
|
|
|
|
if (accPermission.readAcc == E_MEM_RD_ACC_RD)
|
|
{
|
|
pmpCfgAcc |= (1 << PMPCFG_R_BIT);
|
|
}
|
|
|
|
if (accPermission.writeAcc == E_MEM_WR_ACC_WR)
|
|
{
|
|
pmpCfgAcc |= (1 << PMPCFG_W_BIT);
|
|
}
|
|
|
|
if (accPermission.excuteAcc == E_MEM_EX_ACC_EX)
|
|
{
|
|
pmpCfgAcc |= (1 << PMPCFG_X_BIT);
|
|
}
|
|
return pmpCfgAcc;
|
|
}
|
|
|
|
static void PmpCfgWrite(uint8_t pmpCfgIdx, uint8_t pmpCfgVal)
|
|
{
|
|
uint32_t cfgVal;
|
|
|
|
switch (GET_PMPCFG_NUM(pmpCfgIdx))
|
|
{
|
|
case 0: /* PMP memory R/W/X property sets register number register 0 */
|
|
cfgVal = read_csr(pmpcfg0);
|
|
cfgVal = GET_PMPCFG_VALID_VALUE(pmpCfgIdx, cfgVal, pmpCfgVal);
|
|
write_csr(pmpcfg0, cfgVal);
|
|
break;
|
|
case 1: /* PMP memory R/W/X property sets register number register 1 */
|
|
cfgVal = read_csr(pmpcfg1);
|
|
cfgVal = GET_PMPCFG_VALID_VALUE(pmpCfgIdx, cfgVal, pmpCfgVal);
|
|
write_csr(pmpcfg1, cfgVal);
|
|
break;
|
|
case 2: /* PMP memory R/W/X property sets register number register 2 */
|
|
cfgVal = read_csr(pmpcfg2);
|
|
cfgVal = GET_PMPCFG_VALID_VALUE(pmpCfgIdx, cfgVal, pmpCfgVal);
|
|
write_csr(pmpcfg2, cfgVal);
|
|
break;
|
|
case 3: /* PMP memory R/W/X property sets register number register 3 */
|
|
cfgVal = read_csr(pmpcfg3);
|
|
cfgVal = GET_PMPCFG_VALID_VALUE(pmpCfgIdx, cfgVal, pmpCfgVal);
|
|
write_csr(pmpcfg3, cfgVal);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Function : PmpNapotAddrGet
|
|
Description : get the pmp address (NAPOT) of the physical memory protection entry
|
|
Input : base -- base addr
|
|
Input : size -- protection size
|
|
Output : pmp address (NAPOT)
|
|
Return : OS_SUCCESS
|
|
*****************************************************************************/
|
|
static uint32_t PmpNapotAddrGet(uint32_t base, uint32_t size)
|
|
{
|
|
return (uint32_t)SET_PMP_PROT_ADDR(base + GET_PMP_NAPOT_SIZE(size));
|
|
}
|
|
|
|
static void PmpMemattrWrite(uint8_t pmpMemAttrIdx, PmpMemAttrInfo pmpMemAttrVal)
|
|
{
|
|
uint32_t memAttrVal;
|
|
|
|
if (GET_MEMATTRREG_NUM(pmpMemAttrIdx) == 0)
|
|
{
|
|
memAttrVal = read_custom_csr(MEMATTRL);
|
|
memAttrVal &= CLEAR_MEMATTR_BIT(pmpMemAttrIdx);
|
|
memAttrVal |= ((uint32_t)pmpMemAttrVal << GET_MEMATTR_PMP_NUM(pmpMemAttrIdx));
|
|
write_custom_csr(MEMATTRL, memAttrVal);
|
|
}
|
|
else
|
|
{
|
|
memAttrVal = read_custom_csr(MEMATTRH);
|
|
memAttrVal &= CLEAR_MEMATTR_BIT(pmpMemAttrIdx);
|
|
memAttrVal |= ((uint32_t)pmpMemAttrVal << GET_MEMATTR_PMP_NUM(pmpMemAttrIdx));
|
|
write_custom_csr(MEMATTRH, memAttrVal);
|
|
}
|
|
}
|
|
|
|
static void PmpSectlWrite(uint8_t pmpSecIdx, uint8_t pmpCfgVal)
|
|
{
|
|
uint32_t sectl;
|
|
|
|
sectl = read_custom_csr(SECTL);
|
|
sectl &= CLEAR_SECTL_BIT(pmpSecIdx);
|
|
sectl |= (pmpCfgVal << GET_SECTL_PMP_NUM(pmpSecIdx));
|
|
write_custom_csr(SECTL, sectl);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Function : ulArchRegionDisable
|
|
Description: disable region by number
|
|
Input : number -- mpu region number want to disable
|
|
Return : pdPASS or Error Information
|
|
*****************************************************************************/
|
|
uint32_t ulArchRegionDisable(uint8_t number)
|
|
{
|
|
uint32_t intSave;
|
|
if (number >= PMP_MAX_SUPPORT)
|
|
{
|
|
return errPMP_INVALID_NUMBER;
|
|
}
|
|
|
|
if (PmpIsLocked(number) == pdTRUE)
|
|
{
|
|
return errPMP_ENTRY_IS_LOCKED;
|
|
}
|
|
|
|
intSave = uxHwiLock();
|
|
|
|
PmpSectlWrite(number, SEC_CONTRLO_SECURE_NOMMU);
|
|
|
|
PmpCfgWrite(number, PMP_RGN_ADDR_MATCH_OFF);
|
|
|
|
vHwiRestore(intSave);
|
|
|
|
return pdPASS;
|
|
}
|
|
|
|
static void PmpRegionConfig(const PMP_ENTRY_INFO *pmpInfo)
|
|
{
|
|
uint8_t pmpXCfg = 0;
|
|
uint32_t pmpXAddr = UINT32_CUT_MASK;
|
|
|
|
switch ((pmpInfo->ucAddressMatch & PMP_RGN_ADDR_MATCH_MASK))
|
|
{
|
|
case PMP_RGN_ADDR_MATCH_OFF:
|
|
pmpXAddr = SET_PMP_PROT_ADDR(pmpInfo->uwBaseAddress);
|
|
break;
|
|
case PMP_RGN_ADDR_MATCH_NAPOT:
|
|
pmpXAddr = PmpNapotAddrGet(pmpInfo->uwBaseAddress, pmpInfo->uwRegionSize);
|
|
break;
|
|
case PMP_RGN_ADDR_MATCH_TOR:
|
|
pmpXAddr = SET_PMP_PROT_ADDR(pmpInfo->uwBaseAddress);
|
|
break;
|
|
case PMP_RGN_ADDR_MATCH_NA4:
|
|
/* The PMP entry size granularity must be the multiple of cache line size, not support yet! */
|
|
return;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
/* write pmp address register */
|
|
if (g_pmpTopFlag != pdTRUE)
|
|
{
|
|
PmpAddrWrite(pmpInfo->ucNumber, pmpXAddr);
|
|
}
|
|
|
|
/* write pmp memattr/memattrh register */
|
|
PmpMemattrWrite(pmpInfo->ucNumber, pmpInfo->memAttr);
|
|
|
|
/* write pmp sectl register */
|
|
PmpSectlWrite(pmpInfo->ucNumber, pmpInfo->seCtl);
|
|
|
|
/* write pmp cfg register */
|
|
if (pmpInfo->ucAddressMatch != PMP_RGN_ADDR_MATCH_OFF)
|
|
{
|
|
pmpXCfg |= (pmpInfo->ucAddressMatch) | (PmpAccpGet(pmpInfo->accPermission));
|
|
}
|
|
if (pmpInfo->bLocked)
|
|
{
|
|
pmpXCfg |= PMP_RGN_LOCK;
|
|
}
|
|
|
|
PmpCfgWrite(pmpInfo->ucNumber, pmpXCfg);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Function : ulArchGetSectl
|
|
Description: Get Sectl region
|
|
Input : None
|
|
Return : Sectl register value
|
|
*****************************************************************************/
|
|
uint32_t ulArchGetSectl(void)
|
|
{
|
|
return read_custom_csr(SECTL);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Function : ulArchProtectionRegionSet
|
|
Description: set protection region
|
|
Input : pmpInfo --- PMP parameters to be set.
|
|
The base address must be in the range of RAM
|
|
Return : pdPASS or the index of pmpInfo which set up failed
|
|
*****************************************************************************/
|
|
uint32_t ulArchProtectionRegionSet(PMP_ENTRY_INFO *pmpInfo)
|
|
{
|
|
uint32_t ret;
|
|
uint32_t intSave;
|
|
PMP_ENTRY_INFO *pmpConfig = NULL;
|
|
|
|
intSave = uxHwiLock();
|
|
|
|
pmpConfig = pmpInfo;
|
|
ret = PmpCheckParame(pmpConfig);
|
|
if (ret != pdPASS)
|
|
{
|
|
PRINTK(ePrintkErr, "set protection region error, ret: [0x%x]\n", ret);
|
|
vHwiRestore(intSave);
|
|
return ret;
|
|
}
|
|
|
|
PmpRegionConfig(pmpConfig);
|
|
vHwiRestore(intSave);
|
|
|
|
return pdPASS;
|
|
}
|
|
|
|
uint32_t ulArchProtectionUnitInit(uint64_t minAddr, uint64_t maxAddr)
|
|
{
|
|
uint32_t intSave;
|
|
intSave = uxHwiLock();
|
|
|
|
g_pmpMinAddr = minAddr;
|
|
g_pmpMaxAddr = maxAddr;
|
|
|
|
vHwiRestore(intSave);
|
|
return pdPASS;
|
|
}
|
|
|
|
void vArchPmpAddrWrite(uint8_t pmpAddrIdx, uint32_t pmpAddrVal)
|
|
{
|
|
PmpAddrWrite(pmpAddrIdx, SET_PMP_PROT_ADDR(pmpAddrVal));
|
|
}
|
|
|
|
#ifdef __cplusplus
|
|
#if __cplusplus
|
|
}
|
|
#endif /* __cplusplus */
|
|
#endif /* __cplusplus */
|
|
|