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