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