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