Skip to content

Commit 52822cb

Browse files
authored
Merge pull request #8871 from c1728p9/mpu
MPU API (Reopened)
2 parents e62abd8 + a236896 commit 52822cb

File tree

17 files changed

+1411
-120
lines changed

17 files changed

+1411
-120
lines changed

TESTS/mbed_hal/flash/functional_tests/main.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "utest/utest.h"
2222
#include "unity/unity.h"
2323
#include "greentea-client/test_env.h"
24+
#include "platform/mbed_mpu_mgmt.h"
2425

2526
#include "mbed.h"
2627
#include "flash_api.h"
@@ -251,11 +252,22 @@ Case cases[] = {
251252

252253
utest::v1::status_t greentea_test_setup(const size_t number_of_cases)
253254
{
255+
mbed_mpu_manager_lock_ram_execution();
256+
mbed_mpu_manager_lock_rom_write();
257+
254258
GREENTEA_SETUP(20, "default_auto");
255259
return greentea_test_setup_handler(number_of_cases);
256260
}
257261

258-
Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler);
262+
void greentea_test_teardown(const size_t passed, const size_t failed, const failure_t failure)
263+
{
264+
mbed_mpu_manager_unlock_ram_execution();
265+
mbed_mpu_manager_unlock_rom_write();
266+
267+
greentea_test_teardown_handler(passed, failed, failure);
268+
}
269+
270+
Specification specification(greentea_test_setup, cases, greentea_test_teardown);
259271

