1 /*
2  * Copyright (c) 2020 Intel Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 #include <zephyr/kernel.h>
7 #include <zephyr/ztest.h>
8 
9 
10 #if defined(CONFIG_ZTEST_FATAL_HOOK)
11 /* This is a flag indicate if treating fatal error as expected, then take
12  * action dealing with it. It's SMP-safe.
13  */
14 ZTEST_BMEM volatile bool fault_in_isr;
15 ZTEST_BMEM volatile k_tid_t valid_fault_tid;
16 
reset_stored_fault_status(void)17 static inline void reset_stored_fault_status(void)
18 {
19 	valid_fault_tid = NULL;
20 	fault_in_isr = false;
21 }
22 
z_impl_ztest_set_fault_valid(bool valid)23 void z_impl_ztest_set_fault_valid(bool valid)
24 {
25 	if (valid) {
26 		if (k_is_in_isr()) {
27 			fault_in_isr = true;
28 		} else {
29 			valid_fault_tid = k_current_get();
30 		}
31 	} else {
32 		reset_stored_fault_status();
33 	}
34 }
35 
36 #if defined(CONFIG_USERSPACE)
z_vrfy_ztest_set_fault_valid(bool valid)37 static inline void z_vrfy_ztest_set_fault_valid(bool valid)
38 {
39 	z_impl_ztest_set_fault_valid(valid);
40 }
41 #include <syscalls/ztest_set_fault_valid_mrsh.c>
42 #endif
43 
ztest_post_fatal_error_hook(unsigned int reason,const z_arch_esf_t * pEsf)44 __weak void ztest_post_fatal_error_hook(unsigned int reason,
45 		const z_arch_esf_t *pEsf)
46 {
47 }
48 
k_sys_fatal_error_handler(unsigned int reason,const z_arch_esf_t * pEsf)49 void k_sys_fatal_error_handler(unsigned int reason, const z_arch_esf_t *pEsf)
50 {
51 	k_tid_t curr_tid = k_current_get();
52 	bool valid_fault = (curr_tid == valid_fault_tid) || fault_in_isr;
53 
54 	printk("Caught system error -- reason %d %d\n", reason, valid_fault);
55 
56 	if (valid_fault) {
57 		printk("Fatal error expected as part of test case.\n");
58 
59 		/* reset back to normal */
60 		reset_stored_fault_status();
61 
62 		/* do some action after expected fatal error happened */
63 		ztest_post_fatal_error_hook(reason, pEsf);
64 	} else {
65 		printk("Fatal error was unexpected, aborting...\n");
66 		k_fatal_halt(reason);
67 	}
68 }
69 #endif
70 
71 
72 #if defined(CONFIG_ZTEST_ASSERT_HOOK)
73 /* This is a flag indicate if treating assert fail as expected, then take
74  * action dealing with it. It's SMP-safe.
75  */
76 ZTEST_BMEM volatile bool assert_in_isr;
77 ZTEST_BMEM volatile k_tid_t valid_assert_tid;
78 
reset_stored_assert_status(void)79 static inline void reset_stored_assert_status(void)
80 {
81 	valid_assert_tid = NULL;
82 	assert_in_isr = 0;
83 }
84 
z_impl_ztest_set_assert_valid(bool valid)85 void z_impl_ztest_set_assert_valid(bool valid)
86 {
87 	if (valid) {
88 		if (k_is_in_isr()) {
89 			assert_in_isr = true;
90 		} else {
91 			valid_assert_tid = k_current_get();
92 		}
93 	} else {
94 		reset_stored_assert_status();
95 	}
96 }
97 
98 #if defined(CONFIG_USERSPACE)
z_vrfy_ztest_set_assert_valid(bool valid)99 static inline void z_vrfy_ztest_set_assert_valid(bool valid)
100 {
101 	z_impl_ztest_set_assert_valid(valid);
102 }
103 #include <syscalls/ztest_set_assert_valid_mrsh.c>
104 #endif
105 
ztest_post_assert_fail_hook(void)106 __weak void ztest_post_assert_fail_hook(void)
107 {
108 	k_thread_abort(k_current_get());
109 
110 	CODE_UNREACHABLE;
111 }
112 
113 #ifdef CONFIG_ASSERT_NO_FILE_INFO
assert_post_action(void)114 void assert_post_action(void)
115 #else
116 void assert_post_action(const char *file, unsigned int line)
117 #endif
118 {
119 #ifndef CONFIG_ASSERT_NO_FILE_INFO
120 	ARG_UNUSED(file);
121 	ARG_UNUSED(line);
122 #endif
123 
124 	printk("Caught assert failed\n");
125 
126 	if ((k_current_get() == valid_assert_tid) || assert_in_isr) {
127 		printk("Assert error expected as part of test case.\n");
128 
129 		/* reset back to normal */
130 		reset_stored_assert_status();
131 
132 		/* It won't go back to caller when assert failed, and it
133 		 * will terminate the thread.
134 		 */
135 		ztest_post_assert_fail_hook();
136 	} else {
137 		printk("Assert failed was unexpected, aborting...\n");
138 #ifdef CONFIG_USERSPACE
139 	/* User threads aren't allowed to induce kernel panics; generate
140 	 * an oops instead.
141 	 */
142 		if (k_is_user_context()) {
143 			k_oops();
144 		}
145 #endif
146 		k_panic();
147 	}
148 }
149 #endif
150