• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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