Initial commit of firmware

This commit is contained in:
2025-04-12 13:30:57 +01:00
commit 264a3462e0
374 changed files with 332649 additions and 0 deletions

View File

@@ -0,0 +1,85 @@
/***************************************************************************//**
* @file
* @brief MPU API definition.
*******************************************************************************
* # License
* <b>Copyright 2019 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* SPDX-License-Identifier: Zlib
*
* The licensor of this software is Silicon Laboratories Inc.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
******************************************************************************/
/***************************************************************************//**
* @addtogroup mpu RAM execution disable
* @brief RAM execution disable utilities can be used to disable execution from
* RAM and other selected memory regions.
* @details
* RAM execution disable utilities are useful to protect against code
* injection attacks.
* These utilities make use of MPU to disable execution from RAM and other
* selected memory regions.
*
* @{
******************************************************************************/
#ifndef SL_MPU_H
#define SL_MPU_H
#include "sl_status.h"
#ifdef __cplusplus
extern "C" {
#endif
/***************************************************************************//**
* Configures internal SRAM as non-executable and enable MPU.
*
* @note This function configures the MPU in order to make the entire RAM as
* non-executable (with the exception of the functions marked as ramfunc).
******************************************************************************/
void sl_mpu_disable_execute_from_ram(void);
/***************************************************************************//**
* Configures an address range as non-executable and enable MPU.
*
* @note Configures a MPU region in order to make an address range as
* non-executable. The memory region must have a size of at least 32 bytes.
*
* @param address_begin Beginning of memory segment.
*
* @param address_end End of memory segment.
*
* @param size Size of memory segment.
*
* @return 0 if successful. Error code otherwise.
******************************************************************************/
sl_status_t sl_mpu_disable_execute(uint32_t address_begin,
uint32_t address_end,
uint32_t size);
#ifdef __cplusplus
}
#endif
#endif /* SL_MPU_H */
/** @} (end addtogroup mpu) */

View File

