1 /*
2 * Copyright (c) 2020 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 /**
8 * @file
9 * @brief ARM Cortex-M debug monitor functions interface based on DWT
10 *
11 */
12
13 #include <zephyr/kernel.h>
14 #include <zephyr/device.h>
15 #include <cortex_m/dwt.h>
16 #include <cortex_m/debug.h>
17
18 /**
19 * @brief Assess whether a debug monitor event should be treated as an error
20 *
21 * This routine checks the status of a debug monitor ()exception, and
22 * evaluates whether this needs to be considered as a processor error.
23 *
24 * @return true if the DM exception is a processor error, otherwise false
25 */
z_arm_debug_monitor_event_error_check(void)26 bool z_arm_debug_monitor_event_error_check(void)
27 {
28 #if defined(CONFIG_NULL_POINTER_EXCEPTION_DETECTION_DWT)
29 /* Assess whether this debug exception was triggered
30 * as a result of a null pointer (R/W) dereferencing.
31 */
32 if (SCB->DFSR & SCB_DFSR_DWTTRAP_Msk) {
33 /* Debug event generated by the DWT unit */
34 if (DWT->FUNCTION0 & DWT_FUNCTION_MATCHED_Msk) {
35 /* DWT Comparator match used for */
36 printk("Null-pointer exception?\n");
37 }
38 __ASSERT((DWT->FUNCTION0 & DWT_FUNCTION_MATCHED_Msk) == 0,
39 "MATCHED flag should have been cleared on read.");
40
41 return true;
42 }
43 if (SCB->DFSR & SCB_DFSR_BKPT_Msk) {
44 /* Treat BKPT events as an error as well (since they
45 * would mean the system would be stuck in an infinite loop).
46 */
47 return true;
48 }
49 #endif /* CONFIG_NULL_POINTER_EXCEPTION_DETECTION_DWT */
50 return false;
51 }
52
53 #if defined(CONFIG_NULL_POINTER_EXCEPTION_DETECTION_DWT)
54
55 /* The area (0x0 - <size>) monitored by DWT needs to be a power of 2,
56 * so we add a build assert that catches it.
57 */
58 BUILD_ASSERT(!(CONFIG_CORTEX_M_NULL_POINTER_EXCEPTION_PAGE_SIZE &
59 (CONFIG_CORTEX_M_NULL_POINTER_EXCEPTION_PAGE_SIZE - 1)),
60 "the size of the partition must be power of 2");
61
z_arm_debug_enable_null_pointer_detection(void)62 int z_arm_debug_enable_null_pointer_detection(void)
63 {
64
65 z_arm_dwt_init();
66 z_arm_dwt_enable_debug_monitor();
67
68 /* Enable null pointer detection by monitoring R/W access to the
69 * memory area 0x0 - <size> that is (or was intentionally left)
70 * unused by the system.
71 */
72
73 #if defined(CONFIG_ARMV8_M_MAINLINE)
74
75 /* ASSERT that we have the comparators needed for the implementation */
76 if (((DWT->CTRL & DWT_CTRL_NUMCOMP_Msk) >> DWT_CTRL_NUMCOMP_Pos) < 2) {
77 __ASSERT(0, "on board DWT does not support the feature\n");
78 return -EINVAL;
79 }
80
81 /* Use comparators 0, 1, R/W access check */
82 DWT->COMP0 = 0;
83 DWT->COMP1 = CONFIG_CORTEX_M_NULL_POINTER_EXCEPTION_PAGE_SIZE - 1;
84
85 DWT->FUNCTION0 = ((0x4 << DWT_FUNCTION_MATCH_Pos) & DWT_FUNCTION_MATCH_Msk) |
86 ((0x1 << DWT_FUNCTION_ACTION_Pos) & DWT_FUNCTION_ACTION_Msk) |
87 ((0x0 << DWT_FUNCTION_DATAVSIZE_Pos) & DWT_FUNCTION_DATAVSIZE_Msk);
88 DWT->FUNCTION1 = ((0x7 << DWT_FUNCTION_MATCH_Pos) & DWT_FUNCTION_MATCH_Msk) |
89 ((0x1 << DWT_FUNCTION_ACTION_Pos) & DWT_FUNCTION_ACTION_Msk) |
90 ((0x0 << DWT_FUNCTION_DATAVSIZE_Pos) & DWT_FUNCTION_DATAVSIZE_Msk);
91 #elif defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE)
92
93 /* ASSERT that we have the comparator needed for the implementation */
94 if (((DWT->CTRL & DWT_CTRL_NUMCOMP_Msk) >> DWT_CTRL_NUMCOMP_Pos) < 1) {
95 __ASSERT(0, "on board DWT does not support the feature\n");
96 return -EINVAL;
97 }
98
99 /* Use comparator 0, R/W access check */
100 DWT->COMP0 = 0;
101
102 DWT->FUNCTION0 = (0x7 << DWT_FUNCTION_FUNCTION_Pos) & DWT_FUNCTION_FUNCTION_Msk;
103
104 /* Set mask according to the desired size */
105 DWT->MASK0 = 32 - __builtin_clzl(CONFIG_CORTEX_M_NULL_POINTER_EXCEPTION_PAGE_SIZE - 1);
106 #endif
107
108 return 0;
109 }
110
111 #endif /* CONFIG_NULL_POINTER_EXCEPTION_DETECTION_DWT */
112