blob: 3025f74cf2129812adf7d2b8593471d0d31f01f9 [file] [log] [blame]
/*
* Copyright (c) 2020 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @file
* @brief ARM Cortex-M debug monitor functions interface based on DWT
*
*/
#include <zephyr/device.h>
#include <aarch32/cortex_m/dwt.h>
/**
* @brief Assess whether a debug monitor event should be treated as an error
*
* This routine checks the status of a debug monitor ()exception, and
* evaluates whether this needs to be considered as a processor error.
*
* @return true if the DM exception is a processor error, otherwise false
*/
bool z_arm_debug_monitor_event_error_check(void)
{
#if defined(CONFIG_NULL_POINTER_EXCEPTION_DETECTION_DWT)
/* Assess whether this debug exception was triggered
* as a result of a null pointer (R/W) dereferencing.
*/
if (SCB->DFSR & SCB_DFSR_DWTTRAP_Msk) {
/* Debug event generated by the DWT unit */
if (DWT->FUNCTION0 & DWT_FUNCTION_MATCHED_Msk) {
/* DWT Comparator match used for */
printk("Null-pointer exception?\n");
}
__ASSERT((DWT->FUNCTION0 & DWT_FUNCTION_MATCHED_Msk) == 0,
"MATCHED flag should have been cleared on read.");
return true;
}
if (SCB->DFSR & SCB_DFSR_BKPT_Msk) {
/* Treat BKPT events as an error as well (since they
* would mean the system would be stuck in an infinite loop).
*/
return true;
}
#endif /* CONFIG_NULL_POINTER_EXCEPTION_DETECTION_DWT */
return false;
}
#if defined(CONFIG_NULL_POINTER_EXCEPTION_DETECTION_DWT)
/* The area (0x0 - <size>) monitored by DWT needs to be a power of 2,
* so we add a build assert that catches it.
*/
BUILD_ASSERT(!(CONFIG_CORTEX_M_NULL_POINTER_EXCEPTION_PAGE_SIZE &
(CONFIG_CORTEX_M_NULL_POINTER_EXCEPTION_PAGE_SIZE - 1)),
"the size of the partition must be power of 2");
static int z_arm_debug_enable_null_pointer_detection(const struct device *arg)
{
ARG_UNUSED(arg);
z_arm_dwt_init();
z_arm_dwt_enable_debug_monitor();
/* Enable null pointer detection by monitoring R/W access to the
* memory area 0x0 - <size> that is (or was intentionally left)
* unused by the system.
*/
#if defined(CONFIG_ARMV8_M_MAINLINE)
/* ASSERT that we have the comparators needed for the implementation */
if (((DWT->CTRL & DWT_CTRL_NUMCOMP_Msk) >> DWT_CTRL_NUMCOMP_Pos) < 2) {
__ASSERT(0, "on board DWT does not support the feature\n");
return -EINVAL;
}
/* Use comparators 0, 1, R/W access check */
DWT->COMP0 = 0;
DWT->COMP1 = CONFIG_CORTEX_M_NULL_POINTER_EXCEPTION_PAGE_SIZE - 1;
DWT->FUNCTION0 =
((0x4 << DWT_FUNCTION_MATCH_Pos) & DWT_FUNCTION_MATCH_Msk)
|
((0x1 << DWT_FUNCTION_ACTION_Pos) & DWT_FUNCTION_ACTION_Msk)
|
((0x0 << DWT_FUNCTION_DATAVSIZE_Pos) & DWT_FUNCTION_DATAVSIZE_Msk)
;
DWT->FUNCTION1 =
((0x7 << DWT_FUNCTION_MATCH_Pos) & DWT_FUNCTION_MATCH_Msk)
|
((0x1 << DWT_FUNCTION_ACTION_Pos) & DWT_FUNCTION_ACTION_Msk)
|
((0x0 << DWT_FUNCTION_DATAVSIZE_Pos) & DWT_FUNCTION_DATAVSIZE_Msk)
;
#elif defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE)
/* ASSERT that we have the comparator needed for the implementation */
if (((DWT->CTRL & DWT_CTRL_NUMCOMP_Msk) >> DWT_CTRL_NUMCOMP_Pos) < 1) {
__ASSERT(0, "on board DWT does not support the feature\n");
return -EINVAL;
}
/* Use comparator 0, R/W access check */
DWT->COMP0 = 0;
DWT->FUNCTION0 = (0x7 << DWT_FUNCTION_FUNCTION_Pos) &
DWT_FUNCTION_FUNCTION_Msk;
/* Set mask according to the desired size */
DWT->MASK0 = 32 - __builtin_clzl(
CONFIG_CORTEX_M_NULL_POINTER_EXCEPTION_PAGE_SIZE - 1);
#endif
return 0;
}
SYS_INIT(z_arm_debug_enable_null_pointer_detection, PRE_KERNEL_1,
CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);
#endif /* CONFIG_NULL_POINTER_EXCEPTION_DETECTION_DWT */