@@ -0,0 +1,493 @@
/***************************************************************************//**
* @file
* @brief MPU API implementation.
*******************************************************************************
* # License
* <b>Copyright 2019 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* SPDX-License-Identifier: Zlib
*
* The licensor of this software is Silicon Laboratories Inc.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
******************************************************************************/
#include "sl_mpu.h"
#include <stdlib.h>
#include <math.h>
#include <stdbool.h>
#include "em_device.h"
#include "sl_core.h"
/*******************************************************************************
********************************* DEFINES *********************************
******************************************************************************/
#define MPU_MEMORY_ATTRIBUTE_IX_0 0U
#define MPU_MEMORY_ATTRIBUTE_IX_1 1U
#define MPU_RBAR_BASE_ADDR_NONE 0U
#define MPU_RBAR_AP_READ_WRITE 0U
#define MPU_RBAR_AP_READ_ONLY 1U
#define MPU_RBAR_AP_PRIVILEGED 0U
#define MPU_RBAR_AP_NON_PRIVILEGED 1U
#define MPU_RBAR_XN_EXECUTION 0U
#define MPU_RBAR_XN_NON_EXECUTION 1U
// Memory region attributes: non-shareable, read-write, non-privileged, non-executable.
#define MPU_RBAR_VALUE ARM_MPU_RBAR(MPU_RBAR_BASE_ADDR_NONE, \
ARM_MPU_SH_NON, \
MPU_RBAR_AP_READ_WRITE, \
MPU_RBAR_AP_NON_PRIVILEGED, \
MPU_RBAR_XN_NON_EXECUTION)
// The MPU Region Limit Address Register defines the ending address of an MPU region.
// Bit [4:0] of the address value is assigned with 0x1F to provide the limit
// address to be checked against.
#define MPU_RLAR_LIMIT_ADDRESS_ALIGNMENT 32U
// ARM memory map SRAM location and size.
#if defined(_SILICON_LABS_32B_SERIES_2) \
|| (defined(_SILICON_LABS_32B_SERIES_3) && defined(SL_RAM_LINKER))
#define MPU_ARM_SRAM_MEM_BASE SRAM_BASE
// This RAM size is not the real device size. It corresponds to the SRAM max size in the standard
// ARM Cortex-M33 memory map. The max size is 0.5GB.
#define MPU_ARM_SRAM_MEM_SIZE SRAM_SIZE
#elif defined(_SILICON_LABS_32B_SERIES_3)
// These local constants ensure the MPU regions for the secure/non-secure RAM aliases
// and the secure/non-secure RAM non-aliases are properly managed for all
// secure/non-secure project configurations.
#define MPU_RAMFUNC_SRAM_ALIAS_START SRAM_ALIAS_BASE
#define MPU_RAMFUNC_SRAM_ALIAS_END (SRAM_ALIAS_BASE + (SRAM_SIZE - 1U))
#define MPU_DATA_SRAM_START SRAM_BASE
#define MPU_DATA_SRAM_END (SRAM_BASE + (SRAM_SIZE - 1U))
#if defined(SL_TRUSTZONE_SECURE)
#define MPU_NOT_USED_SRAM_ALIAS_START DMEM_INSTR_NS_MEM_BASE
#define MPU_NOT_USED_SRAM_ALIAS_END DMEM_INSTR_NS_MEM_END
#define MPU_NOT_USED_SRAM_START DMEM_NS_MEM_BASE
#define MPU_NOT_USED_SRAM_END DMEM_NS_MEM_END
#else
#define MPU_NOT_USED_SRAM_ALIAS_START DMEM_INSTR_S_MEM_BASE
#define MPU_NOT_USED_SRAM_ALIAS_END DMEM_INSTR_S_MEM_END
#define MPU_NOT_USED_SRAM_START DMEM_S_MEM_BASE
#define MPU_NOT_USED_SRAM_END DMEM_S_MEM_END
#endif
#endif
#if defined(__ICCARM__)
// iccarm
#pragma section = "text_ram"
#define RAMFUNC_SECTION_BEGIN ((uint32_t)(uint32_t *)__section_begin("text_ram"))
#define RAMFUNC_SECTION_END ((uint32_t)(uint32_t *)__section_end("text_ram"))
#define RAMFUNC_SECTION_SIZE __section_size("text_ram")
#elif defined(__GNUC__)
// armgcc
extern uint32_t __vma_ramfuncs_start__;
extern uint32_t __vma_ramfuncs_end__;
#define RAMFUNC_SECTION_BEGIN (uint32_t) &__vma_ramfuncs_start__
#define RAMFUNC_SECTION_END (uint32_t) &__vma_ramfuncs_end__
#define RAMFUNC_SECTION_SIZE (RAMFUNC_SECTION_END - RAMFUNC_SECTION_BEGIN)
#elif defined(__CC_ARM)
// armcc
// The section name in the armcc scatter file must be "ram_code".
extern uint32_t ram_code$$Base;
extern uint32_t ram_code$$Limit;
#define RAMFUNC_SECTION_BEGIN (uint32_t) &ram_code$$Base
#define RAMFUNC_SECTION_END (uint32_t) &ram_code$$Limit
#define RAMFUNC_SECTION_SIZE (RAMFUNC_SECTION_END - RAMFUNC_SECTION_BEGIN)
#endif
/*******************************************************************************
*************************** LOCAL VARIABLES ********************************
******************************************************************************/
static uint32_t region_nbr = 0;
/*******************************************************************************
************************** GLOBAL FUNCTIONS *******************************
******************************************************************************/
/**************************************************************************//**
* Configures internal SRAM as non-executable and enable MPU.
*
* @note (1) On series 2 devices, the MPU regions configuration for the RAM layout
* is for GCC and IAR:
*
* MPU Region Region Attributes Adresses Range
* ------------------------------------------------------------------------
* 0x2000_0000 0x2007_FFFF (DATA, RAMFUNC) 0 non shareable, executable RAMFunc start to RAMFunc end
* 1 non shareable, non executable RAMFunc end to range end
* or
* 0x2000_0000 0x2007_FFFF (DATA) 0 shareable, non executable Entire range
*
* @note (2) On series 3 SIXG301 devices, there are the following RAM-related
* address ranges.
* - 0x0080_0000 0x0087_FFFF (Alias to DMEM_NS) - Non-secure
* - 0x1080_0000 0x1087_FFFF (Alias to DMEM (execute only)) -Secure
* - 0x2000_0000 0x2007_FFFF (DMEM_NS) - Non-secure
* - 0x3000_0000 0x3007_FFFF (DMEM) - Secure
*
* The MPU regions are configured differently depending on the RAM layout
* described in GCC and IAR linker scripts. A common characteristic
* to all the MPU regions for GCC and IAR is:
* - All MPU regions for RAM are non-cacheable.
*
* The table below presents the MPU regions for series 3 SIXG301 devices.
* The table assumes there are RAMFunc in RAM. If there are no RAMFunc
* functions, then the associated region will be a single region covering
* the full addresses range.
*
* GCC
* ---
* MPU Region* Region Attributes Adresses Range
* ------------------------------------------------------------------------
* 0x0080_0000 0x0087_FFFF (RAMFUNC)* 0 shareable, executable RAMFunc start to RAMFunc end
* 1 non shareable, non executable RAMFunc end to range end
* or
* 0x0080_0000 0x0087_FFFF (NOT USED)* x non shareable, non executable Entire range (if no RAMFunc)
*
* 0x1080_0000 0x1087_FFFF (NOT USED)* 2 non shareable, non executable Entire range
* 0x2000_0000 0x2007_FFFF (DATA)* 3 shareable, non executable Entire range
* 0x3000_0000 0x3007_FFFF (NOT USED)* 4 non shareable, non executable Entire range
*
* IAR
* ---
* MPU Region* Region Attributes Adresses Range
* ------------------------------------------------------------------------
* 0x0080_0000 0x0087_FFFF (NOT USED)* 0 non shareable, non executable Entire range
* 0x1080_0000 0x1087_FFFF (NOT USED)* 1 non shareable, non executable Entire range
* 0x2000_0000 0x2007_FFFF (DATA, RAMFUNC)* 2 shareable, non executable Range start to RAMFunc start
* 3 shareable, executable RAMFunc start to RAMFunc end
* 4 shareable, non executable RAMFunc end to range end
* or
* 0x2000_0000 0x2007_FFFF (NOT USED)* x non shareable, non executable Entire range (if no RAMFunc)
*
* 0x3000_0000 0x3007_FFFF (NOT USED)* 5 non shareable, non executable Entire range
* *If the ARM Cortex-M33 works in non-secure, all non-secure alias/
* non-alias will be used by default for RAMfunc and data in RAM.
* Same logic if the Cortex-M33 is in secure, all secure alias/non-alias
* will be used by default. The MPU regions creation will adapt to
* the default secure or non-secure addresses. And thus the order
* in which the MPU regions are created can vary.
*****************************************************************************/
void sl_mpu_disable_execute_from_ram(void)
{
uint32_t mpu_region_begin = 0u;
uint32_t mpu_region_end = 0u;
uint32_t rbar;
ARM_MPU_Disable();
// See Note #1.
#if defined(_SILICON_LABS_32B_SERIES_2) \
|| (defined(_SILICON_LABS_32B_SERIES_3) && defined(SL_RAM_LINKER))
// Memory attributes:
// Outer memory with ARM_MPU_ATTR_MEMORY_(): non-transient data, Write-Through, cache allocation on read miss, no cache allocation on write miss.
// ARM_MPU_ATTR(): outer attributes filled, no inner memory
ARM_MPU_SetMemAttr(MPU_MEMORY_ATTRIBUTE_IX_0,
ARM_MPU_ATTR(ARM_MPU_ATTR_MEMORY_(1, 0, 1, 0), 0));
// Region end address LSB are always considered 0x1F.
mpu_region_begin = MPU_ARM_SRAM_MEM_BASE;
mpu_region_end = (RAMFUNC_SECTION_SIZE > 0) ? (RAMFUNC_SECTION_BEGIN & MPU_RBAR_BASE_Msk) - MPU_RLAR_LIMIT_ADDRESS_ALIGNMENT
: (MPU_ARM_SRAM_MEM_BASE + MPU_ARM_SRAM_MEM_SIZE);
// Define initial MPU region: either 1 unique region = entire RAM. Or 1 region = from RAM START to RAMFUNC START.
if (mpu_region_begin <= mpu_region_end) {
// A bug exists in some versions of ARM_MPU_RBAR(). Set base addr manually.
rbar = MPU_RBAR_VALUE | (mpu_region_begin & MPU_RBAR_BASE_Msk);
ARM_MPU_SetRegion(region_nbr, rbar, ARM_MPU_RLAR(mpu_region_end, MPU_MEMORY_ATTRIBUTE_IX_0));
region_nbr++;
}
// Only if functions placed in RAM, define another region from RAMFUNC END to RAM END.
if (RAMFUNC_SECTION_SIZE > 0u) {
// Region end address LSB are always considered 0x1F.
mpu_region_begin = (RAMFUNC_SECTION_END + 31u) & MPU_RLAR_LIMIT_Msk;
mpu_region_end = MPU_ARM_SRAM_MEM_BASE + MPU_ARM_SRAM_MEM_SIZE - MPU_RLAR_LIMIT_ADDRESS_ALIGNMENT;
// A bug exists in some versions of ARM_MPU_RBAR(). Set base addr manually.
rbar = MPU_RBAR_VALUE | (mpu_region_begin & MPU_RBAR_BASE_Msk);
ARM_MPU_SetRegion(region_nbr, rbar, ARM_MPU_RLAR(mpu_region_end, 0u));
region_nbr++;
}
// See Note #2.
#elif (defined(_SILICON_LABS_32B_SERIES_3) && !defined(SL_RAM_LINKER))
// 1. Set the memory attributes for the entire RAM (alias and non-alias ranges).
// Outer & inner memories: non-cacheable.
ARM_MPU_SetMemAttr(MPU_MEMORY_ATTRIBUTE_IX_0,
ARM_MPU_ATTR(ARM_MPU_ATTR_NON_CACHEABLE, ARM_MPU_ATTR_NON_CACHEABLE));
// 2. Create different MPU regions accounting for all RAM addresses ranges (secure/non-secure alias/non-alias)
// Secure or non secure alias (not used): 1 region (non shareable, non cacheable, non executable)
mpu_region_begin = MPU_NOT_USED_SRAM_ALIAS_START;
rbar = ARM_MPU_RBAR(MPU_RBAR_BASE_ADDR_NONE,
ARM_MPU_SH_NON,
MPU_RBAR_AP_READ_ONLY,
MPU_RBAR_AP_NON_PRIVILEGED,
MPU_RBAR_XN_NON_EXECUTION)
| (mpu_region_begin & MPU_RBAR_BASE_Msk);
mpu_region_end = (MPU_NOT_USED_SRAM_ALIAS_END & MPU_RLAR_LIMIT_Msk);
ARM_MPU_SetRegion(region_nbr, rbar, ARM_MPU_RLAR(mpu_region_end, MPU_MEMORY_ATTRIBUTE_IX_0));
region_nbr++;
// Non secure or secure alias (used for code if functions placed in RAM):
#if defined(__GNUC__)
if (RAMFUNC_SECTION_SIZE > 0u) {
// Functions placed in RAM: 1 region (shareable, non cacheable, executable)
mpu_region_begin = RAMFUNC_SECTION_BEGIN;
rbar = ARM_MPU_RBAR(MPU_RBAR_BASE_ADDR_NONE,
ARM_MPU_SH_OUTER,
MPU_RBAR_AP_READ_ONLY,
MPU_RBAR_AP_NON_PRIVILEGED,
MPU_RBAR_XN_EXECUTION)
| (mpu_region_begin & MPU_RBAR_BASE_Msk);
mpu_region_end = (RAMFUNC_SECTION_END & MPU_RLAR_LIMIT_Msk);
ARM_MPU_SetRegion(region_nbr, rbar, ARM_MPU_RLAR(mpu_region_end, MPU_MEMORY_ATTRIBUTE_IX_0));
region_nbr++;
// Rest of the non secure or secure alias: non shareable, non cacheable, non executable
mpu_region_begin = (RAMFUNC_SECTION_END + 31u) & MPU_RLAR_LIMIT_Msk; // +31u allows to round up to the next 32 bytes alignment.
rbar = ARM_MPU_RBAR(MPU_RBAR_BASE_ADDR_NONE,
ARM_MPU_SH_NON,
MPU_RBAR_AP_READ_ONLY,
MPU_RBAR_AP_NON_PRIVILEGED,
MPU_RBAR_XN_NON_EXECUTION)
| (mpu_region_begin & MPU_RBAR_BASE_Msk);
mpu_region_end = (MPU_RAMFUNC_SRAM_ALIAS_END & MPU_RLAR_LIMIT_Msk);
ARM_MPU_SetRegion(region_nbr, rbar, ARM_MPU_RLAR(mpu_region_end, MPU_MEMORY_ATTRIBUTE_IX_0));
region_nbr++;
} else {
#endif
// No functions placed in RAM: 1 region (non shareable, non cacheable, non executable)
mpu_region_begin = MPU_RAMFUNC_SRAM_ALIAS_START;
rbar = ARM_MPU_RBAR(MPU_RBAR_BASE_ADDR_NONE,
ARM_MPU_SH_NON,
MPU_RBAR_AP_READ_ONLY,
MPU_RBAR_AP_NON_PRIVILEGED,
MPU_RBAR_XN_NON_EXECUTION)
| (mpu_region_begin & MPU_RBAR_BASE_Msk);
mpu_region_end = (MPU_RAMFUNC_SRAM_ALIAS_END & MPU_RLAR_LIMIT_Msk);
ARM_MPU_SetRegion(region_nbr, rbar, ARM_MPU_RLAR(mpu_region_end, MPU_MEMORY_ATTRIBUTE_IX_0));
region_nbr++;
#if defined(__GNUC__)
}
#endif
// Secure or non secure non alias (used for data): 1 region (shareable, non cacheable, non executable)
#if defined(__ICCARM__)
if (RAMFUNC_SECTION_SIZE > 0u) {
// Beginning of non secure alias: shareable, non cacheable, non executable
mpu_region_begin = MPU_DATA_SRAM_START;
rbar = ARM_MPU_RBAR(MPU_RBAR_BASE_ADDR_NONE,
ARM_MPU_SH_OUTER,
MPU_RBAR_AP_READ_WRITE,
MPU_RBAR_AP_NON_PRIVILEGED,
MPU_RBAR_XN_NON_EXECUTION)
| (mpu_region_begin & MPU_RBAR_BASE_Msk);
mpu_region_end = ((RAMFUNC_SECTION_BEGIN - 1u) & MPU_RLAR_LIMIT_Msk);
ARM_MPU_SetRegion(region_nbr, rbar, ARM_MPU_RLAR(mpu_region_end, MPU_MEMORY_ATTRIBUTE_IX_0));
region_nbr++;
// Functions placed in RAM: 1 region (shareable, non cacheable, executable)
mpu_region_begin = RAMFUNC_SECTION_BEGIN;
rbar = ARM_MPU_RBAR(MPU_RBAR_BASE_ADDR_NONE,
ARM_MPU_SH_OUTER,
MPU_RBAR_AP_READ_ONLY,
MPU_RBAR_AP_NON_PRIVILEGED,
MPU_RBAR_XN_EXECUTION)
| (mpu_region_begin & MPU_RBAR_BASE_Msk);
mpu_region_end = (RAMFUNC_SECTION_END & MPU_RLAR_LIMIT_Msk);
ARM_MPU_SetRegion(region_nbr, rbar, ARM_MPU_RLAR(mpu_region_end, MPU_MEMORY_ATTRIBUTE_IX_0));
region_nbr++;
// Rest of non secure alias: shareable, non cacheable, non executable
mpu_region_begin = (RAMFUNC_SECTION_END + 31u) & MPU_RLAR_LIMIT_Msk; // +31u allows to round up to the next 32 bytes alignment.
rbar = ARM_MPU_RBAR(MPU_RBAR_BASE_ADDR_NONE,
ARM_MPU_SH_OUTER,
MPU_RBAR_AP_READ_WRITE,
MPU_RBAR_AP_NON_PRIVILEGED,
MPU_RBAR_XN_NON_EXECUTION)
| (mpu_region_begin & MPU_RBAR_BASE_Msk);
mpu_region_end = (MPU_DATA_SRAM_END & MPU_RLAR_LIMIT_Msk);
ARM_MPU_SetRegion(region_nbr, rbar, ARM_MPU_RLAR(mpu_region_end, MPU_MEMORY_ATTRIBUTE_IX_0));
region_nbr++;
} else {
#endif
mpu_region_begin = MPU_DATA_SRAM_START;
rbar = ARM_MPU_RBAR(MPU_RBAR_BASE_ADDR_NONE,
ARM_MPU_SH_OUTER,
MPU_RBAR_AP_READ_WRITE,
MPU_RBAR_AP_NON_PRIVILEGED,
MPU_RBAR_XN_NON_EXECUTION)
| (mpu_region_begin & MPU_RBAR_BASE_Msk);
mpu_region_end = (MPU_DATA_SRAM_END & MPU_RLAR_LIMIT_Msk);
ARM_MPU_SetRegion(region_nbr, rbar, ARM_MPU_RLAR(mpu_region_end, MPU_MEMORY_ATTRIBUTE_IX_0));
region_nbr++;
#if defined(__ICCARM__)
}
#endif
// Non secure or secure non alias (not used): 1 region (non shareable, non cacheable, non executable)
mpu_region_begin = MPU_NOT_USED_SRAM_START;
rbar = ARM_MPU_RBAR(MPU_RBAR_BASE_ADDR_NONE,
ARM_MPU_SH_NON,
MPU_RBAR_AP_READ_ONLY,
MPU_RBAR_AP_NON_PRIVILEGED,
MPU_RBAR_XN_NON_EXECUTION)
| (mpu_region_begin & MPU_RBAR_BASE_Msk);
mpu_region_end = (MPU_NOT_USED_SRAM_END & MPU_RLAR_LIMIT_Msk);
ARM_MPU_SetRegion(region_nbr, rbar, ARM_MPU_RLAR(mpu_region_end, MPU_MEMORY_ATTRIBUTE_IX_0));
region_nbr++;
#else
(void)rbar;
(void)mpu_region_begin;
(void)mpu_region_end;
#endif
// Enable MPU with default background region.
ARM_MPU_Enable(MPU_CTRL_PRIVDEFENA_Msk);
__DSB();
__ISB();
}
/**************************************************************************//**
* Enables simplified MPU driver. Configures memory address as non-executable.
*****************************************************************************/
sl_status_t sl_mpu_disable_execute(uint32_t address_begin,
uint32_t address_end,
uint32_t size)
{
uint32_t mpu_region_begin = 0u;
uint32_t mpu_region_end = 0u;
sl_status_t status = SL_STATUS_OK;
// Ensure there is still an available MPU region to configure.
if (region_nbr > MPU_RNR_REGION_Msk) {
status = SL_STATUS_NO_MORE_RESOURCE;
}
ARM_MPU_Disable();
uint32_t rbar;
uint8_t is_overlapping = 0u;
uint32_t prev_base_address = 0u;
uint32_t prev_limit_address = 0u;
// Size of memory region must be 32 bytes or more.
if (size >= 32u) {
// Round inside the memory region, if address is not align on 32 bytes.
mpu_region_begin = ((address_begin % 32u) == 0u) ? address_begin
: (address_begin + (32u - (address_begin % 32u)));
// Round inside the memory region, if address is not align on 32 bytes.
mpu_region_end = ((address_end % 32u) == 0u) ? address_end
: (address_end - (address_end % 32u));
// The scanning to check the overlapping region
for (uint8_t index_region = 0; index_region < region_nbr; index_region++) {
// Set to the previous region number
MPU->RNR = index_region;
// Read the base address that was configured by the region number register before
prev_base_address = (MPU->RBAR & MPU_RBAR_BASE_Msk);
// Read the limit address that was configured by the region number register before
prev_limit_address = (MPU->RLAR & MPU_RLAR_LIMIT_Msk);
// Check the overlapping region
if ((mpu_region_begin == prev_base_address) && (mpu_region_end == prev_limit_address)) {
// The new region is the same as the previous region
is_overlapping = 1;
status = SL_STATUS_OK;
} else if (!((mpu_region_begin > prev_limit_address) || (mpu_region_end < prev_base_address))) {
// The new region is invalid
is_overlapping = 1;
status = SL_STATUS_INVALID_RANGE;
}
if (is_overlapping == 1) {
break;
}
MPU->RNR &= ~MPU_RNR_REGION_Msk;
}
// Set specified memory region if no overlap has been detected.
if (!is_overlapping) {
// Device memory type non Gathering, non Re-ordering, Early Write Acknowledgment
ARM_MPU_SetMemAttr(MPU_MEMORY_ATTRIBUTE_IX_1, ARM_MPU_ATTR_DEVICE_nGnRE);
// A bug exists in some versions of ARM_MPU_RBAR(). Set base addr manually.
// Memory region attributes: non-shareable, read-write, non-privileged, non-executable
rbar = ARM_MPU_RBAR(MPU_RBAR_BASE_ADDR_NONE,
ARM_MPU_SH_NON,
MPU_RBAR_AP_READ_WRITE,
MPU_RBAR_AP_NON_PRIVILEGED,
MPU_RBAR_XN_NON_EXECUTION)
| (mpu_region_begin & MPU_RBAR_BASE_Msk);
CORE_DECLARE_IRQ_STATE;
CORE_ENTER_ATOMIC();
ARM_MPU_SetRegion(region_nbr, rbar, ARM_MPU_RLAR(mpu_region_end, MPU_MEMORY_ATTRIBUTE_IX_1));
CORE_EXIT_ATOMIC();
region_nbr++;
}
}
// Enable MPU with default background region
ARM_MPU_Enable(MPU_CTRL_PRIVDEFENA_Msk);
__DSB();
__ISB();
return status;
}
#if __CORTEX_M != (0u)
/**************************************************************************//**
* MemManage default exception handler. Reset target.
*****************************************************************************/
__WEAK void mpu_fault_handler(void)
{
// Force fail assert to trigger reset
__NVIC_SystemReset();
}
/**************************************************************************//**
* MemManage exception handler.
*****************************************************************************/
void MemManage_Handler(void)
{
mpu_fault_handler();
}
#endif