1/*
2 * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
3 * Copyright (c) 2020-2021 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
39#if (LOSCFG_KERNEL_SMP == 1)
40#include "los_mp_pri.h"
41#endif
42
43#if (LOSCFG_SHELL == 1)
44#include "shcmd.h"
45#include "shell.h"
46#endif
47
48#if (LOSCFG_KERNEL_TRACE == 1)
49LITE_OS_SEC_BSS STATIC UINT32 g_traceEventCount;
50LITE_OS_SEC_BSS STATIC volatile enum TraceState g_traceState = TRACE_UNINIT;
51LITE_OS_SEC_DATA_INIT STATIC volatile BOOL g_enableTrace = FALSE;
52LITE_OS_SEC_BSS STATIC UINT32 g_traceMask = TRACE_DEFAULT_MASK;
53
54TRACE_EVENT_HOOK g_traceEventHook = NULL;
55TRACE_DUMP_HOOK g_traceDumpHook = NULL;
56
57#if (LOSCFG_TRACE_CONTROL_AGENT == 1)
58LITE_OS_SEC_BSS STATIC UINT32 g_traceTaskId;
59#endif
60
61#define EVENT_MASK            0xFFFFFFF0
62#define MIN(x, y)             ((x) < (y) ? (x) : (y))
63
64LITE_OS_SEC_BSS STATIC TRACE_HWI_FILTER_HOOK g_traceHwiFliterHook = NULL;
65
66#if (LOSCFG_KERNEL_SMP == 1)
67LITE_OS_SEC_BSS SPIN_LOCK_INIT(g_traceSpin);
68#endif
69
70STATIC_INLINE BOOL OsTraceHwiFilter(UINT32 hwiNum)
71{
72    BOOL ret = ((hwiNum == NUM_HAL_INTERRUPT_UART) || (hwiNum == OS_TICK_INT_NUM));
73#if (LOSCFG_KERNEL_SMP == 1)
74    ret |= (hwiNum == LOS_MP_IPI_SCHEDULE);
75#endif
76    if (g_traceHwiFliterHook != NULL) {
77        ret |= g_traceHwiFliterHook(hwiNum);
78    }
79    return ret;
80}
81
82STATIC VOID OsTraceSetFrame(TraceEventFrame *frame, UINT32 eventType, UINTPTR identity, const UINTPTR *params,
83    UINT16 paramCount)
84{
85    INT32 i;
86    UINT32 intSave;
87
88    (VOID)memset_s(frame, sizeof(TraceEventFrame), 0, sizeof(TraceEventFrame));
89
90    if (paramCount > LOSCFG_TRACE_FRAME_MAX_PARAMS) {
91        paramCount = LOSCFG_TRACE_FRAME_MAX_PARAMS;
92    }
93
94    TRACE_LOCK(intSave);
95    frame->curTask   = OsTraceGetMaskTid(LOS_CurTaskIDGet());
96    frame->identity  = identity;
97    frame->curTime   = LOS_SysCycleGet();
98    frame->eventType = eventType;
99
100#if (LOSCFG_TRACE_FRAME_CORE_MSG == 1)
101    frame->core.cpuId      = ArchCurrCpuid();
102    frame->core.hwiActive  = OS_INT_ACTIVE ? TRUE : FALSE;
103    frame->core.taskLockCnt = MIN(OsPercpuGet()->taskLockCnt, 0xF); /* taskLockCnt is 4 bits, max value = 0xF */
104    frame->core.paramCount = paramCount;
105#endif
106
107#if (LOSCFG_TRACE_FRAME_EVENT_COUNT == 1)
108    frame->eventCount = g_traceEventCount;
109    g_traceEventCount++;
110#endif
111    TRACE_UNLOCK(intSave);
112
113    for (i = 0; i < paramCount; i++) {
114        frame->params[i] = params[i];
115    }
116}
117
118VOID OsTraceSetObj(ObjData *obj, const LosTaskCB *tcb)
119{
120    errno_t ret;
121    (VOID)memset_s(obj, sizeof(ObjData), 0, sizeof(ObjData));
122
123    obj->id   = OsTraceGetMaskTid(tcb->taskID);
124    obj->prio = tcb->priority;
125
126    ret = strncpy_s(obj->name, LOSCFG_TRACE_OBJ_MAX_NAME_SIZE, tcb->taskName, LOSCFG_TRACE_OBJ_MAX_NAME_SIZE - 1);
127    if (ret != EOK) {
128        TRACE_ERROR("Task name copy failed!\n");
129    }
130}
131
132VOID OsTraceHook(UINT32 eventType, UINTPTR identity, const UINTPTR *params, UINT16 paramCount)
133{
134    if ((eventType == TASK_CREATE) || (eventType == TASK_PRIOSET)) {
135        OsTraceObjAdd(eventType, identity); /* handle important obj info, these can not be filtered */
136    }
137
138    if ((g_enableTrace == TRUE) && (eventType & g_traceMask)) {
139        UINTPTR id = identity;
140        if (TRACE_GET_MODE_FLAG(eventType) == TRACE_HWI_FLAG) {
141            if (OsTraceHwiFilter(identity)) {
142                return;
143            }
144        } else if (TRACE_GET_MODE_FLAG(eventType) == TRACE_TASK_FLAG) {
145            id = OsTraceGetMaskTid(identity);
146        } else if (eventType == MEM_INFO_REQ) {
147            LOS_MEM_POOL_STATUS status;
148            LOS_MemInfoGet((VOID *)identity, &status);
149            LOS_TRACE(MEM_INFO, identity, status.totalUsedSize, status.totalFreeSize);
150            return;
151        }
152
153        TraceEventFrame frame;
154        OsTraceSetFrame(&frame, eventType, id, params, paramCount);
155
156        OsTraceWriteOrSendEvent(&frame);
157    }
158}
159
160BOOL OsTraceIsEnable(VOID)
161{
162    return g_enableTrace == TRUE;
163}
164
165STATIC VOID OsTraceHookInstall(VOID)
166{
167    g_traceEventHook = OsTraceHook;
168#if (LOSCFG_RECORDER_MODE_OFFLINE == 1)
169    g_traceDumpHook = OsTraceRecordDump;
170#endif
171}
172
173#if (LOSCFG_TRACE_CONTROL_AGENT == 1)
174STATIC BOOL OsTraceCmdIsValid(const TraceClientCmd *msg)
175{
176    return ((msg->end == TRACE_CMD_END_CHAR) && (msg->cmd < TRACE_CMD_MAX_CODE));
177}
178
179STATIC VOID OsTraceCmdHandle(const TraceClientCmd *msg)
180{
181    if (!OsTraceCmdIsValid(msg)) {
182        return;
183    }
184
185    switch (msg->cmd) {
186        case TRACE_CMD_START:
187            LOS_TraceStart();
188            break;
189        case TRACE_CMD_STOP:
190            LOS_TraceStop();
191            break;
192        case TRACE_CMD_SET_EVENT_MASK:
193            /* 4 params(UINT8) composition the mask(UINT32) */
194            LOS_TraceEventMaskSet(TRACE_MASK_COMBINE(msg->param1, msg->param2, msg->param3, msg->param4));
195            break;
196        case TRACE_CMD_RECODE_DUMP:
197            LOS_TraceRecordDump(TRUE);
198            break;
199        default:
200            break;
201    }
202}
203
204VOID TraceAgent(VOID)
205{
206    UINT32 ret;
207    TraceClientCmd msg;
208
209    while (1) {
210        (VOID)memset_s(&msg, sizeof(TraceClientCmd), 0, sizeof(TraceClientCmd));
211        ret = OsTraceDataWait();
212        if (ret == LOS_OK) {
213            OsTraceDataRecv((UINT8 *)&msg, sizeof(TraceClientCmd), 0);
214            OsTraceCmdHandle(&msg);
215        }
216    }
217}
218
219STATIC UINT32 OsCreateTraceAgentTask(VOID)
220{
221    UINT32 ret;
222    TSK_INIT_PARAM_S taskInitParam;
223
224    (VOID)memset_s((VOID *)(&taskInitParam), sizeof(TSK_INIT_PARAM_S), 0, sizeof(TSK_INIT_PARAM_S));
225    taskInitParam.pfnTaskEntry = (TSK_ENTRY_FUNC)TraceAgent;
226    taskInitParam.usTaskPrio = LOSCFG_TRACE_TASK_PRIORITY;
227    taskInitParam.pcName = "TraceAgent";
228    taskInitParam.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;
229#if (LOSCFG_KERNEL_SMP == 1)
230    taskInitParam.usCpuAffiMask = CPUID_TO_AFFI_MASK(ArchCurrCpuid());
231#endif
232    ret = LOS_TaskCreate(&g_traceTaskId, &taskInitParam);
233    return ret;
234}
235#endif
236
237UINT32 OsTraceInit(VOID)
238{
239    UINT32 intSave;
240    UINT32 ret;
241
242    TRACE_LOCK(intSave);
243    if (g_traceState != TRACE_UNINIT) {
244        TRACE_ERROR("trace has been initialized already, the current state is :%d\n", g_traceState);
245        ret = LOS_ERRNO_TRACE_ERROR_STATUS;
246        goto LOS_ERREND;
247    }
248
249#if (LOSCFG_TRACE_CLIENT_INTERACT == 1)
250    ret = OsTracePipelineInit();
251    if (ret != LOS_OK) {
252        goto LOS_ERREND;
253    }
254#endif
255
256#if (LOSCFG_TRACE_CONTROL_AGENT == 1)
257    ret = OsCreateTraceAgentTask();
258    if (ret != LOS_OK) {
259        TRACE_ERROR("trace init create agentTask error :0x%x\n", ret);
260        goto LOS_ERREND;
261    }
262#endif
263
264#if (LOSCFG_RECORDER_MODE_OFFLINE == 1)
265    ret = OsTraceBufInit(LOSCFG_TRACE_BUFFER_SIZE);
266    if (ret != LOS_OK) {
267#if (LOSCFG_TRACE_CONTROL_AGENT == 1)
268        (VOID)LOS_TaskDelete(g_traceTaskId);
269#endif
270        goto LOS_ERREND;
271    }
272#endif
273
274    OsTraceHookInstall();
275    OsTraceCnvInit();
276
277    g_traceEventCount = 0;
278
279#if (LOSCFG_RECORDER_MODE_ONLINE == 1)  /* Wait trace client to start trace */
280    g_enableTrace = FALSE;
281    g_traceState = TRACE_INITED;
282#else
283    g_enableTrace = TRUE;
284    g_traceState = TRACE_STARTED;
285#endif
286    TRACE_UNLOCK(intSave);
287    return LOS_OK;
288LOS_ERREND:
289    TRACE_UNLOCK(intSave);
290    return ret;
291}
292
293UINT32 LOS_TraceStart(VOID)
294{
295    UINT32 intSave;
296    UINT32 ret = LOS_OK;
297
298    TRACE_LOCK(intSave);
299    if (g_traceState == TRACE_STARTED) {
300        goto START_END;
301    }
302
303    if (g_traceState == TRACE_UNINIT) {
304        TRACE_ERROR("trace not inited, be sure LOS_TraceInit excute success\n");
305        ret = LOS_ERRNO_TRACE_ERROR_STATUS;
306        goto START_END;
307    }
308
309    OsTraceNotifyStart();
310
311    g_enableTrace = TRUE;
312    g_traceState = TRACE_STARTED;
313
314    TRACE_UNLOCK(intSave);
315    LOS_TRACE(MEM_INFO_REQ, m_aucSysMem0);
316    return ret;
317START_END:
318    TRACE_UNLOCK(intSave);
319    return ret;
320}
321
322VOID LOS_TraceStop(VOID)
323{
324    UINT32 intSave;
325
326    TRACE_LOCK(intSave);
327    if (g_traceState != TRACE_STARTED) {
328        goto STOP_END;
329    }
330
331    g_enableTrace = FALSE;
332    g_traceState = TRACE_STOPED;
333    OsTraceNotifyStop();
334STOP_END:
335    TRACE_UNLOCK(intSave);
336}
337
338VOID LOS_TraceEventMaskSet(UINT32 mask)
339{
340    g_traceMask = mask & EVENT_MASK;
341}
342
343VOID LOS_TraceRecordDump(BOOL toClient)
344{
345    if (g_traceState != TRACE_STOPED) {
346        TRACE_ERROR("trace dump must after trace stopped , the current state is : %d\n", g_traceState);
347        return;
348    }
349    OsTraceRecordDump(toClient);
350}
351
352OfflineHead *LOS_TraceRecordGet(VOID)
353{
354    return OsTraceRecordGet();
355}
356
357VOID LOS_TraceReset(VOID)
358{
359    if (g_traceState == TRACE_UNINIT) {
360        TRACE_ERROR("trace not inited, be sure LOS_TraceInit excute success\n");
361        return;
362    }
363
364    OsTraceReset();
365}
366
367VOID LOS_TraceHwiFilterHookReg(TRACE_HWI_FILTER_HOOK hook)
368{
369    UINT32 intSave;
370
371    TRACE_LOCK(intSave);
372    g_traceHwiFliterHook = hook;
373    TRACE_UNLOCK(intSave);
374}
375
376#if (LOSCFG_SHELL == 1)
377LITE_OS_SEC_TEXT_MINOR UINT32 OsShellCmdTraceSetMask(INT32 argc, const CHAR **argv)
378{
379    size_t mask;
380    CHAR *endPtr = NULL;
381
382    if (argc >= 2) { /* 2:Just as number of parameters */
383        PRINTK("\nUsage: trace_mask or trace_mask ID\n");
384        return OS_ERROR;
385    }
386
387    if (argc == 0) {
388        mask = TRACE_DEFAULT_MASK;
389    } else {
390        mask = strtoul(argv[0], &endPtr, 0);
391    }
392    LOS_TraceEventMaskSet((UINT32)mask);
393    return LOS_OK;
394}
395
396LITE_OS_SEC_TEXT_MINOR UINT32 OsShellCmdTraceDump(INT32 argc, const CHAR **argv)
397{
398    BOOL toClient;
399    CHAR *endPtr = NULL;
400
401    if (argc >= 2) { /* 2:Just as number of parameters */
402        PRINTK("\nUsage: trace_dump or trace_dump [1/0]\n");
403        return OS_ERROR;
404    }
405
406    if (argc == 0) {
407        toClient = FALSE;
408    } else {
409        toClient = strtoul(argv[0], &endPtr, 0) != 0 ? TRUE : FALSE;
410    }
411    LOS_TraceRecordDump(toClient);
412    return LOS_OK;
413}
414#endif
415
416#endif /* LOSCFG_KERNEL_TRACE == 1 */
417