637 lines
24 KiB
C
637 lines
24 KiB
C
|
|
/*
|
||
|
|
* Copyright (c) CompanyNameMagicTag 2012-2019. All rights reserved.
|
||
|
|
* Description: implementation of error handling of system errors.
|
||
|
|
* Author: CompanyName
|
||
|
|
* Create: 2012-07-14
|
||
|
|
*/
|
||
|
|
|
||
|
|
#include "soc_system_error.h"
|
||
|
|
#include "sal_common.h"
|
||
|
|
|
||
|
|
#include <dfx_sal.h>
|
||
|
|
#include <sal_inf.h>
|
||
|
|
#include <soc_partition_table.h>
|
||
|
|
#include <soc_sal_nv.h>
|
||
|
|
#include <sal_os_dfx.h>
|
||
|
|
#include <soc_mdm_watchdog.h>
|
||
|
|
#include <soc_mdm_task.h>
|
||
|
|
#include <soc_flash_prv.h>
|
||
|
|
#include <securec.h>
|
||
|
|
#include <soc_mdm_time.h>
|
||
|
|
#include <soc_mdm_ver.h>
|
||
|
|
#include <soc_mdm_crc.h>
|
||
|
|
#include <los_hwi.h>
|
||
|
|
#include <los_exc.h>
|
||
|
|
#include <los_hwi.h>
|
||
|
|
#include <soc_asm_func.h>
|
||
|
|
|
||
|
|
#define BLOCK_SIZE PRODUCT_CFG_FLASH_BLOCK_SIZE
|
||
|
|
#define STACK_INFO_ADDR 0x800 /* Stack information is stored relative to the relative address of the dead memory */
|
||
|
|
#define STACK_INFO_SIZE (BLOCK_SIZE - STACK_INFO_ADDR)
|
||
|
|
#define PEND_SV_ERR 14
|
||
|
|
|
||
|
|
typedef struct {
|
||
|
|
td_u32 type;
|
||
|
|
td_u32 addr;
|
||
|
|
td_u32 end_addr;
|
||
|
|
} ext_stack_info_head;
|
||
|
|
|
||
|
|
typedef struct {
|
||
|
|
unsigned msp;
|
||
|
|
unsigned psp;
|
||
|
|
unsigned exc_return_lr;
|
||
|
|
unsigned fault_type;
|
||
|
|
unsigned pri_mask;
|
||
|
|
unsigned r0;
|
||
|
|
unsigned r1;
|
||
|
|
unsigned r2;
|
||
|
|
unsigned r3;
|
||
|
|
unsigned r12;
|
||
|
|
unsigned lr;
|
||
|
|
unsigned pc;
|
||
|
|
unsigned xpsr;
|
||
|
|
unsigned r4;
|
||
|
|
unsigned r5;
|
||
|
|
unsigned r6;
|
||
|
|
unsigned r7;
|
||
|
|
unsigned r8;
|
||
|
|
unsigned r9;
|
||
|
|
unsigned r10;
|
||
|
|
unsigned r11;
|
||
|
|
unsigned sp;
|
||
|
|
} osa_crash_reg_info;
|
||
|
|
|
||
|
|
static td_bool g_power_down = TD_FALSE;
|
||
|
|
static ext_syserr_exc_callback g_syserr_exc_user_hook;
|
||
|
|
#define EXT_WRITE_CRASH_INFO_PER_SIZE 512
|
||
|
|
|
||
|
|
EXT_VOLATILE ext_syserr_info g_sys_err_val;
|
||
|
|
#define sys_err_ptr() ((ext_syserr_info *)(&g_sys_err_val))
|
||
|
|
|
||
|
|
static ext_task_info_s g_task_info;
|
||
|
|
|
||
|
|
__isr td_u32 flash_read_crash(EXT_IN td_u32 addr, EXT_IN td_void *data, EXT_IN td_u32 size)
|
||
|
|
{
|
||
|
|
return uapi_flash_read(addr, size, data);
|
||
|
|
}
|
||
|
|
|
||
|
|
__isr td_u32 flash_write_crash(EXT_IN td_u32 addr, EXT_IN EXT_CONST td_void *data, EXT_IN td_u32 size)
|
||
|
|
{
|
||
|
|
return uapi_flash_write(addr, size, data, TD_FALSE);
|
||
|
|
}
|
||
|
|
|
||
|
|
__isr td_u32 flash_erase_crash(EXT_IN td_u32 addr, EXT_IN td_u32 size)
|
||
|
|
{
|
||
|
|
return uapi_flash_erase(addr, size);
|
||
|
|
}
|
||
|
|
|
||
|
|
__isr td_char *get_eid_str(ext_syserr_id eid)
|
||
|
|
{
|
||
|
|
if (eid == EXT_EID_FAULT_IN_ISR) {
|
||
|
|
return EXT_EXC_IN_ISR_STR;
|
||
|
|
} else if (eid == EXT_EID_FAULT_IN_TASK) {
|
||
|
|
return EXT_EXC_IN_TASK_STR;
|
||
|
|
} else if (eid == EXT_EID_SYS_REBOOT) {
|
||
|
|
return EXT_EXC_SYS_REBOOT_STR;
|
||
|
|
} else {
|
||
|
|
return EXT_EXC_RESERVE_STR;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
#ifdef PRODUCT_CFG_SUPPORT_FLASH_PROTECT
|
||
|
|
__isr td_void set_protect_info(td_void)
|
||
|
|
{
|
||
|
|
ext_flash_protect_ctrl *info;
|
||
|
|
|
||
|
|
info = uapi_flash_protect_get_ctrl_info();
|
||
|
|
|
||
|
|
sys_err_ptr()->protect_info.enable = info->enable;
|
||
|
|
sys_err_ptr()->protect_info.current_block = info->current_block;
|
||
|
|
sys_err_ptr()->protect_info.status_reg = info->flash_status_reg;
|
||
|
|
}
|
||
|
|
#endif
|
||
|
|
|
||
|
|
__isr td_void set_basic_info(ext_syserr_id eid)
|
||
|
|
{
|
||
|
|
/* Unnecessary to check eid, internal control */
|
||
|
|
sys_err_ptr()->basic_info.eid = eid;
|
||
|
|
(td_void)strncpy_s(sys_err_ptr()->basic_info.type_name, EXT_EXC_TYPE_NAME_SIZE, get_eid_str(eid),
|
||
|
|
EXT_EXC_TYPE_NAME_SIZE - 1);
|
||
|
|
sys_err_ptr()->basic_info.type_name[EXT_EXC_TYPE_NAME_SIZE - 1] = 0;
|
||
|
|
|
||
|
|
sys_err_ptr()->basic_info.crash_tsec = (td_u32)(uapi_get_tick64() / LOSCFG_BASE_CORE_TICK_PER_SECOND);
|
||
|
|
sys_err_ptr()->basic_info.boot_ver = uapi_get_boot_ver();
|
||
|
|
|
||
|
|
EXT_CONST ext_product_info *pst = uapi_get_product_info();
|
||
|
|
if (sprintf_s(sys_err_ptr()->basic_info.kernel_ver, sizeof(sys_err_ptr()->basic_info.kernel_ver), "%s,%s,%s",
|
||
|
|
pst->product_version, pst->build_date, pst->build_time) < 0) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
__isr EXT_PRV td_void set_os_usage_info(td_void)
|
||
|
|
{
|
||
|
|
EXT_CONST ext_mem_pool_crash_info_s *mem_info = TD_NULL;
|
||
|
|
(td_void)uapi_os_get_resource_status(&(sys_err_ptr()->os_info.usage));
|
||
|
|
|
||
|
|
mem_info = uapi_mem_get_sys_info_crash();
|
||
|
|
if (mem_info != TD_NULL) {
|
||
|
|
memcpy_s(&(sys_err_ptr()->os_info.mem), sizeof(sys_err_ptr()->os_info.mem), mem_info,
|
||
|
|
sizeof(ext_mem_pool_crash_info_s));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
__isr EXT_PRV td_void set_remap_reg_info(td_void)
|
||
|
|
{
|
||
|
|
for (td_u32 loop = 0; loop < 4; loop++) { /* 4 array */
|
||
|
|
/* Offset 2 bytes */
|
||
|
|
sys_err_ptr()->remap_info.reg_blockmap[loop] = reg_read_val(EXT_MMU_REG_BASE + (loop << 2));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
__isr td_void syserr_save_task_info(td_u32 task_id)
|
||
|
|
{
|
||
|
|
ext_task_info_s *task_info = &g_task_info;
|
||
|
|
|
||
|
|
sys_err_ptr()->os_info.task.id = task_id;
|
||
|
|
if (uapi_task_get_info(task_id, task_info) == EXT_ERR_SUCCESS) {
|
||
|
|
if (memcpy_s(sys_err_ptr()->os_info.task.name, EXT_EXC_TASK_NAME_SIZE, task_info->name,
|
||
|
|
uapi_min(EXT_EXC_TASK_NAME_SIZE, sizeof(task_info->name))) != EOK) { }
|
||
|
|
sys_err_ptr()->os_info.task.stack_size = (td_u16)task_info->stack_size;
|
||
|
|
sys_err_ptr()->os_info.task.status = task_info->status;
|
||
|
|
sys_err_ptr()->os_info.task.sp = task_info->sp;
|
||
|
|
sys_err_ptr()->os_info.task.stack[0] = task_info->top_of_stack;
|
||
|
|
sys_err_ptr()->os_info.task.stack[1] = task_info->bottom_of_stack;
|
||
|
|
sys_err_ptr()->os_info.task.stack_peak = (td_u16)task_info->peak_used;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
__isr EXT_PRV td_void syserr_save_cur_task_info(td_void)
|
||
|
|
{
|
||
|
|
td_u32 id;
|
||
|
|
id = uapi_task_get_current_id();
|
||
|
|
if (id != EXT_INVALID_TASK_ID) {
|
||
|
|
syserr_save_task_info(id);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
__isr EXT_PRV td_void set_isr_info(td_void)
|
||
|
|
{
|
||
|
|
sys_err_ptr()->os_info.task.id = g_cur_interrupt_idx;
|
||
|
|
sys_err_ptr()->os_info.task.sp = 0xAABBCCDD; /* Easy to check if sp is valid */
|
||
|
|
sys_err_ptr()->os_info.task.stack_size =
|
||
|
|
(td_u16)((td_u32)(uintptr_t)(&__SYSTEM_STACK_END__) - (td_u32)(uintptr_t)(&__SYSTEM_STACK_BEGIN__));
|
||
|
|
sys_err_ptr()->os_info.task.stack[0] = (td_u32)(uintptr_t)&__SYSTEM_STACK_BEGIN__;
|
||
|
|
sys_err_ptr()->os_info.task.stack[1] = (td_u32)(uintptr_t)&__SYSTEM_STACK_END__;
|
||
|
|
}
|
||
|
|
|
||
|
|
__isr td_void syserr_save_short_stack(td_u32 real_esp)
|
||
|
|
{
|
||
|
|
td_u32 *ptr = TD_NULL;
|
||
|
|
td_s32 i;
|
||
|
|
td_u32 pre_sp = (td_u32)(real_esp - (EXT_SYS_ESP_PRE_DATA_MAX_NUM * sizeof(td_u32)));
|
||
|
|
|
||
|
|
sys_err_ptr()->os_info.task.stack_data_index = EXT_SYS_ESP_PRE_DATA_MAX_NUM;
|
||
|
|
|
||
|
|
sys_err_ptr()->os_info.task.real_sp = real_esp;
|
||
|
|
|
||
|
|
ptr = (td_u32 *)(uintptr_t)pre_sp;
|
||
|
|
|
||
|
|
for (i = 0; i < EXT_SYS_ESP_PRE_DATA_MAX_NUM; i++) {
|
||
|
|
ptr++;
|
||
|
|
if ((uintptr_t)ptr >= EXT_PERMANENT_MEM_START_ADDR &&
|
||
|
|
(uintptr_t)ptr <= (EXT_PERMANENT_MEM_END_ADDR - sizeof(td_u32))) {
|
||
|
|
sys_err_ptr()->os_info.task.stack_pre_data[i] = *ptr;
|
||
|
|
} else {
|
||
|
|
sys_err_ptr()->os_info.task.stack_pre_data[i] = 0x11223344; /* Easy to check if value is valid */
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
ptr = (td_u32 *)(uintptr_t)real_esp;
|
||
|
|
for (i = 0; i < EXT_SYS_ESP_DATA_MAX_NUM; i++) {
|
||
|
|
ptr++;
|
||
|
|
if ((uintptr_t)ptr >= EXT_PERMANENT_MEM_START_ADDR &&
|
||
|
|
(uintptr_t)ptr <= (EXT_PERMANENT_MEM_END_ADDR - sizeof(td_u32))) {
|
||
|
|
sys_err_ptr()->os_info.task.stack_data[i] = *ptr;
|
||
|
|
} else {
|
||
|
|
sys_err_ptr()->os_info.task.stack_data[i] = 0x11223344; /* Easy to check if value is valid */
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
__isr EXT_PRV td_u32 syserr_get_save_stack_info(td_u32 *save_st_addr, td_u32 *save_end_addr, td_u32 *save_type)
|
||
|
|
{
|
||
|
|
syserr_task_info *ptask = (syserr_task_info *)(&(sys_err_ptr()->os_info.task));
|
||
|
|
td_u32 stack_top = ptask->stack[0];
|
||
|
|
td_u32 stack_bottom = ptask->stack[1];
|
||
|
|
|
||
|
|
if (stack_top >= stack_bottom || stack_top < EXT_PERMANENT_MEM_START_ADDR ||
|
||
|
|
stack_bottom > (EXT_PERMANENT_MEM_END_ADDR - sizeof(td_u32))) {
|
||
|
|
/* The bottom of the stack or the top of the stack is illegal */
|
||
|
|
if (sys_err_ptr()->os_info.task.real_sp >= EXT_PERMANENT_MEM_START_ADDR &&
|
||
|
|
sys_err_ptr()->os_info.task.real_sp <= (EXT_PERMANENT_MEM_END_ADDR - sizeof(td_u32))) {
|
||
|
|
/* SP running at legal address range, stores the stack bases on SP */
|
||
|
|
*save_type = 1; /* Type 1: Store the stack info from real_sp to stack bottom */
|
||
|
|
*save_st_addr = sys_err_ptr()->os_info.task.real_sp;
|
||
|
|
*save_end_addr = uapi_min(sys_err_ptr()->os_info.task.real_sp + STACK_INFO_SIZE,
|
||
|
|
(td_u32)(EXT_PERMANENT_MEM_END_ADDR - sizeof(td_u32)));
|
||
|
|
} else {
|
||
|
|
*save_type = 2; /* Type 2: Store nothing, cause stack information and sp are illegal */
|
||
|
|
*save_st_addr = 0;
|
||
|
|
*save_end_addr = 0;
|
||
|
|
return EXT_ERR_FAILURE;
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
/* Stack bottom and stack top are legal */
|
||
|
|
if (stack_bottom - stack_top <= STACK_INFO_SIZE) {
|
||
|
|
/* Enough space in flash to store the whole stack */
|
||
|
|
*save_type = 3; /* Type 3: Store the whole stack, cause flash space is enough */
|
||
|
|
*save_st_addr = stack_top;
|
||
|
|
*save_end_addr = stack_bottom;
|
||
|
|
} else {
|
||
|
|
/* flash space is not enough */
|
||
|
|
if (sys_err_ptr()->os_info.task.real_sp >= stack_top &&
|
||
|
|
sys_err_ptr()->os_info.task.real_sp <= stack_bottom) { /* flash space */
|
||
|
|
*save_type = 4; /* Type 4: Store a part of stack info, */
|
||
|
|
/* cause there isn't enough space left to store the whole stack. */
|
||
|
|
*save_end_addr = uapi_min(sys_err_ptr()->os_info.task.real_sp + STACK_INFO_SIZE, stack_bottom);
|
||
|
|
*save_st_addr = *save_end_addr - STACK_INFO_SIZE;
|
||
|
|
} else { /* SP is illegal, starting from the stack top */
|
||
|
|
*save_type = 5; /* Type 5: Store the stack from the stack top, cause sp running at illegal address. */
|
||
|
|
*save_st_addr = stack_top;
|
||
|
|
*save_end_addr = stack_top + STACK_INFO_SIZE;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if ((*save_st_addr <= EXT_PERMANENT_MEM_START_ADDR) ||
|
||
|
|
(*save_end_addr >= EXT_PERMANENT_MEM_END_ADDR - sizeof(td_u32)) || (*save_st_addr >= *save_end_addr) ||
|
||
|
|
(*save_end_addr - *save_st_addr > STACK_INFO_SIZE)) {
|
||
|
|
*save_type = 6; /* Type 6: Don't store stack info, cause stack bottom and stack top are at illegal addresses. */
|
||
|
|
return EXT_ERR_FAILURE;
|
||
|
|
}
|
||
|
|
|
||
|
|
return EXT_ERR_SUCCESS;
|
||
|
|
}
|
||
|
|
|
||
|
|
__isr EXT_PRV td_void syserr_save_stack_info(ext_syserr_id eid, td_u16 rid)
|
||
|
|
{
|
||
|
|
unsigned int fault_from = (rid & 0xFF);
|
||
|
|
unsigned int fault_reason = ((rid & 0xFF00) >> 8); /* Get high 8 bits */
|
||
|
|
syserr_reg_info *reg_info = &(sys_err_ptr()->reg_info);
|
||
|
|
|
||
|
|
if (fault_from == OS_EXC_CAUSE_FROM_SVC || fault_reason == OS_EXC_CAUSE_SVC) {
|
||
|
|
if (reg_info->r[0] == 0x02000218 || reg_info->r[0] == 0x02000223) { /* Task stack check error */
|
||
|
|
/* r[1] passes uwTaskID which from LOS_TASK_CB, find LOS_TASK_CB top pStackPointer, offset 16 */
|
||
|
|
LOS_TASK_CB *task_tcb = (LOS_TASK_CB *)((uintptr_t)reg_info->r[1] - 16); /* 16 offset from sp to taskid */
|
||
|
|
/* Store stack info while Stack across the boundary */
|
||
|
|
syserr_save_short_stack(task_tcb->uwTopOfStack);
|
||
|
|
syserr_save_task_info(task_tcb->uwTaskID);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (eid == EXT_EID_FAULT_IN_ISR) {
|
||
|
|
syserr_save_short_stack(reg_info->sp);
|
||
|
|
set_isr_info(); /* Store system stack information */
|
||
|
|
return;
|
||
|
|
} else {
|
||
|
|
syserr_save_short_stack(reg_info->sp);
|
||
|
|
syserr_save_cur_task_info(); /* Store current task info */
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
__isr td_void uapi_syserr_save_cmn_info_step1(ext_syserr_id eid, td_u16 rid)
|
||
|
|
{
|
||
|
|
sys_err_ptr()->sig_s = EXT_SYS_ERR_SIGNATURE;
|
||
|
|
sys_err_ptr()->sig_e = EXT_SYS_ERR_SIGNATURE;
|
||
|
|
sys_err_ptr()->power_magic = EXT_ALL_F_32;
|
||
|
|
|
||
|
|
sys_err_ptr()->basic_info.rid = rid;
|
||
|
|
sys_err_ptr()->basic_info.eid = eid;
|
||
|
|
sys_err_ptr()->basic_info.crash_tsec = (td_u32)(uapi_get_tick64() / LOSCFG_BASE_CORE_TICK_PER_SECOND);
|
||
|
|
sys_err_ptr()->basic_info.boot_ver = uapi_get_boot_ver();
|
||
|
|
|
||
|
|
/* Converts eid to a crash notice string */
|
||
|
|
strncpy_s(sys_err_ptr()->basic_info.type_name,
|
||
|
|
EXT_EXC_TYPE_NAME_SIZE, get_eid_str(eid),
|
||
|
|
EXT_EXC_TYPE_NAME_SIZE - 1);
|
||
|
|
sys_err_ptr()->basic_info.type_name[EXT_EXC_TYPE_NAME_SIZE - 1] = 0;
|
||
|
|
|
||
|
|
/* Store the kernel version */
|
||
|
|
EXT_CONST ext_product_info *pst = uapi_get_product_info();
|
||
|
|
if (sprintf_s(sys_err_ptr()->basic_info.kernel_ver, sizeof(sys_err_ptr()->basic_info.kernel_ver), "%s,%s,%s",
|
||
|
|
pst->product_version, pst->build_date, pst->build_time) < 0) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
__isr td_void uapi_syserr_save_cmn_info_step2(ext_syserr_id eid, td_u16 rid)
|
||
|
|
{
|
||
|
|
ext_flash_partition_table *table = uapi_get_partition_table();
|
||
|
|
ext_unref_param(eid);
|
||
|
|
ext_unref_param(rid);
|
||
|
|
|
||
|
|
td_u8 *data = (td_u8 *)sys_err_ptr() + ext_field_offset(ext_syserr_info, basic_info);
|
||
|
|
td_u16 len = sizeof(ext_syserr_info) - ext_field_offset(ext_syserr_info, basic_info);
|
||
|
|
sys_err_ptr()->crc_val = uapi_crc16(0, data, len);
|
||
|
|
flash_erase_crash(table->table[EXT_FLASH_PARTITON_CRASH_INFO].addr_blk * BLOCK_SIZE,
|
||
|
|
table->table[EXT_FLASH_PARTITON_CRASH_INFO].size_blk * BLOCK_SIZE);
|
||
|
|
|
||
|
|
flash_write_crash(table->table[EXT_FLASH_PARTITON_CRASH_INFO].addr_blk * BLOCK_SIZE, (td_pvoid)sys_err_ptr(),
|
||
|
|
sizeof(ext_syserr_info));
|
||
|
|
}
|
||
|
|
|
||
|
|
__isr td_void uapi_syserr_save_fault_info_step1(ext_syserr_id eid, td_u16 rid)
|
||
|
|
{
|
||
|
|
set_os_usage_info(); /* Storage system resource usage */
|
||
|
|
|
||
|
|
#ifdef PRODUCT_CFG_SUPPORT_FLASH_PROTECT
|
||
|
|
set_protect_info(); /* Store flash protection information */
|
||
|
|
#endif
|
||
|
|
|
||
|
|
uapi_get_track_info(&(sys_err_ptr()->track_info));
|
||
|
|
|
||
|
|
set_remap_reg_info(); /* Store remap information */
|
||
|
|
|
||
|
|
syserr_save_stack_info(eid, rid);
|
||
|
|
}
|
||
|
|
|
||
|
|
__isr EXT_PRV td_void syserr_save_total_stack(td_u32 flash_st_addr, td_u32 ram_st_addr, td_u32 write_size)
|
||
|
|
{
|
||
|
|
td_u32 copyed_size = 0;
|
||
|
|
td_u32 this_size;
|
||
|
|
|
||
|
|
/*
|
||
|
|
* Note: The exception stack cannot be stored directly through the flash API,
|
||
|
|
* because the contents of the exception stack will change at the same time when the exception stack is stored.
|
||
|
|
* This causes fail to do the FLASH readback comparison, and return as an exception.
|
||
|
|
* Eventually, only part of the stack content can be stored.
|
||
|
|
*/
|
||
|
|
while (copyed_size < write_size) {
|
||
|
|
this_size = uapi_min(write_size - copyed_size, EXT_WRITE_CRASH_INFO_PER_SIZE);
|
||
|
|
if (memcpy_s((td_pvoid)sys_err_ptr(), sizeof(ext_syserr_info), (td_pvoid)((uintptr_t)ram_st_addr + copyed_size),
|
||
|
|
this_size) != EOK) {
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
(td_void)flash_write_crash(flash_st_addr + copyed_size, (td_pvoid)sys_err_ptr(), this_size);
|
||
|
|
copyed_size += this_size;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
__isr td_void uapi_syserr_save_fault_info_step2(td_void)
|
||
|
|
{
|
||
|
|
td_u32 ret;
|
||
|
|
ext_stack_info_head stack_info = {
|
||
|
|
0,
|
||
|
|
};
|
||
|
|
ext_flash_partition_table *table = uapi_get_partition_table();
|
||
|
|
|
||
|
|
ret = syserr_get_save_stack_info(&stack_info.addr, &stack_info.end_addr, &stack_info.type);
|
||
|
|
if (ret == EXT_ERR_SUCCESS) {
|
||
|
|
flash_write_crash((td_u32)(table->table[EXT_FLASH_PARTITON_CRASH_INFO].addr_blk * BLOCK_SIZE + STACK_INFO_ADDR -
|
||
|
|
sizeof(stack_info)),
|
||
|
|
(td_pvoid)&stack_info, sizeof(stack_info));
|
||
|
|
|
||
|
|
syserr_save_total_stack(table->table[EXT_FLASH_PARTITON_CRASH_INFO].addr_blk * BLOCK_SIZE + STACK_INFO_ADDR,
|
||
|
|
stack_info.addr, stack_info.end_addr - stack_info.addr);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
__isr td_u32 uapi_syserr_get(ext_syserr_info *info)
|
||
|
|
{
|
||
|
|
td_u32 ret;
|
||
|
|
td_u16 crc_val;
|
||
|
|
ext_flash_partition_table *table = uapi_get_partition_table();
|
||
|
|
|
||
|
|
td_u8 *data = TD_NULL;
|
||
|
|
td_u16 len;
|
||
|
|
|
||
|
|
if (info == TD_NULL) {
|
||
|
|
return EXT_ERR_INVALID_PARAMETER;
|
||
|
|
}
|
||
|
|
|
||
|
|
ret = uapi_flash_read(table->table[EXT_FLASH_PARTITON_CRASH_INFO].addr_blk * BLOCK_SIZE, sizeof(ext_syserr_info),
|
||
|
|
(td_u8 *)info);
|
||
|
|
info->power_down = g_power_down;
|
||
|
|
if (ret != EXT_ERR_SUCCESS) {
|
||
|
|
info->crc_usable = TD_FALSE;
|
||
|
|
info->basic_info.now_tsec = uapi_get_seconds();
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
if ((info->sig_s != EXT_SYS_ERR_SIGNATURE) || (info->sig_e != EXT_SYS_ERR_SIGNATURE)) {
|
||
|
|
info->crc_usable = TD_FALSE;
|
||
|
|
info->basic_info.now_tsec = uapi_get_seconds();
|
||
|
|
return EXT_ERR_NOT_FOUND;
|
||
|
|
}
|
||
|
|
data = (td_u8 *)sys_err_ptr() + ext_field_offset(ext_syserr_info, basic_info);
|
||
|
|
len = sizeof(ext_syserr_info) - ext_field_offset(ext_syserr_info, basic_info);
|
||
|
|
crc_val = uapi_crc16(0, data, len);
|
||
|
|
if (crc_val == info->crc_val) {
|
||
|
|
info->crc_usable = TD_TRUE;
|
||
|
|
}
|
||
|
|
info->basic_info.now_tsec = uapi_get_seconds();
|
||
|
|
|
||
|
|
return EXT_ERR_SUCCESS;
|
||
|
|
}
|
||
|
|
|
||
|
|
__isr EXT_PRV td_void temp_watchdog_func(td_u32 data)
|
||
|
|
{
|
||
|
|
ext_unref_param(data);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
__isr td_u32 uapi_syserr_wdg_init(td_bool enable, td_u32 time, td_bool record_crash_info)
|
||
|
|
{
|
||
|
|
td_u32 ret = EXT_ERR_SUCCESS;
|
||
|
|
ext_wdg_mode_e mode = (record_crash_info == TD_TRUE) ? EXT_WDG_INTER : EXT_WDG_ERR;
|
||
|
|
|
||
|
|
if (enable) {
|
||
|
|
ret = uapi_watchdog_register(mode, temp_watchdog_func, time);
|
||
|
|
if (ret == EXT_ERR_SUCCESS) {
|
||
|
|
sys_err_ptr()->wdg_info.enable = TD_TRUE;
|
||
|
|
sys_err_ptr()->wdg_info.time_ms = 0x7FFFFFFF & time;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (mode == EXT_WDG_INTER) {
|
||
|
|
m_pstHwiForm[WatchDog_IRQn + OS_SYS_VECTOR_CNT] = (HWI_PROC_FUNC)osExcWatchDog;
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
uapi_watchdog_disable();
|
||
|
|
sys_err_ptr()->wdg_info.enable = TD_FALSE;
|
||
|
|
}
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
td_void hardware_init(td_void)
|
||
|
|
{
|
||
|
|
td_u32 reg_val;
|
||
|
|
reg_val = reg_read_val(DW21_SYSCTRL_SC_HW_ID_REG);
|
||
|
|
sys_err_ptr()->hw_info.hw_id = reg_val & ((1 << SYSCTRL_HW_ID_LEN) - 1);
|
||
|
|
sys_err_ptr()->hw_info.jtag_mode = (reg_val & (1 << SYSCTRL_JTAG_EN_OFFSET)) ? 1 : 0;
|
||
|
|
reg_val = reg_read_val(DW21_SYSCTRL_SC_VERSION_ID_REG);
|
||
|
|
sys_err_ptr()->hw_info.chip_ = (reg_val & (1 << SYSCTRL_TYPE_ID_OFFSET)) ? 1 : 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
td_void uapi_syserr_init(td_void)
|
||
|
|
{
|
||
|
|
td_u32 temp_size = 0;
|
||
|
|
ext_flash_partition_table *table = uapi_get_partition_table();
|
||
|
|
if (!uint_2_multiply(table->table[EXT_FLASH_PARTITON_CRASH_INFO].addr_blk, BLOCK_SIZE, &temp_size)) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
td_u32 addr = temp_size + ext_field_offset(ext_syserr_info, power_magic);
|
||
|
|
td_u32 power_magic = 0;
|
||
|
|
|
||
|
|
sys_err_ptr()->basic_info.log_ver = EXT_SYSERR_VERSION;
|
||
|
|
sys_err_ptr()->info_len = sizeof(ext_syserr_info);
|
||
|
|
hardware_init();
|
||
|
|
flash_read_crash(addr, &power_magic, sizeof(power_magic));
|
||
|
|
/* This is specially designed to write only when EXT_NO_POWER_DOWN, to avoid
|
||
|
|
individual bit errors causing write repeatedly at power-on */
|
||
|
|
if (power_magic == EXT_NO_POWER_DOWN) {
|
||
|
|
power_magic = EXT_POWER_DOWN;
|
||
|
|
flash_write_crash(addr, &power_magic, sizeof(power_magic));
|
||
|
|
} else {
|
||
|
|
g_power_down = TD_TRUE;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
__isr ext_syserr_info *uapi_syserr_ptr(td_void)
|
||
|
|
{
|
||
|
|
return (sys_err_ptr());
|
||
|
|
}
|
||
|
|
|
||
|
|
td_void uapi_syserr_exc_register(ext_syserr_exc_callback func)
|
||
|
|
{
|
||
|
|
g_syserr_exc_user_hook = func;
|
||
|
|
}
|
||
|
|
|
||
|
|
typedef struct {
|
||
|
|
td_u8 times;
|
||
|
|
} ext_crash_ctrl;
|
||
|
|
|
||
|
|
ext_crash_ctrl g_crash_ctrl = { 0 };
|
||
|
|
|
||
|
|
__isr EXT_PRV td_void sys_err_make_core_info(td_void)
|
||
|
|
{
|
||
|
|
sys_err_ptr()->core_info.cur_task_id = (td_u16)uapi_get_cur_task_id();
|
||
|
|
sys_err_ptr()->core_info.new_task_id = (td_u16)uapi_get_new_task_id();
|
||
|
|
UAPI_REG_READ32(0xE000ED04, sys_err_ptr()->core_info.reg_icsr); /* Interrupt Control and Status Register ICSR */
|
||
|
|
UAPI_REG_READ32(0xE000ED28, sys_err_ptr()->core_info.reg_fsr);
|
||
|
|
UAPI_REG_READ32(0xE000ED2C, sys_err_ptr()->core_info.reg_hfsr);
|
||
|
|
UAPI_REG_READ32(0xE000ED38, sys_err_ptr()->core_info.reg_bfar); /* bus fault address register */
|
||
|
|
/* System Handler control and status register (some abnormal activity in the suspension) */
|
||
|
|
UAPI_REG_READ32(0xE000ED24, sys_err_ptr()->core_info.reg_shcsr);
|
||
|
|
UAPI_REG_READ32(0xE000E200, sys_err_ptr()->core_info.reg_isr_pend); /* Interrupt enable */
|
||
|
|
UAPI_REG_READ32(0xE000E300, sys_err_ptr()->core_info.reg_isr_active); /* Interrupt enable */
|
||
|
|
}
|
||
|
|
|
||
|
|
__isr EXT_PRV td_void sys_err_make_reg_info(EXT_CONST osa_crash_reg_info *m3_info)
|
||
|
|
{
|
||
|
|
if (m3_info == TD_NULL) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
do {
|
||
|
|
sys_err_ptr()->reg_info.pc = m3_info->pc;
|
||
|
|
sys_err_ptr()->reg_info.sp = m3_info->sp;
|
||
|
|
sys_err_ptr()->reg_info.msp = m3_info->msp;
|
||
|
|
sys_err_ptr()->reg_info.psp = m3_info->psp;
|
||
|
|
sys_err_ptr()->reg_info.exc_return_lr = m3_info->exc_return_lr;
|
||
|
|
sys_err_ptr()->reg_info.xpsr = m3_info->xpsr;
|
||
|
|
sys_err_ptr()->reg_info.pri_mask = m3_info->pri_mask;
|
||
|
|
sys_err_ptr()->reg_info.r[0] = m3_info->r0; /* 0th working register */
|
||
|
|
sys_err_ptr()->reg_info.r[1] = m3_info->r1; /* 1st working register */
|
||
|
|
sys_err_ptr()->reg_info.r[2] = m3_info->r2; /* 2nd working register */
|
||
|
|
sys_err_ptr()->reg_info.r[3] = m3_info->r3; /* 3rd working register */
|
||
|
|
sys_err_ptr()->reg_info.r[4] = m3_info->r4; /* 4th working register */
|
||
|
|
sys_err_ptr()->reg_info.r[5] = m3_info->r5; /* 5th working register */
|
||
|
|
sys_err_ptr()->reg_info.r[6] = m3_info->r6; /* 6th working register */
|
||
|
|
sys_err_ptr()->reg_info.r[7] = m3_info->r7; /* 7th working register */
|
||
|
|
sys_err_ptr()->reg_info.r[8] = m3_info->r8; /* 8th working register */
|
||
|
|
sys_err_ptr()->reg_info.r[9] = m3_info->r9; /* 9th working register */
|
||
|
|
sys_err_ptr()->reg_info.r[10] = m3_info->r10; /* 10th working register */
|
||
|
|
sys_err_ptr()->reg_info.r[11] = m3_info->r11; /* 11th working register */
|
||
|
|
sys_err_ptr()->reg_info.r[12] = m3_info->r12; /* 12th working register */
|
||
|
|
sys_err_ptr()->reg_info.r[13] = m3_info->sp; /* 13th working register */
|
||
|
|
sys_err_ptr()->reg_info.r[14] = m3_info->lr; /* 14th working register */
|
||
|
|
} while (0);
|
||
|
|
}
|
||
|
|
|
||
|
|
__isr EXT_PRV td_void sys_err_conver_eid_rid(td_u32 crash_from, ext_syserr_id *eid, td_u16 *rid)
|
||
|
|
{
|
||
|
|
td_u8 fault_from;
|
||
|
|
td_u8 fault_reason;
|
||
|
|
syserr_core_info *core_info = &(sys_err_ptr()->core_info);
|
||
|
|
syserr_reg_info *reg_info = &(sys_err_ptr()->reg_info);
|
||
|
|
|
||
|
|
if (reg_info->psp == reg_info->sp) {
|
||
|
|
*eid = EXT_EID_FAULT_IN_TASK;
|
||
|
|
} else {
|
||
|
|
*eid = EXT_EID_FAULT_IN_ISR;
|
||
|
|
}
|
||
|
|
reg_info->sp += 32; /* When crashing, m3 pushes in 8 registers for a total of 32 bytes. */
|
||
|
|
|
||
|
|
if (crash_from == OS_EXC_CAUSE_FROM_SVC) {
|
||
|
|
fault_from = OS_EXC_CAUSE_FROM_SVC;
|
||
|
|
fault_reason = 0xFF;
|
||
|
|
if (reg_info->r[0] == 0x02000218 || reg_info->r[0] == 0x02000223) {
|
||
|
|
*eid = EXT_EID_FAULT_IN_TASK;
|
||
|
|
}
|
||
|
|
} else if (crash_from == OS_EXC_CAUSE_FROM_WATCH_DOG) {
|
||
|
|
fault_from = OS_EXC_CAUSE_FROM_WATCH_DOG;
|
||
|
|
fault_reason = OS_EXC_CAUSE_FROM_WATCH_DOG;
|
||
|
|
} else {
|
||
|
|
/* OS_EXC_CAUSE_HARDFAULT,OS_EXC_CAUSE_NMI,OS_EXC_CAUSE_BUSFAULT */
|
||
|
|
fault_from = (td_u8)crash_from;
|
||
|
|
if (core_info->reg_hfsr & 0x80000000) {
|
||
|
|
fault_reason = OS_EXC_CAUSE_DEBUGEVT;
|
||
|
|
} else if (core_info->reg_hfsr & 0x00000002) {
|
||
|
|
fault_reason = OS_EXC_CAUSE_VECTBL;
|
||
|
|
} else {
|
||
|
|
td_u32 reg_val = ((core_info->reg_fsr) & (~((1 << 15) | (1 << 7)))); /* Clear low 15th and lower 7th */
|
||
|
|
td_u32 x = uapi_clz(reg_val);
|
||
|
|
if (x == 32) { /* When crashing, m3 pushes in 8 registers for a total of 32 bytes. */
|
||
|
|
fault_reason = OS_EXC_CAUSE_SVC; /* illegal branch */
|
||
|
|
} else {
|
||
|
|
fault_reason = g_uwExcTbl[x];
|
||
|
|
}
|
||
|
|
if (x == 32 && /* When crashing, m3 pushes in 8 registers for a total of 32 bytes */
|
||
|
|
(reg_info->r[0] == 0x02000218 || reg_info->r[0] == 0x02000223)) {
|
||
|
|
*eid = EXT_EID_FAULT_IN_TASK;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
*rid = (((td_u16)fault_from) | ((td_u16)fault_reason << 8)); /* Take the lower 8 digits */
|
||
|
|
}
|
||
|
|
|
||
|
|
__isr td_void osa_exc_hook(td_u32 crash_from, EXT_CONST osa_crash_reg_info *reg_info)
|
||
|
|
{
|
||
|
|
ext_syserr_id eid = EXT_EID_RESERVE;
|
||
|
|
td_u16 rid = 0;
|
||
|
|
|
||
|
|
if (g_crash_ctrl.times > 0) {
|
||
|
|
while (1) { }
|
||
|
|
}
|
||
|
|
g_crash_ctrl.times++;
|
||
|
|
|
||
|
|
sys_err_make_reg_info(reg_info);
|
||
|
|
sys_err_make_core_info();
|
||
|
|
sys_err_conver_eid_rid(crash_from, &eid, &rid);
|
||
|
|
|
||
|
|
uapi_watchdog_feed();
|
||
|
|
uapi_syserr_save_cmn_info_step1(eid, rid);
|
||
|
|
uapi_syserr_save_fault_info_step1(eid, rid);
|
||
|
|
uapi_syserr_save_cmn_info_step2(eid, rid);
|
||
|
|
uapi_syserr_save_fault_info_step2();
|
||
|
|
|
||
|
|
if (g_syserr_exc_user_hook) {
|
||
|
|
g_syserr_exc_user_hook();
|
||
|
|
}
|
||
|
|
|
||
|
|
uapi_watchdog_register(EXT_WDG_NORMAL, TD_NULL, 500); /* deley 500ms */
|
||
|
|
while (1) { } /* System error, blocking infinite loop PC_LINT alarm */
|
||
|
|
}
|