diff --git a/TESTS/mbed_hal/flash/functional_tests/main.cpp b/TESTS/mbed_hal/flash/functional_tests/main.cpp index 46d9906..498e666 100644 --- a/TESTS/mbed_hal/flash/functional_tests/main.cpp +++ b/TESTS/mbed_hal/flash/functional_tests/main.cpp @@ -252,7 +252,8 @@ utest::v1::status_t greentea_test_setup(const size_t number_of_cases) { - mbed_mpu_manager_lock_mem_xn(); + mbed_mpu_manager_lock_ram_xn(); + mbed_mpu_manager_lock_rom_wn(); GREENTEA_SETUP(20, "default_auto"); return greentea_test_setup_handler(number_of_cases); @@ -260,7 +261,8 @@ void greentea_test_teardown(const size_t passed, const size_t failed, const failure_t failure) { - mbed_mpu_manager_unlock_mem_xn(); + mbed_mpu_manager_unlock_ram_xn(); + mbed_mpu_manager_unlock_rom_wn(); greentea_test_teardown_handler(passed, failed, failure); } diff --git a/drivers/FlashIAP.cpp b/drivers/FlashIAP.cpp index fc8a42b..d8e412c 100644 --- a/drivers/FlashIAP.cpp +++ b/drivers/FlashIAP.cpp @@ -26,6 +26,7 @@ #include "FlashIAP.h" #include "platform/mbed_assert.h" #include "platform/ScopedMpuXnLock.h" +#include "platform/ScopedMpuWnLock.h" #ifdef DEVICE_FLASH @@ -59,6 +60,7 @@ _mutex->lock(); { ScopedMpuXnLock xn; + ScopedMpuWnLock wn; if (flash_init(&_flash)) { ret = -1; } @@ -76,6 +78,7 @@ _mutex->lock(); { ScopedMpuXnLock xn; + ScopedMpuWnLock wn; if (flash_free(&_flash)) { ret = -1; } @@ -92,6 +95,7 @@ _mutex->lock(); { ScopedMpuXnLock xn; + ScopedMpuWnLock wn; ret = flash_read(&_flash, addr, (uint8_t *) buffer, size); } _mutex->unlock(); @@ -138,6 +142,7 @@ } { ScopedMpuXnLock xn; + ScopedMpuWnLock wn; if (flash_program_page(&_flash, addr, prog_buf, prog_size)) { ret = -1; break; @@ -185,6 +190,7 @@ while (size) { { ScopedMpuXnLock xn; + ScopedMpuWnLock wn; ret = flash_erase_sector(&_flash, addr); } if (ret != 0) { diff --git a/hal/mpu/mbed_mpu_v7m.c b/hal/mpu/mbed_mpu_v7m.c index 548fa62..53ee075 100644 --- a/hal/mpu/mbed_mpu_v7m.c +++ b/hal/mpu/mbed_mpu_v7m.c @@ -14,31 +14,43 @@ * limitations under the License. */ #include "hal/mpu_api.h" +#include "platform/mbed_assert.h" +#include "platform/mbed_error.h" #include "cmsis.h" #if ((__ARM_ARCH_7M__ == 1U) || (__ARM_ARCH_7EM__ == 1U) || (__ARM_ARCH_6M__ == 1U)) && \ - defined (__MPU_PRESENT) && (__MPU_PRESENT == 1U) + defined (__MPU_PRESENT) && (__MPU_PRESENT == 1U) && \ + !defined(MBED_MPU_CUSTOM) #if !DEVICE_MPU #error "Device has v7m MPU but it is not enabled. Add 'MPU' to device_has in targets.json" #endif +#if !defined(MBED_MPU_ROM_END) +#define MBED_MPU_ROM_END (0x10000000 - 1) +#endif +#define MBED_MPU_RAM_START (MBED_MPU_ROM_END + 1) + +MBED_STATIC_ASSERT( + MBED_MPU_ROM_END == 0x04000000 - 1 || + MBED_MPU_ROM_END == 0x08000000 - 1 || + MBED_MPU_ROM_END == 0x0C000000 - 1 || + MBED_MPU_ROM_END == 0x10000000 - 1 || + MBED_MPU_ROM_END == 0x14000000 - 1 || + MBED_MPU_ROM_END == 0x18000000 - 1 || + MBED_MPU_ROM_END == 0x1C000000 - 1 || + MBED_MPU_ROM_END == 0x20000000 - 1, + "Unsupported value for MBED_MPU_ROM_END"); + void mbed_mpu_init() { - mbed_mpu_enable_ram_xn(false); -} - -void mbed_mpu_free() -{ - mbed_mpu_enable_ram_xn(false); -} - -void mbed_mpu_enable_ram_xn(bool enable) -{ // Flush memory writes before configuring the MPU. __DSB(); const uint32_t regions = (MPU->TYPE & MPU_TYPE_DREGION_Msk) >> MPU_TYPE_DREGION_Pos; + if (regions < 4) { + MBED_ERROR(MBED_MAKE_ERROR(MBED_MODULE_HAL, MBED_ERROR_CODE_EINVAL), "Device is not capable of supporting an MPU - remove DEVICE_MPU for device_has."); + } // Disable the MCU MPU->CTRL = 0; @@ -48,15 +60,11 @@ ARM_MPU_ClrRegion(i); } - if (!enable) { - return; - } - /* - * ARMv6m and ARMv7m memory map: + * ARMv6m and ARMv7-M memory map: * * Start End Name Executable by default Mbed MPU protection - * 0x00000000 - 0x1FFFFFFF Code Yes Execute disabled for second half + * 0x00000000 - 0x1FFFFFFF Code Yes Write disabled for first portion and execute disabled for the rest * 0x20000000 - 0x3FFFFFFF SRAM Yes Execute disabled * 0x40000000 - 0x5FFFFFFF Peripheral No * 0x60000000 - 0x7FFFFFFF RAM Yes Execute disabled @@ -66,81 +74,102 @@ * 0xE0000000 - 0xFFFFFFFF System No */ - if (regions >= 3) { - // Select region 0 and used it for the WT rom region - // - RAM 0x10000000 - 0x1FFFFFFF - MPU->RNR = 0; - // Set address to 0 - MPU->RBAR = 0; - // Configure and enable region - MPU->RASR = - MPU_RASR_ENABLE_Msk | - ARM_MPU_RASR( - 1, // DisableExec - ARM_MPU_AP_FULL, // AccessPermission - 0, // TypeExtField - 0, // IsShareable - 1, // IsCacheable - 0, // IsBufferable - // SubRegionDisable - (1 << 0) | // Disable Sub-region - (1 << 1) | // Disable Sub-region - (1 << 2) | // Disable Sub-region - (1 << 3) | // Disable Sub-region - (0 << 4) | // Enable Sub-region RAM 0x10000000 - 0x1FFFFFFF - (0 << 5) | - (0 << 6) | - (0 << 7), - ARM_MPU_REGION_SIZE_512MB // Size - ); + // Select region 1 and used it for the WT rom region + // - RAM 0x00000000 to MBED_MPU_ROM_END + MPU->RNR = 0; + // Set address to 0 + MPU->RBAR = 0; + // Configure and enable region + MPU->RASR = + ARM_MPU_RASR( + 0, // DisableExec + ARM_MPU_AP_RO, // AccessPermission + 0, // TypeExtField + 0, // IsShareable + 1, // IsCacheable + 0, // IsBufferable + // SubRegionDisable - based on where ROM ends + ((MBED_MPU_ROM_END >= 0x00000000) ? 0 : (1 << 0)) | // 0 to enable, 1 << n to disable + ((MBED_MPU_ROM_END >= 0x04000000) ? 0 : (1 << 1)) | + ((MBED_MPU_ROM_END >= 0x08000000) ? 0 : (1 << 2)) | + ((MBED_MPU_ROM_END >= 0x0C000000) ? 0 : (1 << 3)) | + ((MBED_MPU_ROM_END >= 0x10000000) ? 0 : (1 << 4)) | + ((MBED_MPU_ROM_END >= 0x14000000) ? 0 : (1 << 5)) | + ((MBED_MPU_ROM_END >= 0x18000000) ? 0 : (1 << 6)) | + ((MBED_MPU_ROM_END >= 0x1C000000) ? 0 : (1 << 7)), + ARM_MPU_REGION_SIZE_512MB // Size + ); - // Select region 1 and used it for WBWA ram regions - // - SRAM 0x20000000 - 0x3FFFFFFF - // - RAM 0x60000000 - 0x7FFFFFFF - MPU->RNR = 1; - // Set address to 0 - MPU->RBAR = 0; - // Configure and enable region - MPU->RASR = - MPU_RASR_ENABLE_Msk | - ARM_MPU_RASR( - 1, // DisableExec - ARM_MPU_AP_FULL, // AccessPermission - 1, // TypeExtField - 0, // IsShareable - 1, // IsCacheable - 1, // IsBufferable - // SubRegionDisable - (1 << 0) | // Disable Sub-region - (0 << 1) | // Enable Sub-region SRAM 0x20000000 - 0x3FFFFFFF - (1 << 2) | // Disable Sub-region - (0 << 3) | // Enable Sub-region RAM 0x60000000 - 0x7FFFFFFF - (1 << 4) | // Disable Sub-region - (1 << 5) | // Disable Sub-region - (1 << 6) | // Disable Sub-region - (1 << 7), // Disable Sub-region - ARM_MPU_REGION_SIZE_4GB // Size - ); + // Select region 1 and used it for the WT rom region + // - RAM MBED_MPU_ROM_END + 1 to 0x1FFFFFFF + MPU->RNR = 1; + // Set address to 0 + MPU->RBAR = 0; + // Configure and enable region + MPU->RASR = + ARM_MPU_RASR( + 1, // DisableExec + ARM_MPU_AP_FULL, // AccessPermission + 0, // TypeExtField + 0, // IsShareable + 1, // IsCacheable + 0, // IsBufferable + // SubRegionDisable - based on where RAM starts + ((MBED_MPU_RAM_START <= 0x04000000) ? 0 : (1 << 0)) | // 0 to enable, 1 << n to disable + ((MBED_MPU_RAM_START <= 0x08000000) ? 0 : (1 << 1)) | + ((MBED_MPU_RAM_START <= 0x0C000000) ? 0 : (1 << 2)) | + ((MBED_MPU_RAM_START <= 0x10000000) ? 0 : (1 << 3)) | + ((MBED_MPU_RAM_START <= 0x14000000) ? 0 : (1 << 4)) | + ((MBED_MPU_RAM_START <= 0x18000000) ? 0 : (1 << 5)) | + ((MBED_MPU_RAM_START <= 0x1C000000) ? 0 : (1 << 6)) | + ((MBED_MPU_RAM_START <= 0x20000000) ? 0 : (1 << 7)), + ARM_MPU_REGION_SIZE_512MB // Size + ); - // Select region 2 and used it for the WT ram region - // - RAM RAM 0x80000000 - 0x9FFFFFFF - MPU->RNR = 2; - // Set address - MPU->RBAR = 0x80000000; - // Configure and enable region - MPU->RASR = - MPU_RASR_ENABLE_Msk | - ARM_MPU_RASR( - 1, // DisableExec - ARM_MPU_AP_FULL, // AccessPermission - 0, // TypeExtField - 0, // IsShareable - 1, // IsCacheable - 0, // IsBufferable - ~0U, // SubRegionDisable - ARM_MPU_REGION_SIZE_512MB // Size - ); - } + // Select region 2 and used it for WBWA ram regions + // - SRAM 0x20000000 to 0x3FFFFFFF + // - RAM 0x60000000 to 0x7FFFFFFF + MPU->RNR = 2; + // Set address to 0 + MPU->RBAR = 0; + // Configure and enable region + MPU->RASR = + ARM_MPU_RASR( + 1, // DisableExec + ARM_MPU_AP_FULL, // AccessPermission + 1, // TypeExtField + 0, // IsShareable + 1, // IsCacheable + 1, // IsBufferable + // SubRegionDisable + (1 << 0) | // Disable Sub-region + (0 << 1) | // Enable Sub-region SRAM 0x20000000 - 0x3FFFFFFF + (1 << 2) | // Disable Sub-region + (0 << 3) | // Enable Sub-region RAM 0x60000000 - 0x7FFFFFFF + (1 << 4) | // Disable Sub-region + (1 << 5) | // Disable Sub-region + (1 << 6) | // Disable Sub-region + (1 << 7), // Disable Sub-region + ARM_MPU_REGION_SIZE_4GB // Size + ); + + // Select region 3 and used it for the WT ram region + // - RAM RAM 0x80000000 to 0x9FFFFFFF + MPU->RNR = 3; + // Set address + MPU->RBAR = 0x80000000; + // Configure and enable region + MPU->RASR = + ARM_MPU_RASR( + 1, // DisableExec + ARM_MPU_AP_FULL, // AccessPermission + 0, // TypeExtField + 0, // IsShareable + 1, // IsCacheable + 0, // IsBufferable + ~0U, // SubRegionDisable + ARM_MPU_REGION_SIZE_512MB // Size + ); // Enable the MPU MPU->CTRL = @@ -153,4 +182,49 @@ __DSB(); } +void mbed_mpu_free() +{ + // Flush memory writes before configuring the MPU. + __DSB(); + + // Disable the MPU + MPU->CTRL = 0; + + // Ensure changes take effect + __ISB(); + __DSB(); +} + +void mbed_mpu_enable_rom_wn(bool enable) +{ + // Flush memory writes before configuring the MPU. + __DSB(); + + MPU->RNR = 0; + MPU->RASR = (MPU->RASR & ~MPU_RASR_ENABLE_Msk) | (enable ? MPU_RASR_ENABLE_Msk : 0); + + // Ensure changes take effect + __ISB(); + __DSB(); +} + +void mbed_mpu_enable_ram_xn(bool enable) +{ + // Flush memory writes before configuring the MPU. + __DSB(); + + MPU->RNR = 1; + MPU->RASR = (MPU->RASR & ~MPU_RASR_ENABLE_Msk) | (enable ? MPU_RASR_ENABLE_Msk : 0); + + MPU->RNR = 2; + MPU->RASR = (MPU->RASR & ~MPU_RASR_ENABLE_Msk) | (enable ? MPU_RASR_ENABLE_Msk : 0); + + MPU->RNR = 3; + MPU->RASR = (MPU->RASR & ~MPU_RASR_ENABLE_Msk) | (enable ? MPU_RASR_ENABLE_Msk : 0); + + // Ensure changes take effect + __ISB(); + __DSB(); +} + #endif diff --git a/hal/mpu/mbed_mpu_v8m.c b/hal/mpu/mbed_mpu_v8m.c index 42d68ac..b7aee94 100644 --- a/hal/mpu/mbed_mpu_v8m.c +++ b/hal/mpu/mbed_mpu_v8m.c @@ -14,31 +14,33 @@ * limitations under the License. */ #include "hal/mpu_api.h" +#include "platform/mbed_assert.h" +#include "platform/mbed_error.h" #include "cmsis.h" #if ((__ARM_ARCH_8M_BASE__ == 1U) || (__ARM_ARCH_8M_MAIN__ == 1U)) && \ - defined (__MPU_PRESENT) && (__MPU_PRESENT == 1U) + defined (__MPU_PRESENT) && (__MPU_PRESENT == 1U) && \ + !defined(MBED_MPU_CUSTOM) #if !DEVICE_MPU #error "Device has v8m MPU but it is not enabled. Add 'MPU' to device_has in targets.json" #endif +#if !defined(MBED_MPU_ROM_END) +#define MBED_MPU_ROM_END (0x20000000 - 1) +#endif + +MBED_STATIC_ASSERT(MBED_MPU_ROM_END == 0x1fffffff, "Changing MBED_MPU_ROM_END for ARMv8-M is not supported."); + void mbed_mpu_init() { - mbed_mpu_enable_ram_xn(false); -} - -void mbed_mpu_free() -{ - mbed_mpu_enable_ram_xn(false); -} - -void mbed_mpu_enable_ram_xn(bool enable) -{ // Flush memory writes before configuring the MPU. __DSB(); const uint32_t regions = (MPU->TYPE & MPU_TYPE_DREGION_Msk) >> MPU_TYPE_DREGION_Pos; + if (regions < 4) { + MBED_ERROR(MBED_MAKE_ERROR(MBED_MODULE_HAL, MBED_ERROR_CODE_EINVAL), "Device is not capable of supporting an MPU - remove DEVICE_MPU for device_has."); + } // Disable the MCU MPU->CTRL = 0; @@ -48,15 +50,11 @@ ARM_MPU_ClrRegionEx(MPU, i); } - if (!enable) { - return; - } - /* - * ARMv8m memory map: + * ARMv8-M memory map: * * Start End Name Executable by default Default cache Mbed MPU protection - * 0x00000000 - 0x1FFFFFFF Code Yes WT, WA + * 0x00000000 - 0x1FFFFFFF Code Yes WT, WA Write disabled * 0x20000000 - 0x3FFFFFFF SRAM Yes WB, WA, RA Execute disabled * 0x40000000 - 0x5FFFFFFF Peripheral No * 0x60000000 - 0x7FFFFFFF RAM Yes WB, WA, RA Execute disabled @@ -66,50 +64,57 @@ * 0xE0000000 - 0xFFFFFFFF System No */ - if (regions >= 3) { - uint32_t region; - uint8_t outer; - uint8_t inner; + uint32_t region; + uint8_t outer; + uint8_t inner; - region = 0; - MPU->RNR = region; - outer = 0xF; // Write-Back, Non-transient, Read-allocate, Write-allocate - outer = 0xF; // Write-Back, Non-transient, Read-allocate, Write-allocate - ARM_MPU_SetMemAttrEx(MPU, region, (outer << 4) | (inner << 0)); - MPU->RBAR = (0x20000000 & MPU_RBAR_BASE_Msk) | // Start address is 0x20000000 - (0 << MPU_RBAR_SH_Pos) | // Not shareable - (1 << MPU_RBAR_AP_Pos) | // RW allowed by all privilege levels - (1 << MPU_RBAR_XN_Pos); // Execute Never enabled - MPU->RLAR = (0x3FFFFFFF & MPU_RLAR_LIMIT_Msk) | // Last address is 0x3FFFFFFF - (region << MPU_RLAR_AttrIndx_Pos) | // Attribute index - configured to be the same as the region number - (1 << MPU_RLAR_EN_Pos); // Enable region + region = 0; + MPU->RNR = region; + outer = 0xA; // Write-Through, Non-transient, Read-allocate + inner = 0xA; // Write-Through, Non-transient, Read-allocate + ARM_MPU_SetMemAttrEx(MPU, region, (outer << 4) | (inner << 0)); + MPU->RBAR = (0x00000000 & MPU_RBAR_BASE_Msk) | // Start address is 0x00000000 + (0 << MPU_RBAR_SH_Pos) | // Not shareable + (3 << MPU_RBAR_AP_Pos) | // RO allowed by all privilege levels + (0 << MPU_RBAR_XN_Pos); // Execute Never disabled + MPU->RLAR = (0x1FFFFFFF & MPU_RLAR_LIMIT_Msk) | // Last address is 0x1FFFFFFF + (region << MPU_RLAR_AttrIndx_Pos); // Attribute index - configured to be the same as the region number - region = 1; - MPU->RNR = region; - outer = 0xF; // Write-Back, Non-transient, Read-allocate, Write-allocate - outer = 0xF; // Write-Back, Non-transient, Read-allocate, Write-allocate - ARM_MPU_SetMemAttrEx(MPU, region, (outer << 4) | (inner << 0)); - MPU->RBAR = (0x60000000 & MPU_RBAR_BASE_Msk) | // Start address is 0x60000000 - (0 << MPU_RBAR_SH_Pos) | // Not shareable - (1 << MPU_RBAR_AP_Pos) | // RW allowed by all privilege levels - (1 << MPU_RBAR_XN_Pos); // Execute Never enabled - MPU->RLAR = (0x7FFFFFFF & MPU_RLAR_LIMIT_Msk) | // Last address is 0x7FFFFFFF - (region << MPU_RLAR_AttrIndx_Pos) | // Attribute index - configured to be the same as the region number - (1 << MPU_RLAR_EN_Pos); // Enable region + region = 1; + MPU->RNR = region; + outer = 0xF; // Write-Back, Non-transient, Read-allocate, Write-allocate + outer = 0xF; // Write-Back, Non-transient, Read-allocate, Write-allocate + ARM_MPU_SetMemAttrEx(MPU, region, (outer << 4) | (inner << 0)); + MPU->RBAR = (0x20000000 & MPU_RBAR_BASE_Msk) | // Start address is 0x20000000 + (0 << MPU_RBAR_SH_Pos) | // Not shareable + (1 << MPU_RBAR_AP_Pos) | // RW allowed by all privilege levels + (1 << MPU_RBAR_XN_Pos); // Execute Never enabled + MPU->RLAR = (0x3FFFFFFF & MPU_RLAR_LIMIT_Msk) | // Last address is 0x3FFFFFFF + (region << MPU_RLAR_AttrIndx_Pos); // Attribute index - configured to be the same as the region number - region = 2; - MPU->RNR = region; - outer = 0xA; // Write-Through, Non-transient, Read-allocate - inner = 0xA; // Write-Through, Non-transient, Read-allocate - ARM_MPU_SetMemAttrEx(MPU, region, (outer << 4) | (inner << 0)); - MPU->RBAR = (0x80000000 & MPU_RBAR_BASE_Msk) | // Start address is 0x80000000 - (0 << MPU_RBAR_SH_Pos) | // Not shareable - (1 << MPU_RBAR_AP_Pos) | // RW allowed by all privilege levels - (1 << MPU_RBAR_XN_Pos); // Execute Never enabled - MPU->RLAR = (0x9FFFFFFF & MPU_RLAR_LIMIT_Msk) | // Last address is 0x9FFFFFFF - (region << MPU_RLAR_AttrIndx_Pos) | // Attribute index - configured to be the same as the region number - (1 << MPU_RLAR_EN_Pos); // Enable region - } + region = 2; + MPU->RNR = region; + outer = 0xF; // Write-Back, Non-transient, Read-allocate, Write-allocate + outer = 0xF; // Write-Back, Non-transient, Read-allocate, Write-allocate + ARM_MPU_SetMemAttrEx(MPU, region, (outer << 4) | (inner << 0)); + MPU->RBAR = (0x60000000 & MPU_RBAR_BASE_Msk) | // Start address is 0x60000000 + (0 << MPU_RBAR_SH_Pos) | // Not shareable + (1 << MPU_RBAR_AP_Pos) | // RW allowed by all privilege levels + (1 << MPU_RBAR_XN_Pos); // Execute Never enabled + MPU->RLAR = (0x7FFFFFFF & MPU_RLAR_LIMIT_Msk) | // Last address is 0x7FFFFFFF + (region << MPU_RLAR_AttrIndx_Pos); // Attribute index - configured to be the same as the region number + + region = 3; + MPU->RNR = region; + outer = 0xA; // Write-Through, Non-transient, Read-allocate + inner = 0xA; // Write-Through, Non-transient, Read-allocate + ARM_MPU_SetMemAttrEx(MPU, region, (outer << 4) | (inner << 0)); + MPU->RBAR = (0x80000000 & MPU_RBAR_BASE_Msk) | // Start address is 0x80000000 + (0 << MPU_RBAR_SH_Pos) | // Not shareable + (1 << MPU_RBAR_AP_Pos) | // RW allowed by all privilege levels + (1 << MPU_RBAR_XN_Pos); // Execute Never enabled + MPU->RLAR = (0x9FFFFFFF & MPU_RLAR_LIMIT_Msk) | // Last address is 0x9FFFFFFF + (region << MPU_RLAR_AttrIndx_Pos); // Attribute index - configured to be the same as the region number // Enable the MPU MPU->CTRL = @@ -122,4 +127,49 @@ __DSB(); } +void mbed_mpu_free() +{ + // Flush memory writes before configuring the MPU. + __DSB(); + + // Disable the MCU + MPU->CTRL = 0; + + // Ensure changes take effect + __ISB(); + __DSB(); +} + +void mbed_mpu_enable_rom_wn(bool enable) +{ + // Flush memory writes before configuring the MPU. + __DSB(); + + MPU->RNR = 0; + MPU->RLAR = (MPU->RLAR & ~MPU_RLAR_EN_Msk) | (enable ? MPU_RLAR_EN_Msk : 0); + + // Ensure changes take effect + __ISB(); + __DSB(); +} + +void mbed_mpu_enable_ram_xn(bool enable) +{ + // Flush memory writes before configuring the MPU. + __DSB(); + + MPU->RNR = 1; + MPU->RLAR = (MPU->RLAR & ~MPU_RLAR_EN_Msk) | (enable ? MPU_RLAR_EN_Msk : 0); + + MPU->RNR = 2; + MPU->RLAR = (MPU->RLAR & ~MPU_RLAR_EN_Msk) | (enable ? MPU_RLAR_EN_Msk : 0); + + MPU->RNR = 3; + MPU->RLAR = (MPU->RLAR & ~MPU_RLAR_EN_Msk) | (enable ? MPU_RLAR_EN_Msk : 0); + + // Ensure changes take effect + __ISB(); + __DSB(); +} + #endif diff --git a/hal/mpu_api.h b/hal/mpu_api.h index f39c06a..5c02c74 100644 --- a/hal/mpu_api.h +++ b/hal/mpu_api.h @@ -40,6 +40,7 @@ * * Execution from RAM results in a fault when execute never is enabled. * This RAM includes heap, stack, data and zero init - Verified by ::mpu_fault_test_data, * ::mpu_fault_test_bss, ::mpu_fault_test_stack and ::mpu_fault_test_heap. + * * Writing to ROM results in a fault when write never is enabled - Not verified * * # Undefined behavior * * Calling any function other than ::mbed_mpu_init before the initialization of the MPU. @@ -69,6 +70,16 @@ void mbed_mpu_init(void); /** + * Enable or disable ROM MPU protection + * + * This function is used to mark all of ROM as read and execute only. + * When enabled writes to ROM cause a fault. + * + * @param enable true to disable execution in ram, false otherwise + */ +void mbed_mpu_enable_rom_wn(bool enable); + +/** * Enable or disable ram MPU protection * * This function is used to mark all of RAM as execute never. @@ -90,6 +101,8 @@ #define mbed_mpu_init() +#define mbed_mpu_enable_rom_wn(enable) (void)enable + #define mbed_mpu_enable_ram_xn(enable) (void)enable #define mbed_mpu_free() diff --git a/mbed.h b/mbed.h index dfca470..acdc548 100644 --- a/mbed.h +++ b/mbed.h @@ -95,6 +95,7 @@ #include "platform/DirHandle.h" #include "platform/CriticalSectionLock.h" #include "platform/DeepSleepLock.h" +#include "platform/ScopedMpuWnLock.h" #include "platform/ScopedMpuXnLock.h" #include "platform/mbed_stats.h" diff --git a/platform/ScopedMpuWnLock.h b/platform/ScopedMpuWnLock.h new file mode 100644 index 0000000..33309ac --- /dev/null +++ b/platform/ScopedMpuWnLock.h @@ -0,0 +1,72 @@ +/* mbed Microcontroller Library + * Copyright (c) 2018 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef MBED_SCOPEDMPUWNLOCK_H +#define MBED_SCOPEDMPUWNLOCK_H + +#include "platform/mbed_mpu_mgmt.h" +#include "platform/NonCopyable.h" + +namespace mbed { + +/** \addtogroup platform */ +/** @{*/ + +/** RAII object for disabling, then restoring ROM write never mode + * Usage: + * @code + * + * void f() { + * // some code here + * { + * ScopedMpuXnLock xn; + * // Code in this block is allowed to call functions in RAM + * } + * // Execution from RAM is no longer allowed + * } + * @endcode + */ +class ScopedMpuWnLock : private mbed::NonCopyable { +public: + + /** + * Allow execution from RAM + * + * Increment the execute never lock to ensure code can + * be executed from RAM. This class uses RAII to allow + * execution from ram while it is in scope. + */ + ScopedMpuWnLock() + { + mbed_mpu_manager_lock_rom_wn(); + } + + /** + * Restore previous execution from RAM settings + * + * Decrement the execute never lock to return execute from RAM + * to its prior state. + */ + ~ScopedMpuWnLock() + { + mbed_mpu_manager_unlock_rom_wn(); + } +}; + +/**@}*/ + +} + +#endif diff --git a/platform/ScopedMpuXnLock.h b/platform/ScopedMpuXnLock.h index 59a564a..2b286fb 100644 --- a/platform/ScopedMpuXnLock.h +++ b/platform/ScopedMpuXnLock.h @@ -50,7 +50,7 @@ */ ScopedMpuXnLock() { - mbed_mpu_manager_lock_mem_xn(); + mbed_mpu_manager_lock_ram_xn(); } /** @@ -61,7 +61,7 @@ */ ~ScopedMpuXnLock() { - mbed_mpu_manager_unlock_mem_xn(); + mbed_mpu_manager_unlock_ram_xn(); } }; diff --git a/platform/mbed_mpu_mgmt.c b/platform/mbed_mpu_mgmt.c index 076eb5b..39369b7 100644 --- a/platform/mbed_mpu_mgmt.c +++ b/platform/mbed_mpu_mgmt.c @@ -21,13 +21,14 @@ #include static uint16_t mem_xn_lock; +static uint16_t mem_wn_lock; -void mbed_mpu_manager_lock_mem_xn() +void mbed_mpu_manager_lock_ram_xn() { core_util_critical_section_enter(); if (mem_xn_lock == USHRT_MAX) { core_util_critical_section_exit(); - MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_OVERFLOW), "Memory execute never lock overflow (> USHRT_MAX)", mem_xn_lock); + MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_OVERFLOW), "Ram execute never lock overflow (> USHRT_MAX)", mem_xn_lock); } if (mem_xn_lock == 0) { mbed_mpu_enable_ram_xn(false); @@ -36,12 +37,12 @@ core_util_critical_section_exit(); } -void mbed_mpu_manager_unlock_mem_xn() +void mbed_mpu_manager_unlock_ram_xn() { core_util_critical_section_enter(); if (mem_xn_lock == 0) { core_util_critical_section_exit(); - MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_UNDERFLOW), "Memory execute never lock underflow (< 0)", mem_xn_lock); + MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_UNDERFLOW), "Ram execute never lock underflow (< 0)", mem_xn_lock); } mem_xn_lock--; if (mem_xn_lock == 0) { @@ -49,3 +50,31 @@ } core_util_critical_section_exit(); } + +void mbed_mpu_manager_lock_rom_wn() +{ + core_util_critical_section_enter(); + if (mem_wn_lock == USHRT_MAX) { + core_util_critical_section_exit(); + MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_OVERFLOW), "Rom write never lock overflow (> USHRT_MAX)", mem_wn_lock); + } + if (mem_wn_lock == 0) { + mbed_mpu_enable_rom_wn(false); + } + mem_wn_lock++; + core_util_critical_section_exit(); +} + +void mbed_mpu_manager_unlock_rom_wn() +{ + core_util_critical_section_enter(); + if (mem_wn_lock == 0) { + core_util_critical_section_exit(); + MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_UNDERFLOW), "Rom write never lock underflow (< 0)", mem_wn_lock); + } + mem_wn_lock--; + if (mem_wn_lock == 0) { + mbed_mpu_enable_rom_wn(true); + } + core_util_critical_section_exit(); +} diff --git a/platform/mbed_mpu_mgmt.h b/platform/mbed_mpu_mgmt.h index 8e5ed1c..071cfef 100644 --- a/platform/mbed_mpu_mgmt.h +++ b/platform/mbed_mpu_mgmt.h @@ -45,16 +45,40 @@ * The lock is a counter, can be locked up to USHRT_MAX * This function is IRQ and thread safe */ -void mbed_mpu_manager_lock_mem_xn(void); +void mbed_mpu_manager_lock_ram_xn(void); /** Unlock ram execute never mode * - * Use unlocking in pair with mbed_mpu_manager_lock_mem_xn(). + * Use unlocking in pair with mbed_mpu_manager_lock_ram_xn(). * * The lock is a counter, should be equally unlocked as locked * This function is IRQ and thread safe */ -void mbed_mpu_manager_unlock_mem_xn(void); +void mbed_mpu_manager_unlock_ram_xn(void); + +/** Lock rom write never mode off + * + * This disables the MPU's write never ROM protection and allows + * ROM to be written to. Writing to ROM will not result in an MPU + * fault if this function is invoked at least once(the internal + * counter is non-zero). + * + * Use this locking mechanism for code which needs to write to + * ROM such as flash programming algorithms. + * + * The lock is a counter, can be locked up to USHRT_MAX + * This function is IRQ and thread safe + */ +void mbed_mpu_manager_lock_rom_wn(void); + +/** Unlock rom write never mode + * + * Use unlocking in pair with mbed_mpu_manager_lock_rom_wn(). + * + * The lock is a counter, should be equally unlocked as locked + * This function is IRQ and thread safe + */ +void mbed_mpu_manager_unlock_rom_wn(void); #ifdef __cplusplus } diff --git a/rtos/TARGET_CORTEX/mbed_boot.c b/rtos/TARGET_CORTEX/mbed_boot.c index 41add0a..ccca64a 100644 --- a/rtos/TARGET_CORTEX/mbed_boot.c +++ b/rtos/TARGET_CORTEX/mbed_boot.c @@ -89,6 +89,7 @@ { mbed_mpu_init(); mbed_mpu_enable_ram_xn(true); + mbed_mpu_enable_rom_wn(true); mbed_cpy_nvic(); mbed_sdk_init(); mbed_rtos_init();