260272
int main()
261273
{

TESTS/mbed_hal/mpu/main.cpp

Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
/* mbed Microcontroller Library
2+
* Copyright (c) 2017 ARM Limited
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#include "utest/utest.h"
18+
#include "unity/unity.h"
19+
#include "greentea-client/test_env.h"
20+
21+
#include "cmsis.h"
22+
#include <stdlib.h>
23+
24+
#include "mpu_api.h"
25+
#include "mpu_test.h"
26+
27+
#if !DEVICE_MPU
28+
#error [NOT_SUPPORTED] MPU API not supported for this target
29+
#endif
30+
31+
using namespace utest::v1;
32+
33+
#define HARDFAULT_IRQn ((IRQn_Type)-13)
34+
#define MEMFAULT_IRQn ((IRQn_Type)-12)
35+
36+
// Assembly return instruction: bx lr
37+
#define ASM_BX_LR 0x4770
38+
39+
volatile uint32_t fault_count;
40+
uint32_t real_hard_fault_handler;
41+
uint32_t real_mem_fault_handler;
42+
43+
static volatile uint16_t data_function = ASM_BX_LR;
44+
static volatile uint16_t bss_function;
45+
46+
static void clear_caches()
47+
{
48+
#if defined(__CORTEX_M7)
49+
/* Data cache clean and invalid */
50+
SCB_CleanInvalidateDCache();
51+
52+
/* Instruction cache invalid */
53+
SCB_InvalidateICache();
54+
#endif
55+
56+
__ISB();
57+
__DSB();
58+
59+
}
60+
61+
static void call_mem(const volatile uint16_t *mem_function)
62+
{
63+
// or the address with 1 to ensure the thumb bit is set
64+
((void (*)())((uint32_t)mem_function | 1))();
65+
}
66+
67+
static void hard_fault_handler_test()
68+
{
69+
fault_count++;
70+
mbed_mpu_enable_ram_xn(false);
71+
}
72+
73+
static void mpu_fault_test(const volatile uint16_t *mem_function)
74+
{
75+
mbed_mpu_init();
76+
77+
// Verify that the mpu causes faults when executing ram
78+
fault_count = 0;
79+
mbed_mpu_enable_ram_xn(true);
80+
call_mem(mem_function);
81+
TEST_ASSERT_EQUAL(1, fault_count);
82+
83+
// Verify that the mpu can be turned off
84+
fault_count = 0;
85+
mbed_mpu_enable_ram_xn(false);
86+
call_mem(mem_function);
87+
TEST_ASSERT_EQUAL(0, fault_count);
88+
89+
// Verify that the mpu causes faults when executing ram
90+
fault_count = 0;
91+
mbed_mpu_enable_ram_xn(true);
92+
call_mem(mem_function);
93+
TEST_ASSERT_EQUAL(1, fault_count);
94+
95+
// Verify that free turns off the mpu
96+
fault_count = 0;
97+
mbed_mpu_free();
98+
call_mem(mem_function);
99+
TEST_ASSERT_EQUAL(0, fault_count);
100+
}
101+
102+
void mpu_init_test()
103+
{
104+
for (int i = 0; i < 10; i++) {
105+
mbed_mpu_init();
106+
}
107+
108+
mbed_mpu_free();
109+
}
110+
111+
void mpu_free_test()
112+
{
113+
mbed_mpu_init();
114+
115+
// Enable the MPU
116+
mbed_mpu_enable_ram_xn(true);
117+
118+
// Free and ensure execution from RAM is allowed
119+
mbed_mpu_free();
120+
121+
call_mem(&data_function);
122+
}
123+
124+
void mpu_fault_test_data()
125+
{
126+
mpu_fault_test(&data_function);
127+
}
128+
129+
void mpu_fault_test_bss()
130+
{
131+
bss_function = ASM_BX_LR;
132+
clear_caches();
133+
mpu_fault_test(&bss_function);
134+
}
135+
136+
void mpu_fault_test_stack()
137+
{
138+
uint16_t stack_function;
139+
140+
stack_function = ASM_BX_LR;
141+
clear_caches();
142+
mpu_fault_test(&stack_function);
143+
}
144+
145+
void mpu_fault_test_heap()
146+
{
147+
uint16_t *heap_function = (uint16_t *)malloc(2);
148+
149+
TEST_ASSERT_NOT_EQUAL(NULL, heap_function);
150+
*heap_function = ASM_BX_LR;
151+
clear_caches();
152+
mpu_fault_test(heap_function);
153+
154+
free(heap_function);
155+
}
156+
157+
utest::v1::status_t fault_override_setup(const Case *const source, const size_t index_of_case)
158+
{
159+
// Save old fault handlers and replace it with a new one
160+
real_hard_fault_handler = NVIC_GetVector(HARDFAULT_IRQn);
161+
real_mem_fault_handler = NVIC_GetVector(MEMFAULT_IRQn);
162+
NVIC_SetVector(HARDFAULT_IRQn, (uint32_t)&hard_fault_handler_test);
163+
NVIC_SetVector(MEMFAULT_IRQn, (uint32_t)&hard_fault_handler_test);
164+
165+
return greentea_case_setup_handler(source, index_of_case);
166+
}
167+
168+
utest::v1::status_t fault_override_teardown(const Case *const source, const size_t passed, const size_t failed,
169+
const failure_t reason)
170+
{
171+
// Restore real fault handlers
172+
NVIC_SetVector(HARDFAULT_IRQn, real_hard_fault_handler);
173+
NVIC_SetVector(MEMFAULT_IRQn, real_mem_fault_handler);
174+
175+
return greentea_case_teardown_handler(source, passed, failed, reason);
176+
}
177+
178+
Case cases[] = {
179+
Case("MPU - init", fault_override_setup, mpu_init_test, fault_override_teardown),
180+
Case("MPU - free", fault_override_setup, mpu_free_test, fault_override_teardown),
181+
#if !((__ARM_ARCH_8M_BASE__ == 1U) || (__ARM_ARCH_8M_MAIN__ == 1U))
182+
// Skip fault tests for ARMv8-M until a fault handler hook is provided
183+
Case("MPU - data fault", fault_override_setup, mpu_fault_test_data, fault_override_teardown),
184+
Case("MPU - bss fault", fault_override_setup, mpu_fault_test_bss, fault_override_teardown),
185+
Case("MPU - stack fault", fault_override_setup, mpu_fault_test_stack, fault_override_teardown),
186+
Case("MPU - heap fault", fault_override_setup, mpu_fault_test_heap, fault_override_teardown)
187+
#endif
188+
};
189+
190+
utest::v1::status_t greentea_test_setup(const size_t number_of_cases)
191+
{
192+
GREENTEA_SETUP(20, "default_auto");
193+
return greentea_test_setup_handler(number_of_cases);
194+
}
195+
196+
Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler);
197+
198+
int main()
199+
{
200+
Harness::run(specification);
201+
}

