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(&timestampFrequency);
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(&timestampPeriod);
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