/* ---------------------------------------------------------------------------- * Copyright (c) Huawei Technologies Co., Ltd. 2019-2020. All rights reserved. * Description: LiteOS Trace Implementation * Author: Huawei LiteOS Team * Create: 2019-08-31 * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. * 3. Neither the name of the copyright holder nor the names of its contributors may be used * to endorse or promote products derived from this software without specific prior written * permission. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * --------------------------------------------------------------------------- */ #include "uart.h" #include "los_trace_pri.h" #include "trace_pipeline.h" #ifdef LOSCFG_KERNEL_SMP #include "los_mp_pri.h" #endif #ifdef LOSCFG_SHELL #include "shcmd.h" #include "shell.h" #endif #ifdef __cplusplus #if __cplusplus extern "C" { #endif /* __cplusplus */ #endif /* __cplusplus */ #ifdef LOSCFG_KERNEL_TRACE LITE_OS_SEC_BSS STATIC UINT32 g_traceEventCount; //追踪事件计数// LITE_OS_SEC_BSS STATIC volatile enum TraceState g_traceState = TRACE_UNINIT; //追踪状态// LITE_OS_SEC_DATA_INIT STATIC volatile BOOL g_enableTrace = FALSE; //是否启用追踪功能// LITE_OS_SEC_BSS STATIC UINT32 g_traceMask = TRACE_DEFAULT_MASK; //追踪掩码,用于过滤追踪事件// #ifdef LOSCFG_TRACE_CONTROL_AGENT LITE_OS_SEC_BSS STATIC UINT32 g_traceTaskId; //追踪任务的ID// #endif #define EVENT_MASK 0xFFFFFFF0 #define MIN(x, y) ((x) < (y) ? (x) : (y)) LITE_OS_SEC_BSS STATIC TRACE_HWI_FILTER_HOOK g_traceHwiFliterHook = NULL; LITE_OS_SEC_BSS SPIN_LOCK_INIT(g_traceSpin); STATIC_INLINE BOOL OsTraceHwiFilter(UINT32 hwiNum) //用于判断是否需要过滤某个硬件中断// { BOOL ret = ((hwiNum == NUM_HAL_INTERRUPT_UART) || (hwiNum == OS_TICK_INT_NUM)); #ifdef LOSCFG_KERNEL_SMP ret |= (hwiNum == LOS_MP_IPI_SCHEDULE); #endif if (g_traceHwiFliterHook != NULL) { ret |= g_traceHwiFliterHook(hwiNum); } return ret; } //用于设置追踪事件的帧信息// STATIC VOID OsTraceSetFrame(TraceEventFrame *frame, UINT32 eventType, UINTPTR identity, const UINTPTR *params, UINT16 paramCount) { INT32 i; UINT32 intSave; (VOID)memset_s(frame, sizeof(TraceEventFrame), 0, sizeof(TraceEventFrame)); if (paramCount > LOSCFG_TRACE_FRAME_MAX_PARAMS) { paramCount = LOSCFG_TRACE_FRAME_MAX_PARAMS; } TRACE_LOCK(intSave); frame->curTask = OsTraceGetMaskTid(OsCurrTaskGet()->taskId); frame->identity = identity; frame->curTime = HalClockGetCycles(); frame->eventType = eventType; #ifdef LOSCFG_TRACE_FRAME_CORE_MSG frame->core.cpuId = ArchCurrCpuid(); //CPU的ID// frame->core.hwiActive = OS_INT_ACTIVE ? TRUE : FALSE; //硬件中断活动状态// frame->core.taskLockCnt = MIN(OsPercpuGet()->taskLockCnt, 0xF); /* taskLockCnt is 4 bits, max vaule = 0xF */ //任务锁计数// frame->core.paramCount = paramCount; //参数数目// #endif #ifdef LOSCFG_TRACE_FRAME_EVENT_COUNT frame->eventCount = g_traceEventCount; //追踪事件的计数// g_traceEventCount++; #endif TRACE_UNLOCK(intSave); for (i = 0; i < paramCount; i++) { frame->params[i] = params[i]; } } VOID OsTraceSetObj(ObjData *obj, const LosTaskCB *tcb) //设置对象的追踪信息// { errno_t ret; (VOID)memset_s(obj, sizeof(ObjData), 0, sizeof(ObjData)); obj->id = OsTraceGetMaskTid(tcb->taskId); //获取任务ID// obj->prio = tcb->priority; //获取任务优先级// ret = strncpy_s(obj->name, LOSCFG_TRACE_OBJ_MAX_NAME_SIZE, tcb->taskName, LOSCFG_TRACE_OBJ_MAX_NAME_SIZE - 1); if (ret != EOK) { TRACE_ERROR("Task name copy failed!\n"); } } //处理追踪事件钩子// VOID OsTraceHook(UINT32 eventType, UINTPTR identity, const UINTPTR *params, UINT16 paramCount) { if ((eventType == TASK_CREATE) || (eventType == TASK_PRIOSET)) { OsTraceObjAdd(eventType, identity); /* handle important obj info, these can not be filtered */ } if ((g_enableTrace == TRUE) && (eventType & g_traceMask)) { UINTPTR id = identity; if (TRACE_GET_MODE_FLAG(eventType) == TRACE_HWI_FLAG) { if (OsTraceHwiFilter(identity)) { return; } } else if (TRACE_GET_MODE_FLAG(eventType) == TRACE_TASK_FLAG) { id = OsTraceGetMaskTid(identity); } else if (eventType == MEM_INFO_REQ) { LOS_MEM_POOL_STATUS status; LOS_MemInfoGet((VOID *)identity, &status); LOS_TRACE(MEM_INFO, identity, status.uwTotalUsedSize, status.uwTotalFreeSize); return; } TraceEventFrame frame; OsTraceSetFrame(&frame, eventType, id, params, paramCount); OsTraceWriteOrSendEvent(&frame); //将追踪事件信息写入或发送出去// } } BOOL OsTraceIsEnable(VOID) //判断追踪是否处于启用状态// { return g_enableTrace == TRUE; } STATIC VOID OsTraceHookInstall(VOID) //安装追踪钩子// { g_traceEventHook = OsTraceHook; #ifdef LOSCFG_RECORDER_MODE_OFFLINE g_traceDumpHook = OsTraceRecordDump; //在离线记录模式下设置追踪转储钩子// #endif } #ifdef LOSCFG_TRACE_CONTROL_AGENT STATIC BOOL OsTraceCmdIsValid(const TraceClientCmd *msg) //判断传入的TraceClientCmd结构体是否有效// { return ((msg->end == TRACE_CMD_END_CHAR) && (msg->cmd < TRACE_CMD_MAX_CODE)); } STATIC VOID OsTraceCmdHandle(const TraceClientCmd *msg) //处理传入的TraceClientCmd结构体// { if (!OsTraceCmdIsValid(msg)) { return; } switch (msg->cmd) { case TRACE_CMD_START: //启动追踪// LOS_TraceStart(); break; case TRACE_CMD_STOP: //停止追踪// LOS_TraceStop(); break; case TRACE_CMD_SET_EVENT_MASK: //设置事件掩码// /* 4 params(UINT8) composition the mask(UINT32) */ LOS_TraceEventMaskSet(TRACE_MASK_COMBINE(msg->param1, msg->param2, msg->param3, msg->param4)); break; case TRACE_CMD_RECODE_DUMP: //追踪记录转储// LOS_TraceRecordDump(TRUE); break; default: break; } } VOID TraceAgent(VOID) //不断等待追踪数据的到达,并处理接收到的追踪命令// { UINT32 ret; TraceClientCmd msg; while (1) { (VOID)memset_s(&msg, sizeof(TraceClientCmd), 0, sizeof(TraceClientCmd)); ret = OsTraceDataWait(); if (ret == LOS_OK) { OsTraceDataRecv((UINT8 *)&msg, sizeof(TraceClientCmd), 0); OsTraceCmdHandle(&msg); } } } STATIC UINT32 OsCreateTraceAgentTask(VOID) //创建一个追踪代理任务,用于执行追踪逻辑// { UINT32 ret; TSK_INIT_PARAM_S taskInitParam; (VOID)memset_s((VOID *)(&taskInitParam), sizeof(TSK_INIT_PARAM_S), 0, sizeof(TSK_INIT_PARAM_S)); taskInitParam.pfnTaskEntry = (TSK_ENTRY_FUNC)TraceAgent; taskInitParam.usTaskPrio = LOSCFG_TRACE_TASK_PRIORITY; taskInitParam.pcName = "TraceAgent"; taskInitParam.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE; #ifdef LOSCFG_KERNEL_SMP taskInitParam.usCpuAffiMask = CPUID_TO_AFFI_MASK(ArchCurrCpuid()); #endif ret = LOS_TaskCreate(&g_traceTaskId, &taskInitParam); return ret; } #endif UINT32 LOS_TraceInit(VOID *buf, UINT32 size) //初始化追踪功能// { UINT32 intSave; UINT32 ret; TRACE_LOCK(intSave); if (g_traceState != TRACE_UNINIT) { TRACE_ERROR("trace has been initialized already, the current state is :%d\n", g_traceState); ret = LOS_ERRNO_TRACE_ERROR_STATUS; goto LOS_ERREND; } #ifdef LOSCFG_TRACE_CLIENT_INTERACT //判断是否需要初始化追踪管道// ret = OsTracePipelineInit(); if (ret != LOS_OK) { goto LOS_ERREND; } #endif #ifdef LOSCFG_TRACE_CONTROL_AGENT //判断是否需要创建追踪代理任务// ret = OsCreateTraceAgentTask(); if (ret != LOS_OK) { TRACE_ERROR("trace init create agentTask error :0x%x\n", ret); goto LOS_ERREND; } #endif ret = OsTraceBufInit(buf, size); //初始化追踪缓冲区// if (ret != LOS_OK) { goto LOS_RELEASE; } OsTraceHookInstall(); //安装追踪钩子// g_traceEventCount = 0; /*判断是否需要等待追踪客户端启动追踪*/ #ifdef LOSCFG_RECORDER_MODE_ONLINE /* Wait trace client to start trace */ g_enableTrace = FALSE; g_traceState = TRACE_INITED; #else g_enableTrace = TRUE; g_traceState = TRACE_STARTED; #endif TRACE_UNLOCK(intSave); return LOS_OK; LOS_RELEASE: #ifdef LOSCFG_TRACE_CONTROL_AGENT //判断是否需要删除追踪代理任务// LOS_TaskDelete(g_traceTaskId); #endif LOS_ERREND: TRACE_UNLOCK(intSave); return ret; } UINT32 LOS_TraceStart(VOID) //用于启动追踪功能// { UINT32 intSave; UINT32 ret = LOS_OK; TRACE_LOCK(intSave); if (g_traceState == TRACE_STARTED) { goto START_END; } if (g_traceState == TRACE_UNINIT) { TRACE_ERROR("trace not inited, be sure LOS_TraceInit excute success\n"); ret = LOS_ERRNO_TRACE_ERROR_STATUS; goto START_END; } OsTraceNotifyStart(); //通知追踪功能开始工作// g_enableTrace = TRUE; g_traceState = TRACE_STARTED; TRACE_UNLOCK(intSave); LOS_TRACE(MEM_INFO_REQ, m_aucSysMem0); //发送追踪信息// return ret; START_END: TRACE_UNLOCK(intSave); return ret; } VOID LOS_TraceStop(VOID) //用于停止追踪功能// { UINT32 intSave; TRACE_LOCK(intSave); if (g_traceState != TRACE_STARTED) { goto STOP_END; } g_enableTrace = FALSE; g_traceState = TRACE_STOPED; OsTraceNotifyStop(); //通知追踪功能停止工作// STOP_END: TRACE_UNLOCK(intSave); } VOID LOS_TraceEventMaskSet(UINT32 mask) //设置追踪事件掩码// { g_traceMask = mask & EVENT_MASK; } VOID LOS_TraceRecordDump(BOOL toClient) //转储追踪记录// { if (g_traceState != TRACE_STOPED) { TRACE_ERROR("trace dump must after trace stopped , the current state is : %d\n", g_traceState); return; } OsTraceRecordDump(toClient); } OfflineHead *LOS_TraceRecordGet(VOID) //获取追踪记录// { return OsTraceRecordGet(); } VOID LOS_TraceReset(VOID) //重置追踪功能// { if (g_traceState == TRACE_UNINIT) { TRACE_ERROR("trace not inited, be sure LOS_TraceInit excute success\n"); return; } OsTraceReset(); } VOID LOS_TraceHwiFilterHookReg(TRACE_HWI_FILTER_HOOK hook) //注册中断过滤钩子// { UINT32 intSave; TRACE_LOCK(intSave); g_traceHwiFliterHook = hook; TRACE_UNLOCK(intSave); } #ifdef LOSCFG_SHELL LITE_OS_SEC_TEXT_MINOR UINT32 OsShellCmdTraceSetMask(INT32 argc, const CHAR **argv) //设置追踪事件掩码// { size_t mask; CHAR *endPtr = NULL; if (argc >= 2) { /* 2:Just as number of parameters */ PRINTK("\nUsage: trace_mask or trace_mask ID\n"); return OS_ERROR; } if (argc == 0) { mask = TRACE_DEFAULT_MASK; } else { mask = strtoul(argv[0], &endPtr, 0); } LOS_TraceEventMaskSet((UINT32)mask); return LOS_OK; } LITE_OS_SEC_TEXT_MINOR UINT32 OsShellCmdTraceDump(INT32 argc, const CHAR **argv) //进行追踪记录的转储// { BOOL toClient; CHAR *endPtr = NULL; if (argc >= 2) { /* 2:Just as number of parameters */ PRINTK("\nUsage: trace_dump or trace_dump [1/0]\n"); return OS_ERROR; } if (argc == 0) { toClient = FALSE; } else { toClient = strtoul(argv[0], &endPtr, 0) != 0 ? TRUE : FALSE; } LOS_TraceRecordDump(toClient); return LOS_OK; } /*命令行函数的注册*/ SHELLCMD_ENTRY(tracestart_shellcmd, CMD_TYPE_EX, "trace_start", 0, (CmdCallBackFunc)LOS_TraceStart); //追踪功能的启动// SHELLCMD_ENTRY(tracestop_shellcmd, CMD_TYPE_EX, "trace_stop", 0, (CmdCallBackFunc)LOS_TraceStop); //追踪功能的停止// SHELLCMD_ENTRY(tracesetmask_shellcmd, CMD_TYPE_EX, "trace_mask", 1, (CmdCallBackFunc)OsShellCmdTraceSetMask); //设置追踪事件掩码// SHELLCMD_ENTRY(tracereset_shellcmd, CMD_TYPE_EX, "trace_reset", 0, (CmdCallBackFunc)LOS_TraceReset); //重置追踪记录// SHELLCMD_ENTRY(tracedump_shellcmd, CMD_TYPE_EX, "trace_dump", 1, (CmdCallBackFunc)OsShellCmdTraceDump); //转储追踪记录// #endif #endif /* LOSCFG_KERNEL_TRACE */ #ifdef __cplusplus #if __cplusplus } #endif /* __cplusplus */ #endif /* __cplusplus */