mirror of https://github.com/ARMmbed/mbed-os.git
commit
52822cb8af
|
@ -21,6 +21,7 @@
|
||||||
#include "utest/utest.h"
|
#include "utest/utest.h"
|
||||||
#include "unity/unity.h"
|
#include "unity/unity.h"
|
||||||
#include "greentea-client/test_env.h"
|
#include "greentea-client/test_env.h"
|
||||||
|
#include "platform/mbed_mpu_mgmt.h"
|
||||||
|
|
||||||
#include "mbed.h"
|
#include "mbed.h"
|
||||||
#include "flash_api.h"
|
#include "flash_api.h"
|
||||||
|
@ -251,11 +252,22 @@ Case cases[] = {
|
||||||
|
|
||||||
utest::v1::status_t greentea_test_setup(const size_t number_of_cases)
|
utest::v1::status_t greentea_test_setup(const size_t number_of_cases)
|
||||||
{
|
{
|
||||||
|
mbed_mpu_manager_lock_ram_execution();
|
||||||
|
mbed_mpu_manager_lock_rom_write();
|
||||||
|
|
||||||
GREENTEA_SETUP(20, "default_auto");
|
GREENTEA_SETUP(20, "default_auto");
|
||||||
return greentea_test_setup_handler(number_of_cases);
|
return greentea_test_setup_handler(number_of_cases);
|
||||||
}
|
}
|
||||||
|
|
||||||
Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler);
|
void greentea_test_teardown(const size_t passed, const size_t failed, const failure_t failure)
|
||||||
|
{
|
||||||
|
mbed_mpu_manager_unlock_ram_execution();
|
||||||
|
mbed_mpu_manager_unlock_rom_write();
|
||||||
|
|
||||||
|
greentea_test_teardown_handler(passed, failed, failure);
|
||||||
|
}
|
||||||
|
|
||||||
|
Specification specification(greentea_test_setup, cases, greentea_test_teardown);
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
|
|
|
@ -0,0 +1,201 @@
|
||||||
|
/* mbed Microcontroller Library
|
||||||
|
* Copyright (c) 2017 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "utest/utest.h"
|
||||||
|
#include "unity/unity.h"
|
||||||
|
#include "greentea-client/test_env.h"
|
||||||
|
|
||||||
|
#include "cmsis.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "mpu_api.h"
|
||||||
|
#include "mpu_test.h"
|
||||||
|
|
||||||
|
#if !DEVICE_MPU
|
||||||
|
#error [NOT_SUPPORTED] MPU API not supported for this target
|
||||||
|
#endif
|
||||||
|
|
||||||
|
using namespace utest::v1;
|
||||||
|
|
||||||
|
#define HARDFAULT_IRQn ((IRQn_Type)-13)
|
||||||
|
#define MEMFAULT_IRQn ((IRQn_Type)-12)
|
||||||
|
|
||||||
|
// Assembly return instruction: bx lr
|
||||||
|
#define ASM_BX_LR 0x4770
|
||||||
|
|
||||||
|
volatile uint32_t fault_count;
|
||||||
|
uint32_t real_hard_fault_handler;
|
||||||
|
uint32_t real_mem_fault_handler;
|
||||||
|
|
||||||
|
static volatile uint16_t data_function = ASM_BX_LR;
|
||||||
|
static volatile uint16_t bss_function;
|
||||||
|
|
||||||
|
static void clear_caches()
|
||||||
|
{
|
||||||
|
#if defined(__CORTEX_M7)
|
||||||
|
/* Data cache clean and invalid */
|
||||||
|
SCB_CleanInvalidateDCache();
|
||||||
|
|
||||||
|
/* Instruction cache invalid */
|
||||||
|
SCB_InvalidateICache();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
__ISB();
|
||||||
|
__DSB();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void call_mem(const volatile uint16_t *mem_function)
|
||||||
|
{
|
||||||
|
// or the address with 1 to ensure the thumb bit is set
|
||||||
|
((void (*)())((uint32_t)mem_function | 1))();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hard_fault_handler_test()
|
||||||
|
{
|
||||||
|
fault_count++;
|
||||||
|
mbed_mpu_enable_ram_xn(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mpu_fault_test(const volatile uint16_t *mem_function)
|
||||||
|
{
|
||||||
|
mbed_mpu_init();
|
||||||
|
|
||||||
|
// Verify that the mpu causes faults when executing ram
|
||||||
|
fault_count = 0;
|
||||||
|
mbed_mpu_enable_ram_xn(true);
|
||||||
|
call_mem(mem_function);
|
||||||
|
TEST_ASSERT_EQUAL(1, fault_count);
|
||||||
|
|
||||||
|
// Verify that the mpu can be turned off
|
||||||
|
fault_count = 0;
|
||||||
|
mbed_mpu_enable_ram_xn(false);
|
||||||
|
call_mem(mem_function);
|
||||||
|
TEST_ASSERT_EQUAL(0, fault_count);
|
||||||
|
|
||||||
|
// Verify that the mpu causes faults when executing ram
|
||||||
|
fault_count = 0;
|
||||||
|
mbed_mpu_enable_ram_xn(true);
|
||||||
|
call_mem(mem_function);
|
||||||
|
TEST_ASSERT_EQUAL(1, fault_count);
|
||||||
|
|
||||||
|
// Verify that free turns off the mpu
|
||||||
|
fault_count = 0;
|
||||||
|
mbed_mpu_free();
|
||||||
|
call_mem(mem_function);
|
||||||
|
TEST_ASSERT_EQUAL(0, fault_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mpu_init_test()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 10; i++) {
|
||||||
|
mbed_mpu_init();
|
||||||
|
}
|
||||||
|
|
||||||
|
mbed_mpu_free();
|
||||||
|
}
|
||||||
|
|
||||||
|
void mpu_free_test()
|
||||||
|
{
|
||||||
|
mbed_mpu_init();
|
||||||
|
|
||||||
|
// Enable the MPU
|
||||||
|
mbed_mpu_enable_ram_xn(true);
|
||||||
|
|
||||||
|
// Free and ensure execution from RAM is allowed
|
||||||
|
mbed_mpu_free();
|
||||||
|
|
||||||
|
call_mem(&data_function);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mpu_fault_test_data()
|
||||||
|
{
|
||||||
|
mpu_fault_test(&data_function);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mpu_fault_test_bss()
|
||||||
|
{
|
||||||
|
bss_function = ASM_BX_LR;
|
||||||
|
clear_caches();
|
||||||
|
mpu_fault_test(&bss_function);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mpu_fault_test_stack()
|
||||||
|
{
|
||||||
|
uint16_t stack_function;
|
||||||
|
|
||||||
|
stack_function = ASM_BX_LR;
|
||||||
|
clear_caches();
|
||||||
|
mpu_fault_test(&stack_function);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mpu_fault_test_heap()
|
||||||
|
{
|
||||||
|
uint16_t *heap_function = (uint16_t *)malloc(2);
|
||||||
|
|
||||||
|
TEST_ASSERT_NOT_EQUAL(NULL, heap_function);
|
||||||
|
*heap_function = ASM_BX_LR;
|
||||||
|
clear_caches();
|
||||||
|
mpu_fault_test(heap_function);
|
||||||
|
|
||||||
|
free(heap_function);
|
||||||
|
}
|
||||||
|
|
||||||
|
utest::v1::status_t fault_override_setup(const Case *const source, const size_t index_of_case)
|
||||||
|
{
|
||||||
|
// Save old fault handlers and replace it with a new one
|
||||||
|
real_hard_fault_handler = NVIC_GetVector(HARDFAULT_IRQn);
|
||||||
|
real_mem_fault_handler = NVIC_GetVector(MEMFAULT_IRQn);
|
||||||
|
NVIC_SetVector(HARDFAULT_IRQn, (uint32_t)&hard_fault_handler_test);
|
||||||
|
NVIC_SetVector(MEMFAULT_IRQn, (uint32_t)&hard_fault_handler_test);
|
||||||
|
|
||||||
|
return greentea_case_setup_handler(source, index_of_case);
|
||||||
|
}
|
||||||
|
|
||||||
|
utest::v1::status_t fault_override_teardown(const Case *const source, const size_t passed, const size_t failed,
|
||||||
|
const failure_t reason)
|
||||||
|
{
|
||||||
|
// Restore real fault handlers
|
||||||
|
NVIC_SetVector(HARDFAULT_IRQn, real_hard_fault_handler);
|
||||||
|
NVIC_SetVector(MEMFAULT_IRQn, real_mem_fault_handler);
|
||||||
|
|
||||||
|
return greentea_case_teardown_handler(source, passed, failed, reason);
|
||||||
|
}
|
||||||
|
|
||||||
|
Case cases[] = {
|
||||||
|
Case("MPU - init", fault_override_setup, mpu_init_test, fault_override_teardown),
|
||||||
|
Case("MPU - free", fault_override_setup, mpu_free_test, fault_override_teardown),
|
||||||
|
#if !((__ARM_ARCH_8M_BASE__ == 1U) || (__ARM_ARCH_8M_MAIN__ == 1U))
|
||||||
|
// Skip fault tests for ARMv8-M until a fault handler hook is provided
|
||||||
|
Case("MPU - data fault", fault_override_setup, mpu_fault_test_data, fault_override_teardown),
|
||||||
|
Case("MPU - bss fault", fault_override_setup, mpu_fault_test_bss, fault_override_teardown),
|
||||||
|
Case("MPU - stack fault", fault_override_setup, mpu_fault_test_stack, fault_override_teardown),
|
||||||
|
Case("MPU - heap fault", fault_override_setup, mpu_fault_test_heap, fault_override_teardown)
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
utest::v1::status_t greentea_test_setup(const size_t number_of_cases)
|
||||||
|
{
|
||||||
|
GREENTEA_SETUP(20, "default_auto");
|
||||||
|
return greentea_test_setup_handler(number_of_cases);
|
||||||
|
}
|
||||||
|
|
||||||
|
Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler);
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
Harness::run(specification);
|
||||||
|
}
|
|
@ -0,0 +1,94 @@
|
||||||
|
/* mbed Microcontroller Library
|
||||||
|
* Copyright (c) 2018-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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** \addtogroup hal_mpu_tests
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MBED_MPU_TEST_H
|
||||||
|
#define MBED_MPU_TEST_H
|
||||||
|
|
||||||
|
#if DEVICE_MPU
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** Test that ::mbed_mpu_init can be called multiple times.
|
||||||
|
*
|
||||||
|
* Given board provides MPU.
|
||||||
|
* When ::mbed_mpu_init is called multiple times.
|
||||||
|
* Then ::mbed_mpu_init are successfully performed (no exception is generated).
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void mpu_init_test(void);
|
||||||
|
|
||||||
|
/** Test that ::mbed_mpu_free disables the MPU
|
||||||
|
*
|
||||||
|
* Given board provides MPU.
|
||||||
|
* When ::mbed_mpu_free is called.
|
||||||
|
* Then execution from RAM is allowed.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void mpu_free_test(void);
|
||||||
|
|
||||||
|
/** Test that MPU protection works for global data
|
||||||
|
*
|
||||||
|
* Given board provides MPU.
|
||||||
|
* When RAM execution is disabled with a call to ::mbed_mpu_enable_ram_xn.
|
||||||
|
* Then execution from global initialized data results in a fault.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void mpu_fault_test_data(void);
|
||||||
|
|
||||||
|
/** Test that MPU protection works for zero initialized data
|
||||||
|
*
|
||||||
|
* Given board provides MPU.
|
||||||
|
* When RAM execution is disabled with a call to ::mbed_mpu_enable_ram_xn.
|
||||||
|
* Then execution from global uninitialized data results in a fault.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void mpu_fault_test_bss(void);
|
||||||
|
|
||||||
|
/** Test that MPU protection works for the stack
|
||||||
|
*
|
||||||
|
* Given board provides MPU.
|
||||||
|
* When RAM execution is disabled with a call to ::mbed_mpu_enable_ram_xn.
|
||||||
|
* Then execution from stack memory results in a fault.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void mpu_fault_test_stack(void);
|
||||||
|
|
||||||
|
/** Test that MPU protection works for the heap
|
||||||
|
*
|
||||||
|
* Given board provides MPU.
|
||||||
|
* When RAM execution is disabled with a call to ::mbed_mpu_enable_ram_xn.
|
||||||
|
* Then execution from heap memory results in a fault.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void mpu_fault_test_heap(void);
|
||||||
|
|
||||||
|
/**@}*/
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** @}*/
|
|
@ -2083,6 +2083,7 @@ PREDEFINED = DOXYGEN_ONLY \
|
||||||
DEVICE_INTERRUPTIN \
|
DEVICE_INTERRUPTIN \
|
||||||
DEVICE_ITM \
|
DEVICE_ITM \
|
||||||
DEVICE_LPTICKER \
|
DEVICE_LPTICKER \
|
||||||
|
DEVICE_MPU \
|
||||||
DEVICE_PORTIN \
|
DEVICE_PORTIN \
|
||||||
DEVICE_PORTINOUT \
|
DEVICE_PORTINOUT \
|
||||||
DEVICE_PORTOUT \
|
DEVICE_PORTOUT \
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
"SEARCH_INCLUDES": "YES",
|
"SEARCH_INCLUDES": "YES",
|
||||||
"INCLUDE_PATH": "",
|
"INCLUDE_PATH": "",
|
||||||
"INCLUDE_FILE_PATTERNS": "",
|
"INCLUDE_FILE_PATTERNS": "",
|
||||||
"PREDEFINED": "DOXYGEN_ONLY DEVICE_ANALOGIN DEVICE_ANALOGOUT DEVICE_CAN DEVICE_CRC DEVICE_ETHERNET DEVICE_EMAC DEVICE_FLASH DEVICE_I2C DEVICE_I2CSLAVE DEVICE_I2C_ASYNCH DEVICE_INTERRUPTIN DEVICE_ITM DEVICE_LPTICKER DEVICE_PORTIN DEVICE_PORTINOUT DEVICE_PORTOUT DEVICE_PWMOUT DEVICE_RTC DEVICE_TRNG DEVICE_SERIAL DEVICE_SERIAL_ASYNCH DEVICE_SERIAL_FC DEVICE_SLEEP DEVICE_SPI DEVICE_SPI_ASYNCH DEVICE_SPISLAVE DEVICE_QSPI DEVICE_STORAGE \"MBED_DEPRECATED_SINCE(f, g)=\" \"MBED_ENABLE_IF_CALLBACK_COMPATIBLE(F, M)=\" \"MBED_DEPRECATED(s)=\"",
|
"PREDEFINED": "DOXYGEN_ONLY DEVICE_ANALOGIN DEVICE_ANALOGOUT DEVICE_CAN DEVICE_CRC DEVICE_ETHERNET DEVICE_EMAC DEVICE_FLASH DEVICE_I2C DEVICE_I2CSLAVE DEVICE_I2C_ASYNCH DEVICE_INTERRUPTIN DEVICE_ITM DEVICE_LPTICKER DEVICE_MPU DEVICE_PORTIN DEVICE_PORTINOUT DEVICE_PORTOUT DEVICE_PWMOUT DEVICE_RTC DEVICE_TRNG DEVICE_SERIAL DEVICE_SERIAL_ASYNCH DEVICE_SERIAL_FC DEVICE_SLEEP DEVICE_SPI DEVICE_SPI_ASYNCH DEVICE_SPISLAVE DEVICE_QSPI DEVICE_STORAGE \"MBED_DEPRECATED_SINCE(f, g)=\" \"MBED_ENABLE_IF_CALLBACK_COMPATIBLE(F, M)=\" \"MBED_DEPRECATED(s)=\"",
|
||||||
"EXPAND_AS_DEFINED": "",
|
"EXPAND_AS_DEFINED": "",
|
||||||
"SKIP_FUNCTION_MACROS": "NO",
|
"SKIP_FUNCTION_MACROS": "NO",
|
||||||
"STRIP_CODE_COMMENTS": "NO",
|
"STRIP_CODE_COMMENTS": "NO",
|
||||||
|
|
|
@ -25,6 +25,8 @@
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include "FlashIAP.h"
|
#include "FlashIAP.h"
|
||||||
#include "platform/mbed_assert.h"
|
#include "platform/mbed_assert.h"
|
||||||
|
#include "platform/ScopedRamExecutionLock.h"
|
||||||
|
#include "platform/ScopedRomWriteLock.h"
|
||||||
|
|
||||||
|
|
||||||
#ifdef DEVICE_FLASH
|
#ifdef DEVICE_FLASH
|
||||||
|
@ -56,8 +58,12 @@ int FlashIAP::init()
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
_mutex->lock();
|
_mutex->lock();
|
||||||
if (flash_init(&_flash)) {
|
{
|
||||||
ret = -1;
|
ScopedRamExecutionLock make_ram_executable;
|
||||||
|
ScopedRomWriteLock make_rom_writable;
|
||||||
|
if (flash_init(&_flash)) {
|
||||||
|
ret = -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
uint32_t page_size = get_page_size();
|
uint32_t page_size = get_page_size();
|
||||||
_page_buf = new uint8_t[page_size];
|
_page_buf = new uint8_t[page_size];
|
||||||
|
@ -70,8 +76,12 @@ int FlashIAP::deinit()
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
_mutex->lock();
|
_mutex->lock();
|
||||||
if (flash_free(&_flash)) {
|
{
|
||||||
ret = -1;
|
ScopedRamExecutionLock make_ram_executable;
|
||||||
|
ScopedRomWriteLock make_rom_writable;
|
||||||
|
if (flash_free(&_flash)) {
|
||||||
|
ret = -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
delete[] _page_buf;
|
delete[] _page_buf;
|
||||||
_mutex->unlock();
|
_mutex->unlock();
|
||||||
|
@ -83,7 +93,11 @@ int FlashIAP::read(void *buffer, uint32_t addr, uint32_t size)
|
||||||
{
|
{
|
||||||
int32_t ret = -1;
|
int32_t ret = -1;
|
||||||
_mutex->lock();
|
_mutex->lock();
|
||||||
ret = flash_read(&_flash, addr, (uint8_t *) buffer, size);
|
{
|
||||||
|
ScopedRamExecutionLock make_ram_executable;
|
||||||
|
ScopedRomWriteLock make_rom_writable;
|
||||||
|
ret = flash_read(&_flash, addr, (uint8_t *) buffer, size);
|
||||||
|
}
|
||||||
_mutex->unlock();
|
_mutex->unlock();
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -126,9 +140,13 @@ int FlashIAP::program(const void *buffer, uint32_t addr, uint32_t size)
|
||||||
prog_buf = buf;
|
prog_buf = buf;
|
||||||
prog_size = chunk;
|
prog_size = chunk;
|
||||||
}
|
}
|
||||||
if (flash_program_page(&_flash, addr, prog_buf, prog_size)) {
|
{
|
||||||
ret = -1;
|
ScopedRamExecutionLock make_ram_executable;
|
||||||
break;
|
ScopedRomWriteLock make_rom_writable;
|
||||||
|
if (flash_program_page(&_flash, addr, prog_buf, prog_size)) {
|
||||||
|
ret = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
size -= chunk;
|
size -= chunk;
|
||||||
addr += chunk;
|
addr += chunk;
|
||||||
|
@ -170,7 +188,11 @@ int FlashIAP::erase(uint32_t addr, uint32_t size)
|
||||||
int32_t ret = 0;
|
int32_t ret = 0;
|
||||||
_mutex->lock();
|
_mutex->lock();
|
||||||
while (size) {
|
while (size) {
|
||||||
ret = flash_erase_sector(&_flash, addr);
|
{
|
||||||
|
ScopedRamExecutionLock make_ram_executable;
|
||||||
|
ScopedRomWriteLock make_rom_writable;
|
||||||
|
ret = flash_erase_sector(&_flash, addr);
|
||||||
|
}
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
ret = -1;
|
ret = -1;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -0,0 +1,230 @@
|
||||||
|
/* 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.
|
||||||
|
*/
|
||||||
|
#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(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()
|
||||||
|
{
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
// Reset all mapping
|
||||||
|
for (uint32_t i = 0; i < regions; i++) {
|
||||||
|
ARM_MPU_ClrRegion(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ARMv6m and ARMv7-M memory map:
|
||||||
|
*
|
||||||
|
* Start End Name Executable by default Mbed MPU protection
|
||||||
|
* 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
|
||||||
|
* 0x80000000 - 0x9FFFFFFF RAM Yes Execute disabled
|
||||||
|
* 0xA0000000 - 0xBFFFFFFF Device No
|
||||||
|
* 0xC0000000 - 0xDFFFFFFF Device No
|
||||||
|
* 0xE0000000 - 0xFFFFFFFF System No
|
||||||
|
*/
|
||||||
|
|
||||||
|
// 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 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 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 =
|
||||||
|
(1 << MPU_CTRL_PRIVDEFENA_Pos) | // Use the default memory map for unmapped addresses
|
||||||
|
(1 << MPU_CTRL_HFNMIENA_Pos) | // Keep MPU turned on for faults
|
||||||
|
(1 << MPU_CTRL_ENABLE_Pos); // Enable MPU
|
||||||
|
|
||||||
|
// Ensure changes take effect
|
||||||
|
__ISB();
|
||||||
|
__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
|
|
@ -0,0 +1,175 @@
|
||||||
|
/* 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.
|
||||||
|
*/
|
||||||
|
#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(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()
|
||||||
|
{
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
// Reset all mapping
|
||||||
|
for (uint32_t i = 0; i < regions; i++) {
|
||||||
|
ARM_MPU_ClrRegionEx(MPU, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ARMv8-M memory map:
|
||||||
|
*
|
||||||
|
* Start End Name Executable by default Default cache Mbed MPU protection
|
||||||
|
* 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
|
||||||
|
* 0x80000000 - 0x9FFFFFFF RAM Yes WT, RA Execute disabled
|
||||||
|
* 0xA0000000 - 0xBFFFFFFF Device No
|
||||||
|
* 0xC0000000 - 0xDFFFFFFF Device No
|
||||||
|
* 0xE0000000 - 0xFFFFFFFF System No
|
||||||
|
*/
|
||||||
|
|
||||||
|
uint32_t region;
|
||||||
|
uint8_t outer;
|
||||||
|
uint8_t inner;
|
||||||
|
|
||||||
|
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 = (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 = 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 =
|
||||||
|
(1 << MPU_CTRL_PRIVDEFENA_Pos) | // Use the default memory map for unmapped addresses
|
||||||
|
(1 << MPU_CTRL_HFNMIENA_Pos) | // Keep MPU turned on for faults
|
||||||
|
(1 << MPU_CTRL_ENABLE_Pos); // Enable MPU
|
||||||
|
|
||||||
|
// Ensure changes take effect
|
||||||
|
__ISB();
|
||||||
|
__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
|
|
@ -0,0 +1,118 @@
|
||||||
|
|
||||||
|
/** \addtogroup hal */
|
||||||
|
/** @{*/
|
||||||
|
/* mbed Microcontroller Library
|
||||||
|
* Copyright (c) 2018-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_MPU_API_H
|
||||||
|
#define MBED_MPU_API_H
|
||||||
|
|
||||||
|
#include "device.h"
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if DEVICE_MPU
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \defgroup hal_mpu MPU hal
|
||||||
|
*
|
||||||
|
* The MPU hal provides a simple MPU API to enhance device security by preventing
|
||||||
|
* execution from ram.
|
||||||
|
*
|
||||||
|
* # Defined behavior
|
||||||
|
* * The function ::mbed_mpu_init is safe to call repeatedly - Verified by ::mpu_init_test
|
||||||
|
* * The function ::mbed_mpu_free disables MPU protection - Verified by ::mpu_free_test
|
||||||
|
* * 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.
|
||||||
|
*
|
||||||
|
* @see hal_mpu_tests
|
||||||
|
*
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \defgroup hal_mpu_tests MPU hal tests
|
||||||
|
* The MPU test validates proper implementation of the MPU hal.
|
||||||
|
*
|
||||||
|
* To run the MPU hal tests use the command:
|
||||||
|
*
|
||||||
|
* mbed test -t <toolchain> -m <target> -n tests-mbed_hal-mpu*
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the MPU
|
||||||
|
*
|
||||||
|
* Initialize or re-initialize the memory protection unit.
|
||||||
|
* It is implementation defined what region are protected
|
||||||
|
* by the MPU after initialization.
|
||||||
|
*/
|
||||||
|
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.
|
||||||
|
* When enabled code is only allowed to execute from flash.
|
||||||
|
*
|
||||||
|
* @param enable true to disable execution in ram, false otherwise
|
||||||
|
*/
|
||||||
|
void mbed_mpu_enable_ram_xn(bool enable);
|
||||||
|
|
||||||
|
/** Deinitialize the MPU
|
||||||
|
*
|
||||||
|
* Powerdown the MPU in preparation for powerdown, reset or jumping to another application.
|
||||||
|
*/
|
||||||
|
void mbed_mpu_free(void);
|
||||||
|
|
||||||
|
/**@}*/
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#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()
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** @}*/
|
2
mbed.h
2
mbed.h
|
@ -95,6 +95,8 @@
|
||||||
#include "platform/DirHandle.h"
|
#include "platform/DirHandle.h"
|
||||||
#include "platform/CriticalSectionLock.h"
|
#include "platform/CriticalSectionLock.h"
|
||||||
#include "platform/DeepSleepLock.h"
|
#include "platform/DeepSleepLock.h"
|
||||||
|
#include "platform/ScopedRomWriteLock.h"
|
||||||
|
#include "platform/ScopedRamExecutionLock.h"
|
||||||
#include "platform/mbed_stats.h"
|
#include "platform/mbed_stats.h"
|
||||||
|
|
||||||
// mbed Non-hardware components
|
// mbed Non-hardware components
|
||||||
|
|
|
@ -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_SCOPEDRAMEXECUTIONLOCK_H
|
||||||
|
#define MBED_SCOPEDRAMEXECUTIONLOCK_H
|
||||||
|
|
||||||
|
#include "platform/mbed_mpu_mgmt.h"
|
||||||
|
#include "platform/NonCopyable.h"
|
||||||
|
|
||||||
|
namespace mbed {
|
||||||
|
|
||||||
|
/** \addtogroup platform */
|
||||||
|
/** @{*/
|
||||||
|
|
||||||
|
/** RAII object for disabling, then restoring RAM execute never mode
|
||||||
|
* Usage:
|
||||||
|
* @code
|
||||||
|
*
|
||||||
|
* void f() {
|
||||||
|
* // some code here
|
||||||
|
* {
|
||||||
|
* ScopedRamExecutionLock make_ram_executable;
|
||||||
|
* // Code in this block is allowed to call functions in RAM
|
||||||
|
* }
|
||||||
|
* // Execution from RAM is no longer allowed
|
||||||
|
* }
|
||||||
|
* @endcode
|
||||||
|
*/
|
||||||
|
class ScopedRamExecutionLock : private mbed::NonCopyable<ScopedRamExecutionLock> {
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
ScopedRamExecutionLock()
|
||||||
|
{
|
||||||
|
mbed_mpu_manager_lock_ram_execution();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Restore previous execution from RAM settings
|
||||||
|
*
|
||||||
|
* Decrement the execute never lock to return execute from RAM
|
||||||
|
* to its prior state.
|
||||||
|
*/
|
||||||
|
~ScopedRamExecutionLock()
|
||||||
|
{
|
||||||
|
mbed_mpu_manager_unlock_ram_execution();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**@}*/
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -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_SCOPEDROMWRITELOCK_H
|
||||||
|
#define MBED_SCOPEDROMWRITELOCK_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
|
||||||
|
* {
|
||||||
|
* ScopedRomWriteLock make_ram_executable;
|
||||||
|
* // Code in this block is allowed to write to ROM
|
||||||
|
* }
|
||||||
|
* // Writing to ROM is no longer allowed
|
||||||
|
* }
|
||||||
|
* @endcode
|
||||||
|
*/
|
||||||
|
class ScopedRomWriteLock : private mbed::NonCopyable<ScopedRomWriteLock> {
|
||||||
|
public:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allow writing to ROM
|
||||||
|
*
|
||||||
|
* Increment the ROM write lock to ensure code can
|
||||||
|
* write to ROM. This class uses RAII to allow
|
||||||
|
* writing to ROM while it is in scope.
|
||||||
|
*/
|
||||||
|
ScopedRomWriteLock()
|
||||||
|
{
|
||||||
|
mbed_mpu_manager_lock_rom_write();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Restore previous write to ROM settings
|
||||||
|
*
|
||||||
|
* Decrement the ROM write lock to return ROM write
|
||||||
|
* to its prior state.
|
||||||
|
*/
|
||||||
|
~ScopedRomWriteLock()
|
||||||
|
{
|
||||||
|
mbed_mpu_manager_unlock_rom_write();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**@}*/
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -18,6 +18,7 @@
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include "device.h"
|
#include "device.h"
|
||||||
#include "platform/mbed_application.h"
|
#include "platform/mbed_application.h"
|
||||||
|
#include "hal/mpu_api.h"
|
||||||
|
|
||||||
#if MBED_APPLICATION_SUPPORT
|
#if MBED_APPLICATION_SUPPORT
|
||||||
|
|
||||||
|
@ -67,6 +68,7 @@ void mbed_start_application(uintptr_t address)
|
||||||
SysTick->CTRL = 0x00000000;
|
SysTick->CTRL = 0x00000000;
|
||||||
powerdown_nvic();
|
powerdown_nvic();
|
||||||
powerdown_scb(address);
|
powerdown_scb(address);
|
||||||
|
mbed_mpu_free();
|
||||||
|
|
||||||
sp = *((void **)address + 0);
|
sp = *((void **)address + 0);
|
||||||
pc = *((void **)address + 1);
|
pc = *((void **)address + 1);
|
||||||
|
|
|
@ -0,0 +1,80 @@
|
||||||
|
/* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "platform/mbed_mpu_mgmt.h"
|
||||||
|
#include "platform/mbed_critical.h"
|
||||||
|
#include "platform/mbed_error.h"
|
||||||
|
#include "hal/mpu_api.h"
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
|
static uint16_t mem_xn_lock;
|
||||||
|
static uint16_t mem_wn_lock;
|
||||||
|
|
||||||
|
void mbed_mpu_manager_lock_ram_execution()
|
||||||
|
{
|
||||||
|
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), "Ram execute never lock overflow (> USHRT_MAX)", mem_xn_lock);
|
||||||
|
}
|
||||||
|
if (mem_xn_lock == 0) {
|
||||||
|
mbed_mpu_enable_ram_xn(false);
|
||||||
|
}
|
||||||
|
mem_xn_lock++;
|
||||||
|
core_util_critical_section_exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
void mbed_mpu_manager_unlock_ram_execution()
|
||||||
|
{
|
||||||
|
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), "Ram execute never lock underflow (< 0)", mem_xn_lock);
|
||||||
|
}
|
||||||
|
mem_xn_lock--;
|
||||||
|
if (mem_xn_lock == 0) {
|
||||||
|
mbed_mpu_enable_ram_xn(true);
|
||||||
|
}
|
||||||
|
core_util_critical_section_exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
void mbed_mpu_manager_lock_rom_write()
|
||||||
|
{
|
||||||
|
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_write()
|
||||||
|
{
|
||||||
|
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();
|
||||||
|
}
|
|
@ -0,0 +1,90 @@
|
||||||
|
/** \addtogroup platform */
|
||||||
|
/** @{*/
|
||||||
|
/**
|
||||||
|
* \defgroup platform_mpu_mgmt MPU management functions
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* mbed Microcontroller Library
|
||||||
|
* Copyright (c) 2006-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_MPU_MGMT_H
|
||||||
|
#define MBED_MPU_MGMT_H
|
||||||
|
|
||||||
|
#include "hal/sleep_api.h"
|
||||||
|
#include "mbed_toolchain.h"
|
||||||
|
#include "hal/ticker_api.h"
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** Lock ram execute never mode off
|
||||||
|
*
|
||||||
|
* This disables the MPU's execute never ram protection and allows
|
||||||
|
* functions to run from RAM. Execution directly from ram will be
|
||||||
|
* allowed if this function is invoked at least once (the internal
|
||||||
|
* counter is non-zero).
|
||||||
|
*
|
||||||
|
* Use this locking mechanism for code which needs to execute from
|
||||||
|
* ram such as flash programming algorithms and ram thunks.
|
||||||
|
*
|
||||||
|
* The lock is a counter, can be locked up to USHRT_MAX
|
||||||
|
* This function is IRQ and thread safe
|
||||||
|
*/
|
||||||
|
void mbed_mpu_manager_lock_ram_execution(void);
|
||||||
|
|
||||||
|
/** Unlock ram execute never mode
|
||||||
|
*
|
||||||
|
* Use unlocking in pair with mbed_mpu_manager_lock_ram_execution().
|
||||||
|
*
|
||||||
|
* The lock is a counter, should be equally unlocked as locked
|
||||||
|
* This function is IRQ and thread safe
|
||||||
|
*/
|
||||||
|
void mbed_mpu_manager_unlock_ram_execution(void);
|
||||||
|
|
||||||
|
/** Lock rom write never mode off
|
||||||
|
*
|
||||||
|
* This disables the MPU's read only 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_write(void);
|
||||||
|
|
||||||
|
/** Unlock rom write never mode
|
||||||
|
*
|
||||||
|
* Use unlocking in pair with mbed_mpu_manager_lock_rom_write().
|
||||||
|
*
|
||||||
|
* The lock is a counter, should be equally unlocked as locked
|
||||||
|
* This function is IRQ and thread safe
|
||||||
|
*/
|
||||||
|
void mbed_mpu_manager_unlock_rom_write(void);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** @}*/
|
||||||
|
/** @}*/
|
|
@ -76,6 +76,7 @@
|
||||||
#include "mbed_toolchain.h"
|
#include "mbed_toolchain.h"
|
||||||
#include "mbed_boot.h"
|
#include "mbed_boot.h"
|
||||||
#include "mbed_error.h"
|
#include "mbed_error.h"
|
||||||
|
#include "mpu_api.h"
|
||||||
|
|
||||||
int main(void);
|
int main(void);
|
||||||
static void mbed_cpy_nvic(void);
|
static void mbed_cpy_nvic(void);
|
||||||
|
@ -86,6 +87,9 @@ uint32_t mbed_stack_isr_size = 0;
|
||||||
|
|
||||||
void mbed_init(void)
|
void mbed_init(void)
|
||||||
{
|
{
|
||||||
|
mbed_mpu_init();
|
||||||
|
mbed_mpu_enable_ram_xn(true);
|
||||||
|
mbed_mpu_enable_rom_wn(true);
|
||||||
mbed_cpy_nvic();
|
mbed_cpy_nvic();
|
||||||
mbed_sdk_init();
|
mbed_sdk_init();
|
||||||
mbed_rtos_init();
|
mbed_rtos_init();
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue