mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
Merge pull request #11358 from fjmolinas/riot-cortexm-address-check
cpu/cortexm_common: function to check address validity
This commit is contained in:
commit
cbc08edcd1
@ -874,6 +874,9 @@ FEATURES_USED := $(sort $(FEATURES_REQUIRED) $(filter $(FEATURES_OPTIONAL),$(FEA
|
||||
# all periph features correspond to a periph submodule
|
||||
USEMODULE += $(filter periph_%,$(FEATURES_USED))
|
||||
|
||||
# select cpu_check_address pseudomodule if the corresponding feature is used
|
||||
USEMODULE += $(filter cpu_check_address, $(FEATURES_USED))
|
||||
|
||||
# recursively catch transitive dependencies
|
||||
USEMODULE := $(sort $(USEMODULE))
|
||||
USEPKG := $(sort $(USEPKG))
|
||||
|
@ -1,2 +1,3 @@
|
||||
FEATURES_PROVIDED += periph_pm
|
||||
FEATURES_PROVIDED += cpp
|
||||
FEATURES_PROVIDED += cpu_check_address
|
||||
|
@ -73,3 +73,53 @@ void cortexm_init(void)
|
||||
cortexm_init_isr_priorities();
|
||||
cortexm_init_misc();
|
||||
}
|
||||
|
||||
bool cpu_check_address(volatile const char *address)
|
||||
{
|
||||
#if defined(CPU_ARCH_CORTEX_M3) || defined(CPU_ARCH_CORTEX_M4) || \
|
||||
defined(CPU_ARCH_CORTEX_M4F) || defined(CPU_ARCH_CORTEX_M7)
|
||||
static const uint32_t BFARVALID_MASK = (0x80 << SCB_CFSR_BUSFAULTSR_Pos);
|
||||
|
||||
bool is_valid = true;
|
||||
|
||||
/* Clear BFARVALID flag */
|
||||
SCB->CFSR |= BFARVALID_MASK;
|
||||
|
||||
/* Ignore BusFault by enabling BFHFNMIGN and disabling interrupts */
|
||||
uint32_t mask = __get_FAULTMASK();
|
||||
__disable_fault_irq();
|
||||
SCB->CCR |= SCB_CCR_BFHFNMIGN_Msk;
|
||||
|
||||
*address;
|
||||
/* Check BFARVALID flag */
|
||||
if ((SCB->CFSR & BFARVALID_MASK) != 0) {
|
||||
/* Bus Fault occured reading the address */
|
||||
is_valid = false;
|
||||
}
|
||||
|
||||
/* Reenable BusFault by clearing BFHFNMIGN */
|
||||
SCB->CCR &= ~SCB_CCR_BFHFNMIGN_Msk;
|
||||
__set_FAULTMASK(mask);
|
||||
|
||||
return is_valid;
|
||||
#else
|
||||
/* Cortex-M0 doesn't have BusFault so we need to catch HardFault */
|
||||
(void)address;
|
||||
|
||||
bool result;
|
||||
|
||||
__asm__ volatile (
|
||||
"movs r5, #1 \n" /* R5 will be set to 0 by HardFault handler */
|
||||
/* to indicate HardFault has occured */
|
||||
"ldr r1, =0xDEADF00D \n" /* set magic number */
|
||||
"ldr r2, =0xCAFEBABE \n" /* 2nd magic to be sure */
|
||||
"ldrb r3, %1 \n" /* probe address */
|
||||
"mov %0, r5 \n" /* store result */
|
||||
: "=r"(result)
|
||||
: "m"(*address)
|
||||
: "r1", "r2", "r3", "r5", "cc"
|
||||
);
|
||||
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
@ -228,6 +228,17 @@ static inline uint32_t cpu_get_image_baseaddr(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Checks is memory address valid or not
|
||||
*
|
||||
* This function can be used to check for memory size,
|
||||
* peripherals availability, etc.
|
||||
*
|
||||
* @param[in] address Address to check
|
||||
* @return true if address is valid
|
||||
*/
|
||||
bool cpu_check_address(volatile const char *address);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -165,6 +165,7 @@ __attribute__((naked)) void hard_fault_default(void)
|
||||
/* Get stack pointer where exception stack frame lies */
|
||||
__asm__ volatile
|
||||
(
|
||||
".syntax unified \n"
|
||||
/* Check that msp is valid first because we want to stack all the
|
||||
* r4-r11 registers so that we can use r0, r1, r2, r3 for other things. */
|
||||
"mov r0, sp \n" /* r0 = msp */
|
||||
@ -188,6 +189,24 @@ __attribute__((naked)) void hard_fault_default(void)
|
||||
" use_psp: \n" /* else { */
|
||||
"mrs r0, psp \n" /* r0 = psp */
|
||||
" out: \n" /* } */
|
||||
#if (defined(CPU_ARCH_CORTEX_M0) || defined(CPU_ARCH_CORTEX_M0PLUS)) \
|
||||
&& defined(MODULE_CPU_CHECK_ADDRESS)
|
||||
/* catch intended HardFaults on Cortex-M0 to probe memory addresses */
|
||||
"ldr r1, [r0, #0x04] \n" /* read R1 from the stack */
|
||||
"ldr r2, =0xDEADF00D \n" /* magic number to be found */
|
||||
"cmp r1, r2 \n" /* compare with the magic number */
|
||||
"bne regular_handler \n" /* no magic -> handle as usual */
|
||||
"ldr r1, [r0, #0x08] \n" /* read R2 from the stack */
|
||||
"ldr r2, =0xCAFEBABE \n" /* 2nd magic number to be found */
|
||||
"cmp r1, r2 \n" /* compare with 2nd magic number */
|
||||
"bne regular_handler \n" /* no magic -> handle as usual */
|
||||
"ldr r1, [r0, #0x18] \n" /* read PC from the stack */
|
||||
"adds r1, r1, #2 \n" /* move to the next instruction */
|
||||
"str r1, [r0, #0x18] \n" /* modify PC in the stack */
|
||||
"ldr r5, =0 \n" /* set R5 to indicate HardFault */
|
||||
"bx lr \n" /* exit the exception handler */
|
||||
" regular_handler: \n"
|
||||
#endif
|
||||
#if defined(CPU_ARCH_CORTEX_M0) || defined(CPU_ARCH_CORTEX_M0PLUS) \
|
||||
|| defined(CPU_ARCH_CORTEX_M23)
|
||||
"push {r4-r7} \n" /* save r4..r7 to the stack */
|
||||
|
@ -8,6 +8,7 @@ PSEUDOMODULES += conn_can_isotp_multi
|
||||
PSEUDOMODULES += cord_ep_standalone
|
||||
PSEUDOMODULES += core_%
|
||||
PSEUDOMODULES += cortexm_fpu
|
||||
PSEUDOMODULES += cpu_check_address
|
||||
PSEUDOMODULES += ecc_%
|
||||
PSEUDOMODULES += emb6_router
|
||||
PSEUDOMODULES += event_%
|
||||
|
10
tests/cpu_cortexm_address_check/Makefile
Normal file
10
tests/cpu_cortexm_address_check/Makefile
Normal file
@ -0,0 +1,10 @@
|
||||
BOARD ?= samr21-xpro
|
||||
|
||||
include ../Makefile.tests_common
|
||||
|
||||
FEATURES_REQUIRED += cpu_check_address
|
||||
|
||||
USEMODULE += shell
|
||||
USEMODULE += shell_commands
|
||||
|
||||
include $(RIOTBASE)/Makefile.include
|
12
tests/cpu_cortexm_address_check/README.md
Normal file
12
tests/cpu_cortexm_address_check/README.md
Normal file
@ -0,0 +1,12 @@
|
||||
# Cortex-M check for memory address validity
|
||||
|
||||
## Introduction
|
||||
Cortex-M3/M4/M7-based MCUs allow to check memory address validity
|
||||
by temporarily blocking BusFault handler.
|
||||
|
||||
Validity check can be used to determine RAM/flash/EEPROM sizes,
|
||||
peripherals availability, etc., to create firmware that runs
|
||||
effectively on different MCUs without recompiling.
|
||||
|
||||
NB: Cortex-M0 and Cortex-M0+ don't have BusFault events, all
|
||||
bus errors escalate to HardFault immediately.
|
65
tests/cpu_cortexm_address_check/main.c
Normal file
65
tests/cpu_cortexm_address_check/main.c
Normal file
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Unwired Devices LLC
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ingroup tests
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Test application for Cortex-M address checks
|
||||
*
|
||||
* @author Oleg Artamonov <oleg@unwds.com>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "cpu.h"
|
||||
#include "shell.h"
|
||||
|
||||
static int cmd_check(int argc, char **argv)
|
||||
{
|
||||
if (argc < 2) {
|
||||
printf("usage: %s <hex address>\n", argv[0]);
|
||||
printf("\t example: %s 0x08080000\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
char *address;
|
||||
uint32_t address_value = strtoul(argv[1], NULL, 0);
|
||||
|
||||
address = (char *)address_value;
|
||||
|
||||
if (cpu_check_address(address))
|
||||
printf("Address 0x%08" PRIx32 " is valid. Feel free to access it\n", address_value);
|
||||
else
|
||||
printf("Address 0x%08" PRIx32 " is NOT valid. Accessing it will result in BusFault\n", address_value);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const shell_command_t shell_commands[] = {
|
||||
{ "check", "Check address", cmd_check},
|
||||
{ NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
int main(void)
|
||||
{
|
||||
puts("Address check test\n");
|
||||
puts("Please refer to the README.md for more details\n");
|
||||
puts("usage: check <hex address>");
|
||||
puts("\texample: check 0x08080000");
|
||||
|
||||
/* run the shell */
|
||||
char line_buf[SHELL_DEFAULT_BUFSIZE];
|
||||
shell_run(shell_commands, line_buf, SHELL_DEFAULT_BUFSIZE);
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user