临终遗言使用方法
功能说明
临终遗言日志存储钩子函数,实现日志存储的读写函数的注册,接口详细信息可以查看API参考。
接口名 |
描述 |
---|---|
LOS_ExcInfoRegHook |
注册读写临终遗言日志的钩子函数,并设置记录临终遗言日志的起始地址、大小和缓冲区。 |
LOS_ExcInfoRegHook有4个参数:
- startAddr:临终遗言日志的存储起始地址。
- space:临终遗言日志的存储空间大小。
- buf:临终遗言日志在内存中的buffer地址,大小space。
- LogReadWriteFunc:读写异常信息的钩子函数。该函数的入参包括startAddr、space、rwFlag和buf。rwFlag是读写标记,0为写,1为读。其余3个入参同LOS_ExcInfoRegHook。
使用方法
- 通过make menuconfig开启临终遗言记录功能,即配置LOSCFG_SHELL_EXCINFO_DUMP=y,该功能默认关闭,菜单路径为:Debug ---> Enable a Debug Version ---> Enable Shell ---> Enable Shell excInfo。
- 注册读写钩子函数。
- 编写读写临终遗言日志的钩子函数,示例代码如下。
#include "los_base.h" #if defined(LOSCFG_SHELL_EXCINFO) && defined(LOSCFG_DRIVERS_MTD_SPI_NOR) #include "linux/mtd/mtd.h" #include "linux/module.h" #include "linux/mtd/mtd_list.h" #include "spinor.h" #endif #include "los_hwi.h" #ifdef LOSCFG_FS_VFS #include "fs/fs.h" #endif #ifdef LOSCFG_SHELL_EXCINFO_DUMP STATIC struct mtd_info *g_mtdSpinor = NULL; STATIC VOID OsSpiflashErase(UINT32 start, size_t size) { struct erase_info eraseInfo; (VOID)memset_s(&eraseInfo, sizeof(struct erase_info), 0, sizeof(struct erase_info)); eraseInfo.mtd = g_mtdSpinor; eraseInfo.callback = NULL; eraseInfo.fail_addr = (UINT64)MTD_FAIL_ADDR_UNKNOWN; eraseInfo.addr = start; eraseInfo.len = size; eraseInfo.time = 1; eraseInfo.retries = 1; eraseInfo.dev = 0; eraseInfo.cell = 0; eraseInfo.priv = 0; eraseInfo.state = 0; eraseInfo.next = NULL; eraseInfo.scrub = 0; (VOID)g_mtdSpinor->erase(g_mtdSpinor, &eraseInfo); } STATIC INT32 OsWriteExcInfoToSpiFlash(UINT32 startAddr, UINT32 space, const CHAR *buf) { UINT32 outLen; OsSpiflashErase(startAddr, LOS_Align(space, g_mtdSpinor->erasesize)); return g_mtdSpinor->write(g_mtdSpinor, (loff_t)startAddr, space, &outLen, buf); } STATIC INT32 OsReadExcInfoForSpiFlash(UINT32 startAddr, UINT32 space, CHAR *buf) { UINT32 outLen; return g_mtdSpinor->read(g_mtdSpinor, (loff_t)startAddr, space, &outLen, buf); } /* Be called in the exception. */ VOID OsReadWriteExceptionInfo(UINT32 startAddr, UINT32 space, UINT32 flag, CHAR *buf) { if ((buf == NULL) || (space == 0)) { PRINT_ERR("buffer is null or space is zero\n"); return; } g_mtdSpinor = get_mtd("spinor"); if (g_mtdSpinor == NULL) { (VOID)spinor_init(); g_mtdSpinor = get_mtd("spinor"); if (g_mtdSpinor == NULL) { PRINT_ERR("Init spinor is failed\n"); return; } } if (flag == 0) { if (OsWriteExcInfoToSpiFlash(startAddr, space, buf) != LOS_OK) { PRINT_ERR("Exception information written to 0x%x flash failed\n", startAddr); } #ifndef LOSCFG_EXC_INTERACTION /* * When system is in the exception interaction, this buf was free, * but this feature is still running. This buffer may be used again * without malloc. * So, consider whether or not the "buf" is released according to actual use. */ free(buf); #endif } elseif (flag == 1) { if (OsReadExcInfoForSpiFlash(startAddr, space, buf) != LOS_OK) { PRINT_ERR("Exception information read from 0x%x flash failed\n", startAddr); } } else { PRINT_ERR("flag is error\n"); } } #endif #endif
- 在初始化函数如app_init中注册钩子函数,示例代码如下。
#ifdef LOSCFG_SHELL_EXCINFO_DUMP #define EXCINFO_RECORD_BUF_SIZE (16 * 1024) /* 用户自己定义 */ #define EXCINFO_RECORD_ADDR (0xffffffff) /* 此处是非法值,需要用户自己定义 */ CHAR *buf = (CHAR *)malloc(EXCINFO_RECORD_BUF_SIZE); if (buf != NULL) { (VOID)memset_s(buf, EXCINFO_RECORD_BUF_SIZE, 0, EXCINFO_RECORD_BUF_SIZE); LOS_ExcInfoRegHook(EXCINFO_RECORD_ADDR, EXCINFO_RECORD_BUF_SIZE, buf, OsReadWriteExceptionInfo); } else { PRINTK("shell excinfo malloc failed!\n"); } #ifdef LOSCFG_FS_VFS los_vfs_init(); #endif #endif
- OsReadWriteExceptionInfo函数是对Nor Flash进行读写的功能函数,宏EXCINFO_RECORD_BUF_SIZE,EXCINFO_RECORD_ADDR需要用户根据实际情况进行配置,建议该段代码放在用户业务代码前。
- Nor Flash写数据之前要进行块擦除,块大小为64k,因此设置的临终遗言存储起始地址之后的64k区域,在写临终遗言信息时会被擦除,建议此区域不保存数据。
- 编写读写临终遗言日志的钩子函数,示例代码如下。
- 查看异常信息。
系统复位重启后,Shell窗口中执行excInfo命令,会打印出已记录的临终遗言日志。
注意事项
保存临终遗言信息的buffer需要用户进行维护,重复调用注册函数时,需要用户自行释放前一次注册时传入的buffer。