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