1 /*
2 * Trace Recorder for Tracealyzer v4.6.6
3 * Copyright 2021 Percepio AB
4 * www.percepio.com
5 *
6 * SPDX-License-Identifier: Apache-2.0
7 *
8 * The generic core of the trace recorder's streaming mode.
9 */
10
11 #include <trcRecorder.h>
12
13 #if (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING)
14
15 #if (TRC_USE_TRACEALYZER_RECORDER == 1)
16
17 #ifndef TRC_KERNEL_PORT_HEAP_INIT
18 #define TRC_KERNEL_PORT_HEAP_INIT(__size)
19 #endif
20
21 typedef struct TraceHeader
22 {
23 uint32_t uiPSF;
24 uint16_t uiVersion;
25 uint16_t uiPlatform;
26 uint32_t uiOptions;
27 uint32_t uiNumCores;
28 uint32_t isrTailchainingThreshold;
29 char platformCfg[8];
30 uint16_t uiPlatformCfgPatch;
31 uint8_t uiPlatformCfgMinor;
32 uint8_t uiPlatformCfgMajor;
33 } TraceHeader_t;
34
35 /* The data structure for commands (a bit overkill) */
36 typedef struct TraceCommandType_t
37 {
38 unsigned char cmdCode;
39 unsigned char param1;
40 unsigned char param2;
41 unsigned char param3;
42 unsigned char param4;
43 unsigned char param5;
44 unsigned char checksumLSB;
45 unsigned char checksumMSB;
46 } TraceCommand_t;
47
48 #ifndef TRC_CFG_RECORDER_DATA_INIT
49 #define TRC_CFG_RECORDER_DATA_INIT 1
50 #endif
51
52 /* Used to interpret the data format */
53 #define TRACE_FORMAT_VERSION ((uint16_t)0x000A)
54
55 /* Used to determine endian of data (big/little) */
56 #define TRACE_PSF_ENDIANESS_IDENTIFIER ((uint32_t)0x50534600)
57
58 #if (TRC_CFG_RECORDER_BUFFER_ALLOCATION == TRC_RECORDER_BUFFER_ALLOCATION_STATIC)
59 static TraceRecorderData_t xRecorderData TRC_CFG_RECORDER_DATA_ATTRIBUTE;
60 TraceRecorderData_t* pxTraceRecorderData = &xRecorderData;
61 #else
62 /* If using DYNAMIC or CUSTOM allocation */
63 TraceRecorderData_t* pxTraceRecorderData TRC_CFG_RECORDER_DATA_ATTRIBUTE;
64 #endif
65
66 static TraceHeader_t* pxHeader;
67
68 /*******************************************************************************
69 * RecorderInitialized
70 *
71 * Makes sure the recorder data is only initialized once.
72 *
73 * NOTE: RecorderInitialized is only initialized to 0 if
74 * TRC_CFG_RECORDER_DATA_INIT is non-zero.
75 * This will avoid issues where the recorder must be started before main(),
76 * which can lead to RecorderInitialized be cleared by late initialization after
77 * xTraceEnable(TRC_INIT) was called and assigned RecorderInitialized its'
78 * value.
79 ******************************************************************************/
80 #if (TRC_CFG_RECORDER_DATA_INIT != 0)
81 uint32_t RecorderInitialized = 0;
82 #else /* (TRC_CFG_RECORDER_DATA_INIT != 0) */
83 uint32_t RecorderInitialized TRC_CFG_RECORDER_DATA_ATTRIBUTE;
84 #endif /* (TRC_CFG_RECORDER_DATA_INIT != 0) */
85
86 #if (TRC_EXTERNAL_BUFFERS == 0)
87 /* Stores the header information on Start */
88 static void prvTraceStoreHeader(void);
89
90 /* Store the Timestamp info */
91 static void prvTraceStoreTimestampInfo(void);
92
93 /* Stores the entry table on Start */
94 static void prvTraceStoreEntryTable(void);
95
96 #else /* (TRC_EXTERNAL_BUFFERS == 0) */
97
98 #define prvTraceStoreHeader()
99 #define prvTraceStoreTimestampInfo()
100 #define prvTraceStoreEntryTable()
101
102 #endif /* (TRC_EXTERNAL_BUFFERS == 0) */
103
104 /* Store start event. */
105 static void prvTraceStoreStartEvent(void);
106
107 /* Checks if the provided command is a valid command */
108 static int prvIsValidCommand(TraceCommand_t* cmd);
109
110 /* Executed the received command (Start or Stop) */
111 static void prvProcessCommand(TraceCommand_t* cmd);
112
113 /* Internal function for starting the recorder */
114 static void prvSetRecorderEnabled(void);
115
116 /* Internal function for stopping the recorder */
117 static void prvSetRecorderDisabled(void);
118
119 /******************************************************************************
120 * xTraceInitialize
121 *
122 * Initializes the recorder data.
123 * This function will be called by xTraceEnable(...).
124 * Only needs to be called manually if traced objects are created before the
125 * trace recorder can be enabled, at which point make sure to call this function
126 * as early as possible.
127 * See TRC_CFG_RECORDER_DATA_INIT in trcConfig.h.
128 ******************************************************************************/
xTraceInitialize(void)129 traceResult xTraceInitialize(void)
130 {
131 TRC_ASSERT_EQUAL_SIZE(TraceRecorderDataBuffer_t, TraceRecorderData_t);
132
133 if (RecorderInitialized != 0)
134 {
135 return TRC_SUCCESS;
136 }
137
138 #if (TRC_CFG_RECORDER_BUFFER_ALLOCATION == TRC_RECORDER_BUFFER_ALLOCATION_DYNAMIC)
139 /* Initialize heap */
140 TRC_KERNEL_PORT_HEAP_INIT(sizeof(TraceRecorderData_t));
141
142 /* Allocate data */
143 pxTraceRecorderData = TRC_KERNEL_PORT_HEAP_MALLOC(sizeof(TraceRecorderData_t));
144 #endif
145
146 /* These are set on init so they aren't overwritten by late initialization values. */
147 pxTraceRecorderData->uiSessionCounter = 0;
148 pxTraceRecorderData->uiRecorderEnabled = 0;
149 pxTraceRecorderData->uiTraceSystemState = TRC_STATE_IN_STARTUP;
150
151 #if (TRC_EXTERNAL_BUFFERS == 0)
152 if (xTraceHeaderInitialize(&pxTraceRecorderData->xHeaderBuffer) == TRC_FAIL)
153 {
154 return TRC_FAIL;
155 }
156
157 if (xTraceEntryTableInitialize(&pxTraceRecorderData->xEntryTableBuffer) == TRC_FAIL)
158 {
159 return TRC_FAIL;
160 }
161
162 if (xTraceTimestampInitialize(&pxTraceRecorderData->xTimestampBuffer) == TRC_FAIL)
163 {
164 return TRC_FAIL;
165 }
166 #endif
167
168 if (xTraceStackMonitorInitialize(&pxTraceRecorderData->xStackMonitorBuffer) == TRC_FAIL)
169 {
170 return TRC_FAIL;
171 }
172
173 if (xTraceStreamPortInitialize(&pxTraceRecorderData->xStreamPortBuffer) == TRC_FAIL)
174 {
175 return TRC_FAIL;
176 }
177
178 if (xTraceAssertInitialize(&pxTraceRecorderData->xAssertBuffer) == TRC_FAIL)
179 {
180 return TRC_FAIL;
181 }
182
183 if (xTraceDiagnosticsInitialize(&pxTraceRecorderData->xDiagnosticsBuffer) == TRC_FAIL)
184 {
185 return TRC_FAIL;
186 }
187
188 if (xTraceStaticBufferInitialize(&pxTraceRecorderData->xStaticBufferBuffer) == TRC_FAIL)
189 {
190 return TRC_FAIL;
191 }
192
193 if (xTraceEventInitialize(&pxTraceRecorderData->xEventDataBuffer) == TRC_FAIL)
194 {
195 return TRC_FAIL;
196 }
197
198 if (xTracePrintInitialize(&pxTraceRecorderData->xPrintBuffer) == TRC_FAIL)
199 {
200 return TRC_FAIL;
201 }
202
203 if (xTraceErrorInitialize(&pxTraceRecorderData->xErrorBuffer) == TRC_FAIL)
204 {
205 return TRC_FAIL;
206 }
207
208 if (xTraceISRInitialize(&pxTraceRecorderData->xISRInfoBuffer) == TRC_FAIL)
209 {
210 return TRC_FAIL;
211 }
212
213 if (xTraceTaskInitialize(&pxTraceRecorderData->xTaskInfoBuffer) == TRC_FAIL)
214 {
215 return TRC_FAIL;
216 }
217
218 if (xTraceKernelPortInitialize(&pxTraceRecorderData->xKernelPortBuffer) == TRC_FAIL)
219 {
220 return TRC_FAIL;
221 }
222
223 xTraceSetComponentInitialized(TRC_RECORDER_COMPONENT_CORE);
224
225 return TRC_SUCCESS;
226 }
227
xTraceHeaderInitialize(TraceHeaderBuffer_t * pxBuffer)228 traceResult xTraceHeaderInitialize(TraceHeaderBuffer_t *pxBuffer)
229 {
230 uint32_t i;
231 char* platform_cfg = TRC_PLATFORM_CFG;
232
233 TRC_ASSERT_EQUAL_SIZE(TraceHeaderBuffer_t, TraceHeader_t);
234
235 if (pxBuffer == 0)
236 {
237 return TRC_FAIL;
238 }
239
240 pxHeader = (TraceHeader_t*)pxBuffer;
241
242 pxHeader->uiPSF = TRACE_PSF_ENDIANESS_IDENTIFIER;
243 pxHeader->uiVersion = TRACE_FORMAT_VERSION;
244 pxHeader->uiPlatform = TRACE_KERNEL_VERSION;
245
246 for (i = 0; i < TRC_PLATFORM_CFG_LENGTH; i++)
247 {
248 pxHeader->platformCfg[i] = platform_cfg[i];
249 if (platform_cfg[i] == 0)
250 {
251 break;
252 }
253 }
254 pxHeader->uiPlatformCfgPatch = TRC_PLATFORM_CFG_PATCH;
255 pxHeader->uiPlatformCfgMinor = TRC_PLATFORM_CFG_MINOR;
256 pxHeader->uiPlatformCfgMajor = TRC_PLATFORM_CFG_MAJOR;
257 pxHeader->uiNumCores = TRC_CFG_CORE_COUNT;
258 pxHeader->isrTailchainingThreshold = TRC_CFG_ISR_TAILCHAINING_THRESHOLD;
259
260 /* Lowest bit used for TRC_IRQ_PRIORITY_ORDER */
261 pxHeader->uiOptions = ((TRC_IRQ_PRIORITY_ORDER) << 0);
262
263 /* 3rd bit used for TRC_CFG_TEST_MODE */
264 pxHeader->uiOptions |= ((TRC_CFG_TEST_MODE) << 2);
265
266 return TRC_SUCCESS;
267 }
268
xTraceEnable(uint32_t uiStartOption)269 traceResult xTraceEnable(uint32_t uiStartOption)
270 {
271 TraceCommand_t xCommand;
272 int32_t iBytes = 0;
273
274 if (xTraceInitialize() == TRC_FAIL)
275 {
276 return TRC_FAIL;
277 }
278
279 xTraceStreamPortOnEnable(uiStartOption);
280
281 if (xTraceKernelPortEnable() == TRC_FAIL)
282 {
283 return TRC_FAIL;
284 }
285
286 if (uiStartOption == TRC_START_AWAIT_HOST)
287 {
288 /* We keep trying to read commands from host until the recorder has been started */
289 do
290 {
291 iBytes = 0;
292
293 if (xTraceStreamPortReadData(&xCommand, sizeof(TraceCommand_t), (int32_t*)&iBytes) == TRC_FAIL)
294 {
295 xTraceWarning(TRC_WARNING_STREAM_PORT_READ);
296 }
297
298 if (iBytes == sizeof(TraceCommand_t))
299 {
300 if (prvIsValidCommand(&xCommand))
301 {
302 if (xCommand.cmdCode == CMD_SET_ACTIVE && xCommand.param1 == 1)
303 {
304 /* On start, init and reset the timestamping */
305 TRC_PORT_SPECIFIC_INIT();
306 }
307
308 prvProcessCommand(&xCommand);
309 }
310 }
311 } while (pxTraceRecorderData->uiRecorderEnabled == 0);
312 }
313 else if (uiStartOption == TRC_START)
314 {
315 /* We start streaming directly - this assumes that the host interface is ready! */
316 TRC_PORT_SPECIFIC_INIT();
317
318 xCommand.cmdCode = CMD_SET_ACTIVE;
319 xCommand.param1 = 1;
320 prvProcessCommand(&xCommand);
321 }
322 else if (uiStartOption == TRC_START_FROM_HOST)
323 {
324 /* We prepare the system to receive commands from host, but let system resume execution until that happens */
325 TRC_PORT_SPECIFIC_INIT();
326 }
327
328 return TRC_SUCCESS;
329 }
330
xTraceDisable(void)331 traceResult xTraceDisable(void)
332 {
333 prvSetRecorderDisabled();
334
335 xTraceStreamPortOnDisable();
336
337 return TRC_SUCCESS;
338 }
339
340 #if (TRC_CFG_RECORDER_BUFFER_ALLOCATION == TRC_RECORDER_BUFFER_ALLOCATION_CUSTOM)
xTraceSetBuffer(TraceRecorderDataBuffer_t * pxBuffer)341 traceResult xTraceSetBuffer(TraceRecorderDataBuffer_t* pxBuffer)
342 {
343 if (pxBuffer == 0)
344 {
345 return TRC_FAIL;
346 }
347
348 pxTraceRecorderData = (TraceRecorderData_t*)pxBuffer;
349
350 return TRC_SUCCESS;
351 }
352 #endif
353
xTraceGetEventBuffer(void ** ppvBuffer,TraceUnsignedBaseType_t * puiSize)354 traceResult xTraceGetEventBuffer(void **ppvBuffer, TraceUnsignedBaseType_t *puiSize)
355 {
356 if (pxTraceRecorderData == 0 || ppvBuffer == 0 || puiSize == 0)
357 {
358 return TRC_FAIL;
359 }
360
361 /* Returns the xStreamPortBuffer since that is the one containing trace data */
362 *ppvBuffer = (void*)&pxTraceRecorderData->xStreamPortBuffer;
363 *puiSize = sizeof(pxTraceRecorderData->xStreamPortBuffer);
364
365 return TRC_SUCCESS;
366 }
367
xTraceTzCtrl(void)368 traceResult xTraceTzCtrl(void)
369 {
370 TraceCommand_t xCommand;
371 int32_t iBytes = 0;
372
373 do
374 {
375 /* Listen for new commands */
376 iBytes = 0;
377 if (xTraceStreamPortReadData(&xCommand, sizeof(TraceCommand_t), &iBytes) == TRC_FAIL)
378 {
379 /* The connection has failed, stop tracing */
380 xTraceDisable();
381
382 return TRC_FAIL;
383 }
384
385 if (iBytes == sizeof(TraceCommand_t))
386 {
387 if (prvIsValidCommand(&xCommand))
388 {
389 prvProcessCommand(&xCommand); /* Start or Stop currently... */
390 }
391 }
392
393 #if (TRC_USE_INTERNAL_BUFFER == 1)
394 xTraceInternalEventBufferTransfer(&iBytes);
395 #endif
396
397 /* If there was data sent or received (bytes != 0), loop around and repeat, if there is more data to send or receive.
398 Otherwise, step out of this loop and sleep for a while. */
399
400 } while (iBytes != 0);
401
402 if (xTraceIsRecorderEnabled())
403 {
404 xTraceDiagnosticsCheckStatus();
405 xTraceStackMonitorReport();
406 }
407
408 return TRC_SUCCESS;
409 }
410
vTraceSetFilterGroup(uint16_t filterGroup)411 void vTraceSetFilterGroup(uint16_t filterGroup)
412 {
413 (void)filterGroup;
414 }
415
vTraceSetFilterMask(uint16_t filterMask)416 void vTraceSetFilterMask(uint16_t filterMask)
417 {
418 (void)filterMask;
419 }
420
421 /******************************************************************************/
422 /*** INTERNAL FUNCTIONS *******************************************************/
423 /******************************************************************************/
424 /* Internal function for starting/stopping the recorder. */
prvSetRecorderEnabled(void)425 static void prvSetRecorderEnabled(void)
426 {
427 uint32_t timestampFrequency = 0;
428 uint32_t timestampPeriod = 0;
429
430 TRACE_ALLOC_CRITICAL_SECTION();
431
432 if (pxTraceRecorderData->uiRecorderEnabled == 1)
433 {
434 return;
435 }
436
437 xTraceTimestampGetFrequency(×tampFrequency);
438 /* If not overridden using xTraceTimestampSetFrequency(...), use default value */
439 if (timestampFrequency == 0)
440 {
441 xTraceTimestampSetFrequency((TraceUnsignedBaseType_t)(TRC_HWTC_FREQ_HZ));
442 }
443
444 xTraceTimestampGetPeriod(×tampPeriod);
445 /* If not overridden using xTraceTimestampSetPeriod(...), use default value */
446 if (timestampPeriod == 0)
447 {
448 xTraceTimestampSetPeriod((TraceUnsignedBaseType_t)(TRC_HWTC_PERIOD));
449 }
450
451 TRACE_ENTER_CRITICAL_SECTION();
452
453 /* If the internal event buffer is used, we must clear it */
454 xTraceInternalEventBufferClear();
455
456 xTraceStreamPortOnTraceBegin();
457
458 prvTraceStoreHeader();
459 prvTraceStoreTimestampInfo();
460 prvTraceStoreEntryTable();
461 prvTraceStoreStartEvent();
462
463 pxTraceRecorderData->uiSessionCounter++;
464
465 pxTraceRecorderData->uiRecorderEnabled = 1;
466
467 TRACE_EXIT_CRITICAL_SECTION();
468 }
469
prvSetRecorderDisabled(void)470 static void prvSetRecorderDisabled(void)
471 {
472 TRACE_ALLOC_CRITICAL_SECTION();
473
474 if (pxTraceRecorderData->uiRecorderEnabled == 0)
475 {
476 return;
477 }
478
479 TRACE_ENTER_CRITICAL_SECTION();
480
481 pxTraceRecorderData->uiRecorderEnabled = 0;
482
483 xTraceStreamPortOnTraceEnd();
484
485 TRACE_EXIT_CRITICAL_SECTION();
486 }
487
488 #if (TRC_EXTERNAL_BUFFERS == 0)
489 /* Stores the header information on Start */
prvTraceStoreHeader(void)490 static void prvTraceStoreHeader(void)
491 {
492 TraceEventHandle_t xEventHandle;
493
494 if (xTraceEventBeginRawOfflineBlocking(sizeof(TraceHeader_t), &xEventHandle) == TRC_SUCCESS)
495 {
496 xTraceEventAddData(xEventHandle, pxHeader, sizeof(TraceHeader_t));
497 xTraceEventEndOfflineBlocking(xEventHandle);
498 }
499 }
500
501 /* Store the Timestamp */
prvTraceStoreTimestampInfo(void)502 static void prvTraceStoreTimestampInfo(void)
503 {
504 TraceEventHandle_t xEventHandle;
505
506 if (xTraceEventBeginRawOfflineBlocking(sizeof(TraceTimestampBuffer_t), &xEventHandle) == TRC_SUCCESS)
507 {
508 xTraceEventAddData(xEventHandle, &pxTraceRecorderData->xTimestampBuffer, sizeof(TraceTimestampBuffer_t));
509 xTraceEventEndOfflineBlocking(xEventHandle);
510 }
511 }
512
513 /* Stores the entry table on Start */
prvTraceStoreEntryTable(void)514 static void prvTraceStoreEntryTable(void)
515 {
516 uint32_t i = 0;
517 TraceEventHandle_t xEventHandle;
518 TraceEntryHandle_t xEntryHandle;
519 uint32_t uiEntryCount;
520 void *pvEntryAddress;
521
522 xTraceEntryGetCount(&uiEntryCount);
523
524 if (xTraceEventBeginRawOfflineBlocking(sizeof(uint32_t) + sizeof(uint32_t) + sizeof(uint32_t), &xEventHandle) == TRC_SUCCESS)
525 {
526 xTraceEventAdd32(xEventHandle, uiEntryCount);
527 xTraceEventAdd32(xEventHandle, TRC_ENTRY_TABLE_SLOT_SYMBOL_SIZE);
528 xTraceEventAdd32(xEventHandle, TRC_ENTRY_TABLE_STATE_COUNT);
529 xTraceEventEndOfflineBlocking(xEventHandle);
530 }
531
532 for (i = 0; i < (TRC_ENTRY_TABLE_SLOTS); i++)
533 {
534 xTraceEntryGetAtIndex(i, &xEntryHandle);
535 xTraceEntryGetAddress(xEntryHandle, &pvEntryAddress);
536 /* We only send used entry slots */
537 if (pvEntryAddress != 0)
538 {
539 /* Send entry */
540 if (xTraceEventBeginRawOfflineBlocking(sizeof(TraceEntry_t), &xEventHandle) == TRC_SUCCESS)
541 {
542 xTraceEventAddData(xEventHandle, (void*)xEntryHandle, sizeof(TraceEntry_t));
543 xTraceEventEndOfflineBlocking(xEventHandle);
544 }
545 }
546 }
547 }
548 #endif /* (TRC_EXTERNAL_BUFFERS == 0) */
549
prvTraceStoreStartEvent()550 static void prvTraceStoreStartEvent()
551 {
552 TraceEventHandle_t xEventHandle;
553 void* pvCurrentTask;
554
555 xTraceTaskGetCurrent(&pvCurrentTask);
556
557 if (xTraceEventBeginOffline(PSF_EVENT_TRACE_START, sizeof(uint32_t), &xEventHandle) == TRC_SUCCESS)
558 {
559 xTraceEventAdd32(xEventHandle, (uint32_t)pvCurrentTask);
560 xTraceEventEndOffline(xEventHandle);
561 }
562 }
563
564 /* Checks if the provided command is a valid command */
prvIsValidCommand(TraceCommand_t * cmd)565 static int prvIsValidCommand(TraceCommand_t* cmd)
566 {
567 uint16_t checksum = (uint16_t)(0xFFFF - ( cmd->cmdCode +
568 cmd->param1 +
569 cmd->param2 +
570 cmd->param3 +
571 cmd->param4 +
572 cmd->param5));
573
574 if (cmd->checksumMSB != (unsigned char)(checksum >> 8))
575 return 0;
576
577 if (cmd->checksumLSB != (unsigned char)(checksum & 0xFF))
578 return 0;
579
580 if (cmd->cmdCode > CMD_LAST_COMMAND)
581 return 0;
582
583 return 1;
584 }
585
586 /* Executed the received command (Start or Stop) */
prvProcessCommand(TraceCommand_t * cmd)587 static void prvProcessCommand(TraceCommand_t* cmd)
588 {
589 switch(cmd->cmdCode)
590 {
591 case CMD_SET_ACTIVE:
592 if (cmd->param1 == 1)
593 {
594 prvSetRecorderEnabled();
595 }
596 else
597 {
598 prvSetRecorderDisabled();
599 }
600 break;
601 default:
602 break;
603 }
604 }
605
606 #endif /* (TRC_USE_TRACEALYZER_RECORDER == 1) */
607
608 #endif /*(TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING)*/
609