TESTS/mbed_hal/mpu/mpu_test.h

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
/* mbed Microcontroller Library
2+
* Copyright (c) 2018-2018 ARM Limited
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
/** \addtogroup hal_mpu_tests
18+
* @{
19+
*/
20+
21+
#ifndef MBED_MPU_TEST_H
22+
#define MBED_MPU_TEST_H
23+
24+
#if DEVICE_MPU
25+
26+
#ifdef __cplusplus
27+
extern "C" {
28+
#endif
29+
30+
/** Test that ::mbed_mpu_init can be called multiple times.
31+
*
32+
* Given board provides MPU.
33+
* When ::mbed_mpu_init is called multiple times.
34+
* Then ::mbed_mpu_init are successfully performed (no exception is generated).
35+
*
36+
*/
37+
void mpu_init_test(void);
38+
39+
/** Test that ::mbed_mpu_free disables the MPU
40+
*
41+
* Given board provides MPU.
42+
* When ::mbed_mpu_free is called.
43+
* Then execution from RAM is allowed.
44+
*
45+
*/
46+
void mpu_free_test(void);
47+
48+
/** Test that MPU protection works for global data
49+
*
50+
* Given board provides MPU.
51+
* When RAM execution is disabled with a call to ::mbed_mpu_enable_ram_xn.
52+
* Then execution from global initialized data results in a fault.
53+
*
54+
*/
55+
void mpu_fault_test_data(void);
56+
57+
/** Test that MPU protection works for zero initialized data
58+
*
59+
* Given board provides MPU.
60+
* When RAM execution is disabled with a call to ::mbed_mpu_enable_ram_xn.
61+
* Then execution from global uninitialized data results in a fault.
62+
*
63+
*/
64+
void mpu_fault_test_bss(void);
65+
66+
/** Test that MPU protection works for the stack
67+
*
68+
* Given board provides MPU.
69+
* When RAM execution is disabled with a call to ::mbed_mpu_enable_ram_xn.
70+
* Then execution from stack memory results in a fault.
71+
*
72+
*/
73+
void mpu_fault_test_stack(void);
74+
75+
/** Test that MPU protection works for the heap
76+
*
77+
* Given board provides MPU.
78+
* When RAM execution is disabled with a call to ::mbed_mpu_enable_ram_xn.
79+
* Then execution from heap memory results in a fault.
80+
*
81+
*/
82+
void mpu_fault_test_heap(void);
83+
84+
/**@}*/
85+
86+
#ifdef __cplusplus
87+
}
88+
#endif
89+
90+
#endif
91+
92+
#endif
93+
94+
/** @}*/

doxyfile_options

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2083,6 +2083,7 @@ PREDEFINED = DOXYGEN_ONLY \
20832083
DEVICE_INTERRUPTIN \
20842084
DEVICE_ITM \
20852085
DEVICE_LPTICKER \
2086+
DEVICE_MPU \
20862087
DEVICE_PORTIN \
20872088
DEVICE_PORTINOUT \
20882089
DEVICE_PORTOUT \

doxygen_options.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"SEARCH_INCLUDES": "YES",
77
"INCLUDE_PATH": "",
88
"INCLUDE_FILE_PATTERNS": "",
9-
"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)=\"",
9+
"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)=\"",
1010
"EXPAND_AS_DEFINED": "",
1111
"SKIP_FUNCTION_MACROS": "NO",
1212
"STRIP_CODE_COMMENTS": "NO",

0 commit comments

Comments
 (0)