298 lines
8.4 KiB
C
298 lines
8.4 KiB
C
/*
|
|
* 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();
|
|
}
|