diff --git a/TESTS/mbed_hal/spm/fault_functions.h b/TESTS/mbed_hal/spm/fault_functions.h new file mode 100644 index 0000000000..9346bd1b0c --- /dev/null +++ b/TESTS/mbed_hal/spm/fault_functions.h @@ -0,0 +1,48 @@ +/* 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. + */ + +#ifndef __MBED_HAL_SPM_FAULT_FUNCTIONS__ +#define __MBED_HAL_SPM_FAULT_FUNCTIONS__ + +#include "cmsis_compiler.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// Retruns the value of the LR register +// Used to determine which stack the exception happend in +__STATIC_FORCEINLINE uint32_t __get_LR(void); + +// This function is required as we need a symbol/address +// to jump to from fault handler. +void do_nothing(void); + +// Test exception handler +static void hard_fault_handler_test(); + +// Using naked function as it will not be executed from beginning to the end. +// The execution flow expected to be interrupted by exception and we will +// return to other function. +// compiler will not produce prolog and epilog code for naked function +// and thus will preserve stack in un-corrupted state +__attribute__((naked)) void call_mem(uint32_t addr); + +#ifdef __cplusplus +} +#endif + +#endif // __MBED_HAL_SPM_FAULT_FUNCTIONS__ diff --git a/TESTS/mbed_hal/spm/main.cpp b/TESTS/mbed_hal/spm/main.cpp index da0069dcbe..09e6266c5d 100644 --- a/TESTS/mbed_hal/spm/main.cpp +++ b/TESTS/mbed_hal/spm/main.cpp @@ -14,82 +14,74 @@ * limitations under the License. */ +#if !defined(COMPONENT_PSA_SRV_IPC) +#error [NOT_SUPPORTED] Test supported only on PSA targets +#endif + +#if (defined( __CC_ARM ) || defined(__ARMCC_VERSION) || defined( __ICCARM__ )) +#error [NOT_SUPPORTED] this test is supported on GCC only +#endif + #include "utest/utest.h" #include "unity/unity.h" #include "greentea-client/test_env.h" #include "cmsis.h" #include "spm_api.h" #include +#include "fault_functions.h" using namespace utest::v1; -#if !defined(COMPONENT_PSA_SRV_IPC) -#error [NOT_SUPPORTED] Test supported only on PSA targets -#endif -#if !defined ( __GNUC__ ) -#error [NOT_SUPPORTED] this test is supported on GCC only -#endif - -extern "C" { #define HARDFAULT_IRQn ((IRQn_Type)-13) #define EXC_RETURN_RETURN_STACK_MSK ((uint32_t)(0x00000004)) #define PC_INDEX_IN_STACK_FRAME 6 - volatile uint32_t fault_occurred; - uint32_t real_hard_fault_handler; +volatile uint32_t fault_occurred; +uint32_t real_hard_fault_handler; - __attribute__((always_inline)) __STATIC_INLINE uint32_t __get_LR(void) - { - register uint32_t result; +__STATIC_FORCEINLINE uint32_t __get_LR(void) +{ + uint32_t result; - __ASM volatile("MOV %0, LR\n" : "=r"(result)); - return result; + __ASM volatile("MOV %0, lr" : "=r"(result)); + return (result); +} + +void do_nothing(void) +{ + __NOP(); +} + +static void hard_fault_handler_test() +{ + fault_occurred++; + // LR is set EXC_RETURN + // lowest bits identify PSP vs MSP stack used for stacking + uint32_t lr = __get_LR(); + uint32_t sp; + + if (lr & EXC_RETURN_RETURN_STACK_MSK) { + sp = __get_PSP(); + } else { + sp = __get_MSP(); } -// This function is required as we need a symbol/address -// to jump to from fault handler. - void do_nothing(void) - { - __NOP(); - } + // Overwrite return address. + // Fake return to a our special function since current + // instruction under test will always fail due to memory protection + ((uint32_t *)sp)[PC_INDEX_IN_STACK_FRAME] = (uint32_t)do_nothing; +} -// Test exception handler - static void hard_fault_handler_test() - { - fault_occurred++; - // LR is set EXC_RETURN - // lowest bits identify PSP vs MSP stack used for stacking - uint32_t lr = __get_LR(); - uint32_t sp; - - if (lr & EXC_RETURN_RETURN_STACK_MSK) { - sp = __get_PSP(); - } else { - sp = __get_MSP(); - } - - // Overwrite return address. - // Fake return to a our special function since current - // instruction under test will always fail due to memory protection - ((uint32_t *)sp)[PC_INDEX_IN_STACK_FRAME] = (uint32_t)do_nothing; - } - -// Using naked function as it will not be executed from beginning to the end. -// The execution flow expected to be interrupted by exception and we will -// return to other function. -// compiler will not produce prolog and epilog code for naked function -// and thus will preserve stack in un-corrupted state - __attribute__((naked)) void call_mem(uint32_t addr) - { - // Only first instruction will be executed in positive flow, - // since exception will be generated for invalid memory access. - // Other instructions are for calling do_nothing function according to AAPCS. - __ASM( - "LDR r1, [r0]\n" - "BX lr\n" - ); - } +__attribute__((naked)) void call_mem(uint32_t addr) +{ + // Only first instruction will be executed in positive flow, + // since exception will be generated for invalid memory access. + // Other instructions are for calling do_nothing function according to AAPCS. + __ASM( + "LDR r1, [r0]\n" + "BX lr\n" + ); } static void test_memory(uint32_t addr, uint32_t expected_fatal_count)