-
Notifications
You must be signed in to change notification settings - Fork 3k
MPU API #8335
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
MPU API #8335
Changes from all commits
5f9cb71
b43bee4
83779f5
9ed0c96
f3bf24a
fe6f52c
108e680
e88ba74
f838fc9
a546d22
afff39c
b9a39b7
9871f1c
6907d9c
819fd7c
c36a453
58599cd
01dee4e
6aeceaf
e5b4eb1
da53768
fbb9533
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would it not be more direct to intercept MemManage exception? Would side-step the security issue. (Any prospect of ever needing the combo of MPU + no ARMv8-M Main Extension? Not sure how easy it is to detect to conditionally support both) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unfortunate. Probably not worth doing it here, but if I wanted conditional code, what would the canonical way of testing for Main Extension be? I can see lots of ways of inferring it from what's defined in core_cm23.h versus core_cm33.h, and I can obviously make more specific feature tests, but is there a "master" architecture flag for the concept? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I didn't see a "master" architecture flag for this. The CMSIS MPU functions are checking for |
||
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); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 | ||
|
||
/** @}*/ |
Uh oh!
There was an error while loading. Please reload this page.