1 /***************************************************************************
2 * Copyright (c) 2024 Microsoft Corporation
3 *
4 * This program and the accompanying materials are made available under the
5 * terms of the MIT License which is available at
6 * https://opensource.org/licenses/MIT.
7 *
8 * SPDX-License-Identifier: MIT
9 **************************************************************************/
10
11
12 /**************************************************************************/
13 /**************************************************************************/
14 /** */
15 /** ThreadX Component */
16 /** */
17 /** Trace */
18 /** */
19 /**************************************************************************/
20 /**************************************************************************/
21
22 #define TX_SOURCE_CODE
23
24
25 /* Include necessary system files. */
26
27 #include "tx_api.h"
28 #ifdef TX_ENABLE_EVENT_TRACE
29 #include "tx_thread.h"
30 #include "tx_timer.h"
31 #include "tx_event_flags.h"
32 #include "tx_queue.h"
33 #include "tx_semaphore.h"
34 #include "tx_mutex.h"
35 #include "tx_block_pool.h"
36 #include "tx_byte_pool.h"
37 #endif
38 #include "tx_trace.h"
39
40
41 /**************************************************************************/
42 /* */
43 /* FUNCTION RELEASE */
44 /* */
45 /* _tx_trace_enable PORTABLE C */
46 /* 6.1 */
47 /* AUTHOR */
48 /* */
49 /* William E. Lamie, Microsoft Corporation */
50 /* */
51 /* DESCRIPTION */
52 /* */
53 /* This function initializes the ThreadX trace buffer and the */
54 /* associated control variables, enabling it for operation. */
55 /* */
56 /* INPUT */
57 /* */
58 /* trace_buffer_start Start of trace buffer */
59 /* trace_buffer_size Size (bytes) of trace buffer */
60 /* registry_entries Number of object registry */
61 /* entries. */
62 /* */
63 /* OUTPUT */
64 /* */
65 /* Completion Status */
66 /* */
67 /* CALLS */
68 /* */
69 /* _tx_thread_system_preempt_check Check for preemption */
70 /* _tx_trace_object_register Register existing objects */
71 /* */
72 /* CALLED BY */
73 /* */
74 /* Application Code */
75 /* */
76 /* RELEASE HISTORY */
77 /* */
78 /* DATE NAME DESCRIPTION */
79 /* */
80 /* 05-19-2020 William E. Lamie Initial Version 6.0 */
81 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
82 /* resulting in version 6.1 */
83 /* */
84 /**************************************************************************/
_tx_trace_enable(VOID * trace_buffer_start,ULONG trace_buffer_size,ULONG registry_entries)85 UINT _tx_trace_enable(VOID *trace_buffer_start, ULONG trace_buffer_size, ULONG registry_entries)
86 {
87
88 #ifdef TX_ENABLE_EVENT_TRACE
89
90 TX_INTERRUPT_SAVE_AREA
91
92 TX_THREAD *thread_ptr;
93 TX_TIMER *timer_ptr;
94 TX_EVENT_FLAGS_GROUP *event_flags_ptr;
95 TX_QUEUE *queue_ptr;
96 TX_SEMAPHORE *semaphore_ptr;
97 TX_MUTEX *mutex_ptr;
98 TX_BLOCK_POOL *block_pool_ptr;
99 TX_BYTE_POOL *byte_pool_ptr;
100 UCHAR *work_ptr;
101 UCHAR *event_start_ptr;
102 TX_TRACE_OBJECT_ENTRY *entry_ptr;
103 TX_TRACE_BUFFER_ENTRY *event_ptr;
104 ULONG i;
105 UINT status;
106
107
108 /* First, see if there is enough room for the control header, the registry entries, and at least one event in
109 memory supplied to this call. */
110 if (trace_buffer_size < ((sizeof(TX_TRACE_HEADER)) + ((sizeof(TX_TRACE_OBJECT_ENTRY)) * registry_entries) + (sizeof(TX_TRACE_BUFFER_ENTRY))))
111 {
112
113 /* No, the memory isn't big enough to hold one trace buffer entry. Return an error. */
114 status = TX_SIZE_ERROR;
115 }
116
117 /* Determine if trace is already enabled. */
118 else if (_tx_trace_buffer_current_ptr != TX_NULL)
119 {
120
121 /* Yes, trace is already enabled. */
122 status = TX_NOT_DONE;
123 }
124 else
125 {
126
127 /* Set the enable bits for all events enabled. */
128 _tx_trace_event_enable_bits = 0xFFFFFFFFUL;
129
130 /* Setup working pointer to the supplied memory. */
131 work_ptr = TX_VOID_TO_UCHAR_POINTER_CONVERT(trace_buffer_start);
132
133 /* Setup pointer to the trace control area. */
134 _tx_trace_header_ptr = TX_UCHAR_TO_HEADER_POINTER_CONVERT(work_ptr);
135
136 /* Move the working pointer past the control area. */
137 work_ptr = TX_UCHAR_POINTER_ADD(work_ptr, (sizeof(TX_TRACE_HEADER)));
138
139 /* Save the start of the trace object registry. */
140 _tx_trace_registry_start_ptr = TX_UCHAR_TO_OBJECT_POINTER_CONVERT(work_ptr);
141
142 /* Setup the end of the trace object registry. */
143 work_ptr = TX_UCHAR_POINTER_ADD(work_ptr, (sizeof(TX_TRACE_OBJECT_ENTRY))*registry_entries);
144 _tx_trace_registry_end_ptr = TX_UCHAR_TO_OBJECT_POINTER_CONVERT(work_ptr);
145
146 /* Loop to make all trace object registry entries empty and valid. */
147 for (i = ((ULONG) 0); i < registry_entries; i++)
148 {
149
150 /* Setup the work pointer. */
151 work_ptr = TX_OBJECT_TO_UCHAR_POINTER_CONVERT(_tx_trace_registry_start_ptr);
152 work_ptr = TX_UCHAR_POINTER_ADD(work_ptr, (sizeof(TX_TRACE_OBJECT_ENTRY))*i);
153
154 /* Convert to a registry entry pointer. */
155 entry_ptr = TX_UCHAR_TO_OBJECT_POINTER_CONVERT(work_ptr);
156
157 /* Initialize object registry entry. */
158 entry_ptr -> tx_trace_object_entry_available = (UCHAR) TX_TRUE;
159 entry_ptr -> tx_trace_object_entry_type = (UCHAR) TX_TRACE_OBJECT_TYPE_NOT_VALID;
160 entry_ptr -> tx_trace_object_entry_reserved1 = (UCHAR) 0;
161 entry_ptr -> tx_trace_object_entry_reserved2 = (UCHAR) 0;
162 entry_ptr -> tx_trace_object_entry_thread_pointer = (ULONG) 0;
163 }
164
165 /* Setup the total number of registry entries. */
166 _tx_trace_total_registry_entries = registry_entries;
167
168 /* Setup the object registry available count to the total number of registry entries. */
169 _tx_trace_available_registry_entries = registry_entries;
170
171 /* Setup the search starting index to the first entry. */
172 _tx_trace_registry_search_start = ((ULONG) 0);
173
174 /* Setup the work pointer to after the trace object registry. */
175 work_ptr = TX_OBJECT_TO_UCHAR_POINTER_CONVERT(_tx_trace_registry_end_ptr);
176
177 /* Adjust the remaining trace buffer size. */
178 trace_buffer_size = trace_buffer_size - ((sizeof(TX_TRACE_OBJECT_ENTRY)) * registry_entries) - (sizeof(TX_TRACE_HEADER));
179
180 /* Setup pointer to the start of the actual event trace log. */
181 _tx_trace_buffer_start_ptr = TX_UCHAR_TO_ENTRY_POINTER_CONVERT(work_ptr);
182
183 /* Save the event trace log start address. */
184 event_start_ptr = work_ptr;
185
186 /* Calculate the end of the trace buffer. */
187 work_ptr = TX_UCHAR_POINTER_ADD(work_ptr, ((trace_buffer_size/(sizeof(TX_TRACE_BUFFER_ENTRY)))*(sizeof(TX_TRACE_BUFFER_ENTRY))));
188 _tx_trace_buffer_end_ptr = TX_UCHAR_TO_ENTRY_POINTER_CONVERT(work_ptr);
189
190 /* Loop to mark all entries in the trace buffer as invalid. */
191 for (i = ((ULONG) 0); i < (trace_buffer_size/(sizeof(TX_TRACE_BUFFER_ENTRY))); i++)
192 {
193
194 /* Setup the work pointer. */
195 work_ptr = TX_UCHAR_POINTER_ADD(event_start_ptr, (sizeof(TX_TRACE_BUFFER_ENTRY))*i);
196
197 /* Convert to a trace event pointer. */
198 event_ptr = TX_UCHAR_TO_ENTRY_POINTER_CONVERT(work_ptr);
199
200 /* Mark this trace event as invalid. */
201 event_ptr -> tx_trace_buffer_entry_thread_pointer = ((ULONG) 0);
202 }
203
204 /* Now, fill in the event trace control header. */
205 _tx_trace_header_ptr -> tx_trace_header_id = TX_TRACE_VALID;
206 _tx_trace_header_ptr -> tx_trace_header_timer_valid_mask = TX_TRACE_TIME_MASK;
207 _tx_trace_header_ptr -> tx_trace_header_trace_base_address = TX_POINTER_TO_ULONG_CONVERT(trace_buffer_start);
208 _tx_trace_header_ptr -> tx_trace_header_registry_start_pointer = TX_POINTER_TO_ULONG_CONVERT(_tx_trace_registry_start_ptr);
209 _tx_trace_header_ptr -> tx_trace_header_reserved1 = ((USHORT) 0);
210 _tx_trace_header_ptr -> tx_trace_header_object_name_size = ((USHORT) TX_TRACE_OBJECT_REGISTRY_NAME);
211 _tx_trace_header_ptr -> tx_trace_header_registry_end_pointer = TX_POINTER_TO_ULONG_CONVERT(_tx_trace_registry_end_ptr);
212 _tx_trace_header_ptr -> tx_trace_header_buffer_start_pointer = TX_POINTER_TO_ULONG_CONVERT(_tx_trace_buffer_start_ptr);
213 _tx_trace_header_ptr -> tx_trace_header_buffer_end_pointer = TX_POINTER_TO_ULONG_CONVERT(_tx_trace_buffer_end_ptr);
214 _tx_trace_header_ptr -> tx_trace_header_buffer_current_pointer = TX_POINTER_TO_ULONG_CONVERT(_tx_trace_buffer_start_ptr);
215 _tx_trace_header_ptr -> tx_trace_header_reserved2 = 0xAAAAAAAAUL;
216 _tx_trace_header_ptr -> tx_trace_header_reserved3 = 0xBBBBBBBBUL;
217 _tx_trace_header_ptr -> tx_trace_header_reserved4 = 0xCCCCCCCCUL;
218
219 /* Now, loop through all existing ThreadX objects and register them in the newly setup trace buffer. */
220
221 /* Disable interrupts. */
222 TX_DISABLE
223
224 /* First, disable preemption. */
225 _tx_thread_preempt_disable++;
226
227 /* Restore interrupts. */
228 TX_RESTORE
229
230 /* Pickup the first thread and the number of created threads. */
231 thread_ptr = _tx_thread_created_ptr;
232 i = _tx_thread_created_count;
233
234 /* Loop to register all threads. */
235 while (i != ((ULONG) 0))
236 {
237
238 /* Decrement the counter. */
239 i--;
240
241 /* Register this thread. */
242 _tx_trace_object_register(TX_TRACE_OBJECT_TYPE_THREAD, thread_ptr, thread_ptr -> tx_thread_name,
243 TX_POINTER_TO_ULONG_CONVERT(thread_ptr -> tx_thread_stack_start), (ULONG) thread_ptr -> tx_thread_stack_size);
244
245 /* Move to the next thread. */
246 thread_ptr = thread_ptr -> tx_thread_created_next;
247 }
248
249 /* Pickup the first timer and the number of created timers. */
250 timer_ptr = _tx_timer_created_ptr;
251 i = _tx_timer_created_count;
252
253 /* Loop to register all timers. */
254 while (i != ((ULONG) 0))
255 {
256
257 /* Decrement the counter. */
258 i--;
259
260 /* Register this timer. */
261 _tx_trace_object_register(TX_TRACE_OBJECT_TYPE_TIMER, timer_ptr, timer_ptr -> tx_timer_name,
262 ((ULONG) 0), timer_ptr -> tx_timer_internal.tx_timer_internal_re_initialize_ticks);
263
264 /* Move to the next timer. */
265 timer_ptr = timer_ptr -> tx_timer_created_next;
266 }
267
268
269 /* Pickup the first event flag group and the number of created groups. */
270 event_flags_ptr = _tx_event_flags_created_ptr;
271 i = _tx_event_flags_created_count;
272
273 /* Loop to register all event flags groups. */
274 while (i != ((ULONG) 0))
275 {
276
277 /* Decrement the counter. */
278 i--;
279
280 /* Register this event flags group. */
281 _tx_trace_object_register(TX_TRACE_OBJECT_TYPE_EVENT_FLAGS, event_flags_ptr, event_flags_ptr -> tx_event_flags_group_name, ((ULONG) 0), ((ULONG) 0));
282
283 /* Move to the next event flags group. */
284 event_flags_ptr = event_flags_ptr -> tx_event_flags_group_created_next;
285 }
286
287 /* Pickup the first queue and the number of created queues. */
288 queue_ptr = _tx_queue_created_ptr;
289 i = _tx_queue_created_count;
290
291 /* Loop to register all queues. */
292 while (i != ((ULONG) 0))
293 {
294
295 /* Decrement the counter. */
296 i--;
297
298 /* Register this queue. */
299 _tx_trace_object_register(TX_TRACE_OBJECT_TYPE_QUEUE, queue_ptr, queue_ptr -> tx_queue_name,
300 (queue_ptr -> tx_queue_capacity * (sizeof(ULONG))), ((ULONG) 0));
301
302 /* Move to the next queue. */
303 queue_ptr = queue_ptr -> tx_queue_created_next;
304 }
305
306 /* Pickup the first semaphore and the number of created semaphores. */
307 semaphore_ptr = _tx_semaphore_created_ptr;
308 i = _tx_semaphore_created_count;
309
310 /* Loop to register all semaphores. */
311 while (i != ((ULONG) 0))
312 {
313
314 /* Decrement the counter. */
315 i--;
316
317 /* Register this semaphore. */
318 _tx_trace_object_register(TX_TRACE_OBJECT_TYPE_SEMAPHORE, semaphore_ptr, semaphore_ptr -> tx_semaphore_name, ((ULONG) 0), ((ULONG) 0));
319
320 /* Move to the next semaphore. */
321 semaphore_ptr = semaphore_ptr -> tx_semaphore_created_next;
322 }
323
324 /* Pickup the first mutex and the number of created mutexes. */
325 mutex_ptr = _tx_mutex_created_ptr;
326 i = _tx_mutex_created_count;
327
328 /* Loop to register all mutexes. */
329 while (i != ((ULONG) 0))
330 {
331
332 /* Decrement the counter. */
333 i--;
334
335 /* Register this mutex. */
336 _tx_trace_object_register(TX_TRACE_OBJECT_TYPE_MUTEX, mutex_ptr, mutex_ptr -> tx_mutex_name,
337 (ULONG) mutex_ptr -> tx_mutex_inherit, ((ULONG) 0));
338
339 /* Move to the next mutex. */
340 mutex_ptr = mutex_ptr -> tx_mutex_created_next;
341 }
342
343 /* Pickup the first block pool and the number of created block pools. */
344 block_pool_ptr = _tx_block_pool_created_ptr;
345 i = _tx_block_pool_created_count;
346
347 /* Loop to register all block pools. */
348 while (i != ((ULONG) 0))
349 {
350
351 /* Decrement the counter. */
352 i--;
353
354 /* Register this block pool. */
355 _tx_trace_object_register(TX_TRACE_OBJECT_TYPE_BLOCK_POOL, block_pool_ptr, block_pool_ptr -> tx_block_pool_name,
356 block_pool_ptr -> tx_block_pool_size, ((ULONG) 0));
357
358 /* Move to the next block pool. */
359 block_pool_ptr = block_pool_ptr -> tx_block_pool_created_next;
360 }
361
362 /* Pickup the first byte pool and the number of created byte pools. */
363 byte_pool_ptr = _tx_byte_pool_created_ptr;
364 i = _tx_byte_pool_created_count;
365
366 /* Loop to register all byte pools. */
367 while (i != ((ULONG) 0))
368 {
369
370 /* Decrement the counter. */
371 i--;
372
373 /* Register this byte pool. */
374 _tx_trace_object_register(TX_TRACE_OBJECT_TYPE_BYTE_POOL, byte_pool_ptr, byte_pool_ptr -> tx_byte_pool_name,
375 byte_pool_ptr -> tx_byte_pool_size, ((ULONG) 0));
376
377 /* Move to the next byte pool. */
378 byte_pool_ptr = byte_pool_ptr -> tx_byte_pool_created_next;
379 }
380
381 /* Disable interrupts. */
382 TX_DISABLE
383
384 /* Release the preeemption. */
385 _tx_thread_preempt_disable--;
386
387 /* Finally, setup the current buffer pointer, which effectively enables the trace! */
388 _tx_trace_buffer_current_ptr = (TX_TRACE_BUFFER_ENTRY *) _tx_trace_buffer_start_ptr;
389
390 /* Insert two RUNNING events so the buffer is not empty. */
391 TX_TRACE_IN_LINE_INSERT(TX_TRACE_RUNNING, 0, 0, 0, 0, TX_TRACE_INTERNAL_EVENTS)
392 TX_TRACE_IN_LINE_INSERT(TX_TRACE_RUNNING, 0, 0, 0, 0, TX_TRACE_INTERNAL_EVENTS)
393
394 /* Restore interrupts. */
395 TX_RESTORE
396
397 /* Check for preemption. */
398 _tx_thread_system_preempt_check();
399
400 /* Return successful completion. */
401 status = TX_SUCCESS;
402 }
403
404 /* Return completion status. */
405 return(status);
406 #else
407
408 UINT status;
409
410
411 /* Access input arguments just for the sake of lint, MISRA, etc. */
412 if (trace_buffer_start != TX_NULL)
413 {
414
415 /* Trace not enabled, return an error. */
416 status = TX_FEATURE_NOT_ENABLED;
417 }
418 else if (trace_buffer_size == ((ULONG) 0))
419 {
420
421 /* Trace not enabled, return an error. */
422 status = TX_FEATURE_NOT_ENABLED;
423 }
424 else if (registry_entries == ((ULONG) 0))
425 {
426
427 /* Trace not enabled, return an error. */
428 status = TX_FEATURE_NOT_ENABLED;
429 }
430 else
431 {
432
433 /* Trace not enabled, return an error. */
434 status = TX_FEATURE_NOT_ENABLED;
435 }
436
437 /* Return completion status. */
438 return(status);
439 #endif
440 }
441
442
443
444