/* * Copyright (c) @CompanyNameMagicTag 2018-2020. All rights reserved. * Description: PANIC module implementation * Author: @CompanyNameTag * Create: */ #include "systick.h" #ifdef SUPPORT_DFX_PRESERVE #include "preserve.h" #endif #include "non_os.h" #include "arch_barrier.h" #ifdef SUPPORT_CPU_TRACE #include "cpu_trace.h" #endif #ifdef SUPPORT_DFX_LOG #include "soc_diag_util.h" #include "log_oml_exception.h" #include "log_def.h" #include "log_printf.h" #endif #include "debug_print.h" #ifdef USE_CMSIS_OS #ifdef __LITEOS__ #include "los_task_pri.h" #endif #endif #ifdef SUPPORT_CPU_UTILS #include "cpu_utils.h" #endif #ifdef SUPPORT_WATCHDOG #include "watchdog.h" #endif #include "panic.h" #if !defined(BUILD_APPLICATION_SSB) && !defined(BUILD_RECOVERY_IMAGE) #include "calendar_porting.h" #include "tcxo.h" #include "pm.h" #endif #ifdef CFG_DRIVERS_NANDFLASH #include "nandflash_config.h" #endif #include "preserve.h" #include "exception_dump.h" #define NON_OS_ENTER_MAX_NUM 8 #define MAX_STR_LEN 64 #define SELF_HEAL_WAIT_TIME 100 static bool g_already_panicking = false; static lib_panic_dump_callback g_panic_dump_callback = NULL; #ifdef SUPPORT_CPU_TRACE static uint32_t g_panic_cpu_trace_pc = 0x0; static uint32_t g_panic_cpu_trace_lr = 0x0; static uint32_t g_panic_cpu_trace_sp = 0x0; #endif #if defined(__ICCARM__) static lib_panic_dump_callback_with_param g_panic_dump_wear_callback = NULL; #endif #if (CORE == BT) && (NON_OS_CRITICAL_RECORD == YES) static volatile uint32_t g_non_os_critical_enter_lr[NON_OS_ENTER_MAX_NUM] = { 0 }; static volatile uint32_t g_non_os_critical_exit_lr[NON_OS_ENTER_MAX_NUM] = { 0 }; #endif void register_panic_dump_callback(lib_panic_dump_callback callback) { if (callback != NULL) { g_panic_dump_callback = callback; } } #if defined(__ICCARM__) void register_panic_dump_callback_with_param(lib_panic_dump_callback_with_param callback) { if (callback != NULL) { g_panic_dump_wear_callback = callback; } } #endif static bool panic_trigger_callback_with_param(panic_id_t origin, uint32_t code, uint32_t caller) { UNUSED(origin); UNUSED(code); UNUSED(caller); #if defined(__ICCARM__) char str[MAX_STR_LEN] = { 0 }; int ret = sprintf_s(str, sizeof(str), "panic:origin:0x%X, code:0x%X, caller:0x%X", origin, code, caller); if (ret < 0) { return false; } PRINT("set info err: ret:%d, id:%d, code:0x%x, call:0x%x", ret, origin, code, caller); if (g_panic_dump_wear_callback != NULL) { g_panic_dump_wear_callback(str); } return true; #else return false; #endif } #if (CORE == BT) && (NON_OS_CRITICAL_RECORD == YES) static void panic_critical_record(critical_statistic_mode_e mode, uint32_t address, uint16_t nestings) { UNUSED(mode); UNUSED(address); UNUSED(nestings); if (mode == CRITICAL_ENTER) { if ((get_already_panicking() == false) && (nestings < NON_OS_ENTER_MAX_NUM)) { g_non_os_critical_enter_lr[nestings] = address; } } else { if ((get_already_panicking() == false) && (nestings < NON_OS_ENTER_MAX_NUM)) { g_non_os_critical_exit_lr[nestings] = address; } } } #endif void panic_init(void) { panic_register_deal_callback(panic_deal); #if (CORE == BT) && (NON_OS_CRITICAL_RECORD == YES) non_os_register_critical_record(panic_critical_record); #endif } void panic_deinit(void) {} void panic_wait_forever(void) { // unlike the hardfault handler 'i' does not need to be static, since we trust our stack volatile uint8_t i = 1; // Loop forever - or until jlink changes i while (i != 0) { #ifdef SUPPORT_WATCHDOG uapi_watchdog_kick(); #endif } } bool get_already_panicking(void) { return g_already_panicking; } static void panic_deal_log(panic_id_t origin, uint32_t code, uint32_t caller) { UNUSED(code); UNUSED(caller); if (origin != PANIC_ASSERT) { #ifdef SUPPORT_DFX_LOG uapi_diag_error_log3(0, "==[system panic]:id:%d,code:0x%x,call:0x%x", origin, code, caller); #endif PRINT("==[system panic]:id:%d,code:0x%x,call:0x%x", origin, code, caller); // Caller need +5 maybe. } else { #ifdef SUPPORT_DFX_LOG uapi_diag_error_log3(0, "==[system assert]:id:%d,code:0x%x,call:0x%x", origin, code, caller); #endif PRINT("==[system assert]:id:%d,call:0x%x", origin, code); } #ifdef SUPPORT_CPU_TRACE hal_cpu_trace_traced_cpu_t cpu; cpu = HAL_CPU_TRACE_TRACED_BCPU; #if CORE == BT cpu = HAL_CPU_TRACE_TRACED_MCPU; #endif cpu_trace_get_locked_regs(cpu, &g_panic_cpu_trace_pc, &g_panic_cpu_trace_lr, &g_panic_cpu_trace_sp); #ifdef SUPPORT_DFX_LOG uapi_diag_error_log3(0, "==[system panic]:normal core:%d,pc:0x%x,lr:0x%x", cpu, g_panic_cpu_trace_pc, g_panic_cpu_trace_lr); #endif PRINT("==[system panic]:normal core:%d,pc:0x%x,lr:0x%x", cpu, g_panic_cpu_trace_pc, g_panic_cpu_trace_lr); #endif } #ifdef SUPPORT_DFX_PRESERVE static void panic_set_desc(panic_id_t origin, uint32_t code, uint32_t caller) { panic_desc_t panic_desc; panic_desc.origin = origin; panic_desc.code = code; panic_desc.timestamp_ms = (uint32_t)uapi_systick_get_us(); panic_desc.caller = caller; set_last_panic(panic_desc); } static void panic_set_exception_info(exception_info_t *exception_info) { #ifdef USE_CMSIS_OS #ifdef __LITEOS__ TSK_INFO_S task_info; uint32_t task_id; task_id = LOS_CurTaskIDGet(); LOS_TaskInfoGet(task_id, &task_info); exception_info->sp_bottom = task_info.uwBottomOfStack; exception_info->exp_task_id = task_id; exception_info->task_array = (unsigned long)(uintptr_t)OS_TCB_FROM_TID(0); exception_info->task_max_num = g_taskMaxNum + 1; // an additional task saves the running task information. #endif #endif set_exception_info(exception_info); } #endif #if defined(SUPPORT_CPU_UTILS) && defined(SUPPORT_DFX_PRESERVE) __attribute__((unused)) static void panic_set_cause(void) { reboot_cause_t cause = REBOOT_CAUSE_APPLICATION_PANIC; cpu_utils_set_system_status_by_cause(cause); } #endif static void panic_deal_wait(void) { #ifndef NO_TIMEOUT #if CORE == APPS && defined(SUPPORT_CPU_UTILS) cpu_utils_reset_chip_with_log((cores_t)APPS, REBOOT_CAUSE_APPLICATION_PANIC); #elif CORE == BT reboot_system(REBOOT_CAUSE_BT_PANIC); panic_wait_forever(); // Need request apps core to deal reboot. #elif CORE == GNSS reboot_system(REBOOT_CAUSE_GNSS_PANIC); panic_wait_forever(); // Need request apps core to deal reboot. #endif #else panic_wait_forever(); #endif } void panic_deal(panic_id_t origin, uint32_t code, uint32_t caller) { if (panic_trigger_callback_with_param(origin, code, caller) == true) { return; } #ifdef SUPPORT_CPU_TRACE cpu_trace_disable(); #endif #if !defined(BUILD_APPLICATION_SSB) && !defined(BUILD_RECOVERY_IMAGE) if (origin == PANIC_BT_STS_ABNORMAL) { uapi_self_heal_timer_enable(); uapi_sys_shipmode(0); uapi_tcxo_delay_ms(SELF_HEAL_WAIT_TIME); } #endif panic_deal_log(origin, code, caller); non_os_enter_critical(); if (!g_already_panicking) { g_already_panicking = true; #ifdef SUPPORT_DFX_PRESERVE panic_set_desc(origin, code, caller); exception_info_t exception_info = { 0 }; exception_stack_frame_t exception_stack_frame = { 0 }; exception_stack_frame.stacked_lr = caller; get_temp_pc(exception_stack_frame.stacked_pc); get_temp_sp(exception_info.sp); // Backtracking parsing from the panic function #if (ARCH == CM3) || (ARCH == CM7) /* // the m3 core r7 is usually saved as the SP reference and is used for sp recovery. */ __asm volatile("MOV %0, R7" : "=r"(exception_info.regs[3])); #endif panic_set_exception_info(&exception_info); set_exception_stack_frame(exception_stack_frame); #if (defined BUILD_APPLICATION_STANDARD) && (CORE == MASTER_BY_ALL) set_exception_time_stamp(); /* set reboot cause before memory dump */ panic_set_cause(); #endif #endif } if (g_panic_dump_callback != NULL) { g_panic_dump_callback(); } #ifdef SUPPORT_DFX_EXCEPTION // Dump whole memory log_oml_memory_dump(); #endif #ifdef CFG_DRIVERS_NANDFLASH nand_driver_init(SPEED_SLOW); set_trans_type(TRANS_BY_CPU_SINGLE_LINE); #if defined(SAVE_EXC_INFO) && (CONFIG_DFX_SUPPORT_FILE_SYSTEM == DFX_YES) dump_all_to_file(); save_preserve_file_to_fs(); #endif #endif panic_deal_wait(); non_os_exit_critical(); }