1 /*
2 * Copyright (c) 2020 HiSilicon (Shanghai) Technologies CO., LIMITED.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 * Description: PANIC module implementation
15 * Author:
16 * Create:
17 */
18 #include "systick.h"
19 #include "non_os.h"
20 #ifdef SUPPORT_DFX_PRESERVE
21 #include "preserve.h"
22 #endif
23 #include "soc_osal.h"
24 #include "arch_barrier.h"
25 #ifdef SUPPORT_CPU_TRACE
26 #include "cpu_trace.h"
27 #endif
28 #ifdef SUPPORT_DFX_LOG
29 #include "log_oml_exception.h"
30 #include "log_def.h"
31 #include "log_printf.h"
32 #include "diag_log.h"
33 #endif
34 #include "debug_print.h"
35
36 #ifdef USE_CMSIS_OS
37 #ifdef __LITEOS__
38 #include "los_task_pri.h"
39 #endif
40 #endif
41 #ifdef SUPPORT_CPU_UTILS
42 #include "cpu_utils.h"
43 #endif
44 #ifdef SUPPORT_CRASH_DATA_RAM
45 #include "crash_data.h"
46 #endif
47
48 #ifdef SUPPORT_WATCHDOG
49 #include "watchdog.h"
50 #endif
51 #include "panic.h"
52
53 #define NON_OS_ENTER_MAX_NUM 8
54 #define MAX_STR_LEN 64
55
56 static bool g_already_panicking = false;
57
58 static lib_panic_dump_callback g_panic_dump_callback = NULL;
59 #ifdef SUPPORT_CPU_TRACE
60 static uint32_t g_panic_cpu_trace_pc = 0x0;
61 static uint32_t g_panic_cpu_trace_lr = 0x0;
62 static uint32_t g_panic_cpu_trace_sp = 0x0;
63 #endif
64
65 #if defined(__ICCARM__)
66 static lib_panic_dump_callback_with_param g_panic_dump_wear_callback = NULL;
67 #endif
68
69 #if (CORE == BT) && (NON_OS_CRITICAL_RECORD == YES)
70 static volatile uint32_t g_non_os_critical_enter_lr[NON_OS_ENTER_MAX_NUM] = { 0 };
71 static volatile uint32_t g_non_os_critical_exit_lr[NON_OS_ENTER_MAX_NUM] = { 0 };
72 #endif
73
register_panic_dump_callback(lib_panic_dump_callback callback)74 void register_panic_dump_callback(lib_panic_dump_callback callback)
75 {
76 if (callback != NULL) {
77 g_panic_dump_callback = callback;
78 }
79 }
80
81 #if defined(__ICCARM__)
register_panic_dump_callback_with_param(lib_panic_dump_callback_with_param callback)82 void register_panic_dump_callback_with_param(lib_panic_dump_callback_with_param callback)
83 {
84 if (callback != NULL) {
85 g_panic_dump_wear_callback = callback;
86 }
87 }
88 #endif
89
panic_trigger_callback_with_param(panic_id_t origin,uint32_t code,uint32_t caller)90 static bool panic_trigger_callback_with_param(panic_id_t origin, uint32_t code, uint32_t caller)
91 {
92 UNUSED(origin);
93 UNUSED(code);
94 UNUSED(caller);
95 #if defined(__ICCARM__)
96 char str[MAX_STR_LEN] = { 0 };
97 int ret = sprintf_s(str, sizeof(str), "panic:origin:0x%X, code:0x%X, caller:0x%X", origin, code, caller);
98 if (ret < 0) {
99 return false;
100 }
101 PRINT("set info err: ret:%d, id:%d, code:0x%x, call:0x%x", ret, origin, code, caller);
102 if (g_panic_dump_wear_callback != NULL) {
103 g_panic_dump_wear_callback(str);
104 }
105 return true;
106 #else
107 return false;
108 #endif
109 }
110
111 #if (CORE == BT) && (NON_OS_CRITICAL_RECORD == YES)
panic_critical_record(critical_statistic_mode_e mode,uint32_t address,uint16_t nestings)112 static void panic_critical_record(critical_statistic_mode_e mode, uint32_t address, uint16_t nestings)
113 {
114 UNUSED(mode);
115 UNUSED(address);
116 UNUSED(nestings);
117 if (mode == CRITICAL_ENTER) {
118 if ((get_already_panicking() == false) && (nestings < NON_OS_ENTER_MAX_NUM)) {
119 g_non_os_critical_enter_lr[nestings] = address;
120 }
121 } else {
122 if ((get_already_panicking() == false) && (nestings < NON_OS_ENTER_MAX_NUM)) {
123 g_non_os_critical_exit_lr[nestings] = address;
124 }
125 }
126 }
127 #endif
128
panic_init(void)129 void panic_init(void)
130 {
131 panic_register_deal_callback(panic_deal);
132 #if (CORE == BT) && (NON_OS_CRITICAL_RECORD == YES)
133 non_os_register_critical_record(panic_critical_record);
134 #endif
135 }
136
panic_deinit(void)137 void panic_deinit(void) {}
138
panic_wait_forever(void)139 void panic_wait_forever(void)
140 {
141 // unlike the hardfault handler 'i' does not need to be static, since we trust our stack
142 volatile uint8_t i = 1;
143 // Loop forever - or until jlink changes i
144 while (i != 0) {
145 #ifdef SUPPORT_WATCHDOG
146 uapi_watchdog_kick();
147 #endif
148 }
149 }
150
get_already_panicking(void)151 bool get_already_panicking(void)
152 {
153 return g_already_panicking;
154 }
155
panic_deal_log(panic_id_t origin,uint32_t code,uint32_t caller)156 static void panic_deal_log(panic_id_t origin, uint32_t code, uint32_t caller)
157 {
158 UNUSED(origin);
159 UNUSED(code);
160 UNUSED(caller);
161 #ifdef SUPPORT_DFX_LOG
162 uapi_diag_error_log3(0, "[panic]id:%d,code:0x%x,call:0x%x", origin, code, caller);
163 #endif
164 PRINT("[panic]id:%d,code:0x%x,call:0x%x", origin, code, caller); // Caller need +5 maybe.
165
166 #ifdef SUPPORT_CPU_TRACE
167 hal_cpu_trace_traced_cpu_t cpu;
168 cpu = HAL_CPU_TRACE_TRACED_BCPU;
169 #if CORE == BT
170 cpu = HAL_CPU_TRACE_TRACED_MCPU;
171 #endif
172 cpu_trace_get_locked_regs(cpu, &g_panic_cpu_trace_pc, &g_panic_cpu_trace_lr, &g_panic_cpu_trace_sp);
173 #ifdef SUPPORT_DFX_LOG
174 uapi_diag_error_log3(0, "[panic]core:%d,pc:0x%x,lr:0x%x", cpu, g_panic_cpu_trace_pc, g_panic_cpu_trace_lr);
175 #endif
176 PRINT("[panic]core:%d,pc:0x%x,lr:0x%x", cpu, g_panic_cpu_trace_pc, g_panic_cpu_trace_lr);
177 #endif
178 }
179
180 #ifdef SUPPORT_DFX_PRESERVE
panic_set_desc(panic_id_t origin,uint32_t code,uint32_t caller)181 static void panic_set_desc(panic_id_t origin, uint32_t code, uint32_t caller)
182 {
183 panic_desc_t panic_desc;
184 panic_desc.origin = origin;
185 panic_desc.code = code;
186 panic_desc.timestamp_ms = (uint32_t)uapi_systick_get_us();
187 panic_desc.caller = caller;
188 set_last_panic(&panic_desc);
189 }
190
panic_set_exception_info(exception_info_t * exception_info)191 static void panic_set_exception_info(exception_info_t *exception_info)
192 {
193 #ifdef USE_CMSIS_OS
194 #ifdef __LITEOS__
195 TSK_INFO_S task_info;
196 uint32_t task_id;
197
198 task_id = LOS_CurTaskIDGet();
199 if (LOS_TaskInfoGet(task_id, &task_info) != LOS_OK) {
200 return;
201 }
202 exception_info->sp_bottom = task_info.uwBottomOfStack;
203 exception_info->exp_task_id = task_id;
204 exception_info->task_array = (unsigned long)(uintptr_t)OS_TCB_FROM_TID(0);
205 exception_info->task_max_num = g_taskMaxNum + 1; // an additional task saves the running task information.
206 #endif
207 #endif
208 set_exception_info(exception_info);
209 }
210 #endif
211
212 #if defined(SUPPORT_CPU_UTILS) && defined(SUPPORT_DFX_PRESERVE)
panic_set_cause(void)213 __attribute__((unused)) static void panic_set_cause(void)
214 {
215 reboot_cause_t cause = REBOOT_CAUSE_APPLICATION_PANIC;
216 cpu_utils_set_system_status_by_cause(cause);
217 }
218 #endif
219
panic_deal_wait(void)220 static void panic_deal_wait(void)
221 {
222 #ifndef NO_TIMEOUT
223 #if CORE == APPS && defined(SUPPORT_CPU_UTILS)
224 cpu_utils_reset_chip_with_log((cores_t)APPS, REBOOT_CAUSE_APPLICATION_PANIC);
225 #elif CORE == BT
226 reboot_system(REBOOT_CAUSE_BT_PANIC);
227 panic_wait_forever(); // Need request apps core to deal reboot.
228 #elif CORE == GNSS
229 reboot_system(REBOOT_CAUSE_GNSS_PANIC);
230 panic_wait_forever(); // Need request apps core to deal reboot.
231 #endif
232 #else
233 panic_wait_forever();
234 #endif
235 }
236
panic_deal(panic_id_t origin,uint32_t code,uint32_t caller)237 void panic_deal(panic_id_t origin, uint32_t code, uint32_t caller)
238 {
239 if (panic_trigger_callback_with_param(origin, code, caller) == true) { return; }
240
241 #ifdef SUPPORT_CPU_TRACE
242 cpu_trace_disable();
243 #endif
244
245 panic_deal_log(origin, code, caller);
246
247 uint32_t irq = osal_irq_lock();
248
249 if (!g_already_panicking) {
250 g_already_panicking = true;
251 #ifdef SUPPORT_DFX_PRESERVE
252 #if (defined(CHIP_SW39) && (CHIP_SW39 == 1))
253 duplicate_app_preserve_mem();
254 #endif
255 #ifdef SUPPORT_CRASH_DATA_RAM
256 crash_data_clear();
257 crash_data_set_time_s();
258 #endif
259 panic_set_desc(origin, code, caller);
260
261 exception_info_t exception_info = { 0 };
262 exception_stack_frame_t exception_stack_frame = { 0 };
263 exception_stack_frame.stacked_lr = caller;
264 get_temp_pc(exception_stack_frame.stacked_pc);
265 get_temp_sp(exception_info.sp); // Backtracking parsing from the panic function
266 #if (ARCH == CM3) || (ARCH == CM7)
267 /* // the m3 core r7 is usually saved as the SP reference and is used for sp recovery. */
268 __asm volatile("MOV %0, R7" : "=r"(exception_info.regs[3]));
269 #endif
270 panic_set_exception_info(&exception_info);
271 set_exception_stack_frame(&exception_stack_frame);
272 #if (defined BUILD_APPLICATION_STANDARD) && (CORE == MASTER_BY_ALL)
273 set_exception_time_stamp();
274 /* set reboot cause before memory dump */
275 panic_set_cause();
276 #if defined(SUPPORT_CRASH_DATA_RAM) && defined(SAVE_EXC_INFO)
277 crash_data_save();
278 #endif
279 #endif
280 #endif
281 }
282
283 if (g_panic_dump_callback != NULL) { g_panic_dump_callback(); }
284
285 #ifdef SUPPORT_DFX_LOG
286 // Dump whole memory
287 log_oml_memory_dump();
288 #endif
289 panic_deal_wait();
290 osal_irq_restore(irq);
291 }
292