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