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