1
0
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:
Juan I Carrano 2019-05-13 11:50:48 +02:00 committed by GitHub
commit cbc08edcd1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 172 additions and 0 deletions

View File

@ -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))

View File

@ -1,2 +1,3 @@
FEATURES_PROVIDED += periph_pm
FEATURES_PROVIDED += cpp
FEATURES_PROVIDED += cpu_check_address

View File

@ -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
}

View File

@ -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

View File

@ -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 */

View File

@ -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_%

View 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

View 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.

View 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;
}