1 /*
2 * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
3 * Copyright (c) 2020-2022 Huawei Device Co., Ltd. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without modification,
6 * are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice, this list of
9 * conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
12 * of conditions and the following disclaimer in the documentation and/or other materials
13 * provided with the distribution.
14 *
15 * 3. Neither the name of the copyright holder nor the names of its contributors may be used
16 * to endorse or promote products derived from this software without specific prior written
17 * permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
26 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
29 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include "los_trace_pri.h"
33 #include "trace_pipeline.h"
34 #include "los_memory.h"
35 #include "los_config.h"
36 #include "securec.h"
37 #include "trace_cnv.h"
38 #include "los_init.h"
39 #include "los_process.h"
40 #include "los_sched_pri.h"
41
42 #ifdef LOSCFG_KERNEL_SMP
43 #include "los_mp.h"
44 #endif
45
46 #ifdef LOSCFG_SHELL
47 #include "shcmd.h"
48 #include "shell.h"
49 #endif
50
51 LITE_OS_SEC_BSS STATIC UINT32 g_traceEventCount;
52 LITE_OS_SEC_BSS STATIC volatile enum TraceState g_traceState = TRACE_UNINIT;
53 LITE_OS_SEC_DATA_INIT STATIC volatile BOOL g_enableTrace = FALSE;
54 LITE_OS_SEC_BSS STATIC UINT32 g_traceMask = TRACE_DEFAULT_MASK;
55
56 TRACE_EVENT_HOOK g_traceEventHook = NULL;
57 TRACE_DUMP_HOOK g_traceDumpHook = NULL;
58
59 #ifdef LOSCFG_TRACE_CONTROL_AGENT
60 LITE_OS_SEC_BSS STATIC UINT32 g_traceTaskId;
61 #endif
62
63 #define EVENT_MASK 0xFFFFFFF0
64 #define MIN(x, y) ((x) < (y) ? (x) : (y))
65
66 LITE_OS_SEC_BSS STATIC TRACE_HWI_FILTER_HOOK g_traceHwiFilterHook = NULL;
67
68 #ifdef LOSCFG_KERNEL_SMP
69 LITE_OS_SEC_BSS SPIN_LOCK_INIT(g_traceSpin);
70 #endif
71
OsTraceHwiFilter(UINT32 hwiNum)72 STATIC_INLINE BOOL OsTraceHwiFilter(UINT32 hwiNum)
73 {
74 BOOL ret = ((hwiNum == NUM_HAL_INTERRUPT_UART) || (hwiNum == OS_TICK_INT_NUM));
75 #ifdef LOSCFG_KERNEL_SMP
76 ret |= (hwiNum == LOS_MP_IPI_SCHEDULE);
77 #endif
78 if (g_traceHwiFilterHook != NULL) {
79 ret |= g_traceHwiFilterHook(hwiNum);
80 }
81 return ret;
82 }
83
OsTraceSetFrame(TraceEventFrame * frame,UINT32 eventType,UINTPTR identity,const UINTPTR * params,UINT16 paramCount)84 STATIC VOID OsTraceSetFrame(TraceEventFrame *frame, UINT32 eventType, UINTPTR identity, const UINTPTR *params,
85 UINT16 paramCount)
86 {
87 INT32 i;
88 UINT32 intSave;
89
90 (VOID)memset_s(frame, sizeof(TraceEventFrame), 0, sizeof(TraceEventFrame));
91
92 if (paramCount > LOSCFG_TRACE_FRAME_MAX_PARAMS) {
93 paramCount = LOSCFG_TRACE_FRAME_MAX_PARAMS;
94 }
95
96 TRACE_LOCK(intSave);
97 frame->curTask = OsTraceGetMaskTid(LOS_CurTaskIDGet());
98 frame->curPid = LOS_GetCurrProcessID();
99 frame->identity = identity;
100 frame->curTime = HalClockGetCycles();
101 frame->eventType = eventType;
102
103 #ifdef LOSCFG_TRACE_FRAME_CORE_MSG
104 frame->core.cpuid = ArchCurrCpuid();
105 frame->core.hwiActive = OS_INT_ACTIVE ? TRUE : FALSE;
106 frame->core.taskLockCnt = MIN(OsSchedLockCountGet(), 0xF); /* taskLockCnt is 4 bits, max value = 0xF */
107 frame->core.paramCount = paramCount;
108 #endif
109
110 #ifdef LOS_TRACE_FRAME_LR
111 /* Get the linkreg from stack fp and storage to frame */
112 LOS_RecordLR(frame->linkReg, LOS_TRACE_LR_RECORD, LOS_TRACE_LR_RECORD, LOS_TRACE_LR_IGNORE);
113 #endif
114
115 #ifdef LOSCFG_TRACE_FRAME_EVENT_COUNT
116 frame->eventCount = g_traceEventCount;
117 g_traceEventCount++;
118 #endif
119 TRACE_UNLOCK(intSave);
120
121 for (i = 0; i < paramCount; i++) {
122 frame->params[i] = params[i];
123 }
124 }
125
OsTraceSetObj(ObjData * obj,const LosTaskCB * tcb)126 VOID OsTraceSetObj(ObjData *obj, const LosTaskCB *tcb)
127 {
128 errno_t ret;
129 SchedParam param = { 0 };
130 (VOID)memset_s(obj, sizeof(ObjData), 0, sizeof(ObjData));
131
132 obj->id = OsTraceGetMaskTid(tcb->taskID);
133 tcb->ops->schedParamGet(tcb, ¶m);
134 obj->prio = param.priority;
135
136 ret = strncpy_s(obj->name, LOSCFG_TRACE_OBJ_MAX_NAME_SIZE, tcb->taskName, LOSCFG_TRACE_OBJ_MAX_NAME_SIZE - 1);
137 if (ret != EOK) {
138 TRACE_ERROR("Task name copy failed!\n");
139 }
140 }
141
OsTraceHook(UINT32 eventType,UINTPTR identity,const UINTPTR * params,UINT16 paramCount)142 VOID OsTraceHook(UINT32 eventType, UINTPTR identity, const UINTPTR *params, UINT16 paramCount)
143 {
144 TraceEventFrame frame;
145 if ((eventType == TASK_CREATE) || (eventType == TASK_PRIOSET)) {
146 OsTraceObjAdd(eventType, identity); /* handle important obj info, these can not be filtered */
147 }
148
149 if ((g_enableTrace == TRUE) && (eventType & g_traceMask)) {
150 UINTPTR id = identity;
151 if (TRACE_GET_MODE_FLAG(eventType) == TRACE_HWI_FLAG) {
152 if (OsTraceHwiFilter(identity)) {
153 return;
154 }
155 } else if (TRACE_GET_MODE_FLAG(eventType) == TRACE_TASK_FLAG) {
156 id = OsTraceGetMaskTid(identity);
157 } else if (eventType == MEM_INFO_REQ) {
158 LOS_MEM_POOL_STATUS status;
159 LOS_MemInfoGet((VOID *)identity, &status);
160 LOS_TRACE(MEM_INFO, identity, status.totalUsedSize, status.totalFreeSize);
161 return;
162 }
163
164 OsTraceSetFrame(&frame, eventType, id, params, paramCount);
165 OsTraceWriteOrSendEvent(&frame);
166 }
167 }
168
OsTraceIsEnable(VOID)169 BOOL OsTraceIsEnable(VOID)
170 {
171 return g_enableTrace;
172 }
173
OsTraceHookInstall(VOID)174 STATIC VOID OsTraceHookInstall(VOID)
175 {
176 g_traceEventHook = OsTraceHook;
177 #ifdef LOSCFG_RECORDER_MODE_OFFLINE
178 g_traceDumpHook = OsTraceRecordDump;
179 #endif
180 }
181
182 #ifdef LOSCFG_TRACE_CONTROL_AGENT
OsTraceCmdIsValid(const TraceClientCmd * msg)183 STATIC BOOL OsTraceCmdIsValid(const TraceClientCmd *msg)
184 {
185 return ((msg->end == TRACE_CMD_END_CHAR) && (msg->cmd < TRACE_CMD_MAX_CODE));
186 }
187
OsTraceCmdHandle(const TraceClientCmd * msg)188 STATIC VOID OsTraceCmdHandle(const TraceClientCmd *msg)
189 {
190 if (!OsTraceCmdIsValid(msg)) {
191 return;
192 }
193
194 switch (msg->cmd) {
195 case TRACE_CMD_START:
196 LOS_TraceStart();
197 break;
198 case TRACE_CMD_STOP:
199 LOS_TraceStop();
200 break;
201 case TRACE_CMD_SET_EVENT_MASK:
202 /* 4 params(UINT8) composition the mask(UINT32) */
203 LOS_TraceEventMaskSet(TRACE_MASK_COMBINE(msg->param1, msg->param2, msg->param3, msg->param4));
204 break;
205 case TRACE_CMD_RECODE_DUMP:
206 LOS_TraceRecordDump(TRUE);
207 break;
208 default:
209 break;
210 }
211 }
212
TraceAgent(VOID)213 VOID TraceAgent(VOID)
214 {
215 UINT32 ret;
216 TraceClientCmd msg;
217
218 while (1) {
219 (VOID)memset_s(&msg, sizeof(TraceClientCmd), 0, sizeof(TraceClientCmd));
220 ret = OsTraceDataWait();
221 if (ret == LOS_OK) {
222 OsTraceDataRecv((UINT8 *)&msg, sizeof(TraceClientCmd), 0);
223 OsTraceCmdHandle(&msg);
224 }
225 }
226 }
227
OsCreateTraceAgentTask(VOID)228 STATIC UINT32 OsCreateTraceAgentTask(VOID)
229 {
230 UINT32 ret;
231 TSK_INIT_PARAM_S taskInitParam;
232
233 (VOID)memset_s((VOID *)(&taskInitParam), sizeof(TSK_INIT_PARAM_S), 0, sizeof(TSK_INIT_PARAM_S));
234 taskInitParam.pfnTaskEntry = (TSK_ENTRY_FUNC)TraceAgent;
235 taskInitParam.usTaskPrio = LOSCFG_TRACE_TASK_PRIORITY;
236 taskInitParam.pcName = "TraceAgent";
237 taskInitParam.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;
238 #ifdef LOSCFG_KERNEL_SMP
239 taskInitParam.usCpuAffiMask = CPUID_TO_AFFI_MASK(ArchCurrCpuid());
240 #endif
241 ret = LOS_TaskCreate(&g_traceTaskId, &taskInitParam);
242 return ret;
243 }
244 #endif
245
OsTraceInit(VOID)246 STATIC UINT32 OsTraceInit(VOID)
247 {
248 UINT32 ret;
249
250 if (g_traceState != TRACE_UNINIT) {
251 TRACE_ERROR("trace has been initialized already, the current state is :%d\n", g_traceState);
252 ret = LOS_ERRNO_TRACE_ERROR_STATUS;
253 goto LOS_ERREND;
254 }
255
256 #ifdef LOSCFG_TRACE_CLIENT_INTERACT
257 ret = OsTracePipelineInit();
258 if (ret != LOS_OK) {
259 goto LOS_ERREND;
260 }
261 #endif
262
263 #ifdef LOSCFG_TRACE_CONTROL_AGENT
264 ret = OsCreateTraceAgentTask();
265 if (ret != LOS_OK) {
266 TRACE_ERROR("trace init create agentTask error :0x%x\n", ret);
267 goto LOS_ERREND;
268 }
269 #endif
270
271 #ifdef LOSCFG_RECORDER_MODE_OFFLINE
272 ret = OsTraceBufInit(LOSCFG_TRACE_BUFFER_SIZE);
273 if (ret != LOS_OK) {
274 #ifdef LOSCFG_TRACE_CONTROL_AGENT
275 (VOID)LOS_TaskDelete(g_traceTaskId);
276 #endif
277 goto LOS_ERREND;
278 }
279 #endif
280
281 OsTraceHookInstall();
282 OsTraceCnvInit();
283
284 g_traceEventCount = 0;
285
286 #ifdef LOSCFG_RECORDER_MODE_ONLINE /* Wait trace client to start trace */
287 g_enableTrace = FALSE;
288 g_traceState = TRACE_INITED;
289 #else
290 g_enableTrace = TRUE;
291 g_traceState = TRACE_STARTED;
292 #endif
293 return LOS_OK;
294 LOS_ERREND:
295 return ret;
296 }
297
LOS_TraceStart(VOID)298 UINT32 LOS_TraceStart(VOID)
299 {
300 UINT32 intSave;
301 UINT32 ret = LOS_OK;
302
303 TRACE_LOCK(intSave);
304 if (g_traceState == TRACE_STARTED) {
305 goto START_END;
306 }
307
308 if (g_traceState == TRACE_UNINIT) {
309 TRACE_ERROR("trace not inited, be sure LOS_TraceInit excute success\n");
310 ret = LOS_ERRNO_TRACE_ERROR_STATUS;
311 goto START_END;
312 }
313
314 OsTraceNotifyStart();
315
316 g_enableTrace = TRUE;
317 g_traceState = TRACE_STARTED;
318
319 TRACE_UNLOCK(intSave);
320 LOS_TRACE(MEM_INFO_REQ, m_aucSysMem0);
321 return ret;
322 START_END:
323 TRACE_UNLOCK(intSave);
324 return ret;
325 }
326
LOS_TraceStop(VOID)327 VOID LOS_TraceStop(VOID)
328 {
329 UINT32 intSave;
330
331 TRACE_LOCK(intSave);
332 if (g_traceState != TRACE_STARTED) {
333 goto STOP_END;
334 }
335
336 g_enableTrace = FALSE;
337 g_traceState = TRACE_STOPED;
338 OsTraceNotifyStop();
339 STOP_END:
340 TRACE_UNLOCK(intSave);
341 }
342
LOS_TraceEventMaskSet(UINT32 mask)343 VOID LOS_TraceEventMaskSet(UINT32 mask)
344 {
345 g_traceMask = mask & EVENT_MASK;
346 }
347
LOS_TraceRecordDump(BOOL toClient)348 VOID LOS_TraceRecordDump(BOOL toClient)
349 {
350 if (g_traceState != TRACE_STOPED) {
351 TRACE_ERROR("trace dump must after trace stopped , the current state is : %d\n", g_traceState);
352 return;
353 }
354 OsTraceRecordDump(toClient);
355 }
356
LOS_TraceRecordGet(VOID)357 OfflineHead *LOS_TraceRecordGet(VOID)
358 {
359 return OsTraceRecordGet();
360 }
361
LOS_TraceReset(VOID)362 VOID LOS_TraceReset(VOID)
363 {
364 if (g_traceState == TRACE_UNINIT) {
365 TRACE_ERROR("trace not inited, be sure LOS_TraceInit excute success\n");
366 return;
367 }
368
369 OsTraceReset();
370 }
371
LOS_TraceHwiFilterHookReg(TRACE_HWI_FILTER_HOOK hook)372 VOID LOS_TraceHwiFilterHookReg(TRACE_HWI_FILTER_HOOK hook)
373 {
374 UINT32 intSave;
375
376 TRACE_LOCK(intSave);
377 g_traceHwiFilterHook = hook;
378 TRACE_UNLOCK(intSave);
379 }
380
381 #ifdef LOSCFG_SHELL
OsShellCmdTraceSetMask(INT32 argc,const CHAR ** argv)382 LITE_OS_SEC_TEXT_MINOR UINT32 OsShellCmdTraceSetMask(INT32 argc, const CHAR **argv)
383 {
384 size_t mask;
385 CHAR *endPtr = NULL;
386
387 if (argc >= 2) { /* 2:Just as number of parameters */
388 PRINTK("\nUsage: trace_mask or trace_mask ID\n");
389 return OS_ERROR;
390 }
391
392 if (argc == 0) {
393 mask = TRACE_DEFAULT_MASK;
394 } else {
395 mask = strtoul(argv[0], &endPtr, 0);
396 }
397 LOS_TraceEventMaskSet((UINT32)mask);
398 return LOS_OK;
399 }
400
OsShellCmdTraceDump(INT32 argc,const CHAR ** argv)401 LITE_OS_SEC_TEXT_MINOR UINT32 OsShellCmdTraceDump(INT32 argc, const CHAR **argv)
402 {
403 BOOL toClient;
404 CHAR *endPtr = NULL;
405
406 if (argc >= 2) { /* 2:Just as number of parameters */
407 PRINTK("\nUsage: trace_dump or trace_dump [1/0]\n");
408 return OS_ERROR;
409 }
410
411 if (argc == 0) {
412 toClient = FALSE;
413 } else {
414 toClient = strtoul(argv[0], &endPtr, 0) != 0 ? TRUE : FALSE;
415 }
416 LOS_TraceRecordDump(toClient);
417 return LOS_OK;
418 }
419
420 SHELLCMD_ENTRY(tracestart_shellcmd, CMD_TYPE_EX, "trace_start", 0, (CmdCallBackFunc)LOS_TraceStart);
421 SHELLCMD_ENTRY(tracestop_shellcmd, CMD_TYPE_EX, "trace_stop", 0, (CmdCallBackFunc)LOS_TraceStop);
422 SHELLCMD_ENTRY(tracesetmask_shellcmd, CMD_TYPE_EX, "trace_mask", 1, (CmdCallBackFunc)OsShellCmdTraceSetMask);
423 SHELLCMD_ENTRY(tracereset_shellcmd, CMD_TYPE_EX, "trace_reset", 0, (CmdCallBackFunc)LOS_TraceReset);
424 SHELLCMD_ENTRY(tracedump_shellcmd, CMD_TYPE_EX, "trace_dump", 1, (CmdCallBackFunc)OsShellCmdTraceDump);
425 #endif
426
427 LOS_MODULE_INIT(OsTraceInit, LOS_INIT_LEVEL_KMOD_EXTENDED);
428