]> git.sur5r.net Git - freertos/blob - FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/trcKernel.c
Update to latest FreeRTOS+Trace recorder code.
[freertos] / FreeRTOS-Plus / Source / FreeRTOS-Plus-Trace / trcKernel.c
1 /*******************************************************************************\r
2  * Tracealyzer v2.4.1 Recorder Library\r
3  * Percepio AB, www.percepio.com\r
4  *\r
5  * trcKernel.c\r
6  *\r
7  * Functions used by trcKernelHooks.h.\r
8  *\r
9  * Terms of Use\r
10  * This software is copyright Percepio AB. The recorder library is free for\r
11  * use together with Percepio products. You may distribute the recorder library\r
12  * in its original form, including modifications in trcHardwarePort.c/.h\r
13  * given that these modification are clearly marked as your own modifications\r
14  * and documented in the initial comment section of these source files.\r
15  * This software is the intellectual property of Percepio AB and may not be\r
16  * sold or in other ways commercially redistributed without explicit written\r
17  * permission by Percepio AB.\r
18  *\r
19  * Disclaimer\r
20  * The trace tool and recorder library is being delivered to you AS IS and\r
21  * Percepio AB makes no warranty as to its use or performance. Percepio AB does\r
22  * not and cannot warrant the performance or results you may obtain by using the\r
23  * software or documentation. Percepio AB make no warranties, express or\r
24  * implied, as to noninfringement of third party rights, merchantability, or\r
25  * fitness for any particular purpose. In no event will Percepio AB, its\r
26  * technology partners, or distributors be liable to you for any consequential,\r
27  * incidental or special damages, including any lost profits or lost savings,\r
28  * even if a representative of Percepio AB has been advised of the possibility\r
29  * of such damages, or for any claim by any third party. Some jurisdictions do\r
30  * not allow the exclusion or limitation of incidental, consequential or special\r
31  * damages, or the exclusion of implied warranties or limitations on how long an\r
32  * implied warranty may last, so the above limitations may not apply to you.\r
33  *\r
34  * Copyright Percepio AB, 2013.\r
35  * www.percepio.com\r
36  ******************************************************************************/\r
37 \r
38 #include "trcKernel.h"\r
39 \r
40 #if (USE_TRACEALYZER_RECORDER == 1)\r
41 \r
42 #include <stdint.h>\r
43 \r
44 /* Internal variables */\r
45 uint8_t nISRactive = 0;\r
46 objectHandleType handle_of_last_logged_task = 0;\r
47 uint8_t inExcludedTask = 0;\r
48 \r
49 static uint32_t prvTraceGetParam(uint32_t, uint32_t);\r
50 \r
51 #if !defined INCLUDE_READY_EVENTS || INCLUDE_READY_EVENTS == 1\r
52 /*******************************************************************************\r
53  * vTraceStoreTaskReady\r
54  *\r
55  * This function stores a ready state for the task handle sent in as parameter.\r
56  ******************************************************************************/\r
57 void vTraceStoreTaskReady(objectHandleType handle)\r
58 {\r
59     uint16_t dts3;\r
60     TREvent* tr;\r
61         \r
62         TRACE_ASSERT(handle > 0 && handle <= NTask, "vTraceStoreTaskReady: Invalid value for handle", );\r
63 \r
64     if (recorder_busy)\r
65     {\r
66       /***********************************************************************\r
67       * This should never occur, as the tick- and kernel call ISR is on lowest\r
68       * interrupt priority and always are disabled during the critical sections\r
69       * of the recorder.\r
70       ***********************************************************************/\r
71 \r
72       vTraceError("Recorder busy - high priority ISR using syscall? (1)");\r
73       return;\r
74     }\r
75 \r
76     if (RecorderDataPtr->recorderActive) /* Need to repeat this check! */\r
77         {\r
78                 if (!TRACE_GET_TASK_FLAG_ISEXCLUDED(handle))\r
79                 {\r
80                         dts3 = (uint16_t)prvTraceGetDTS(0xFFFF);\r
81                         if (RecorderDataPtr->recorderActive) /* Need to repeat this check! */\r
82                         {\r
83                                 tr = (TREvent*)xTraceNextFreeEventBufferSlot();\r
84 \r
85                                 if (tr != NULL)\r
86                                 {\r
87                                         tr->type = DIV_TASK_READY;\r
88                                         tr->dts = dts3;\r
89                                         tr->objHandle = handle;\r
90 \r
91                                         prvTraceUpdateCounters();\r
92                                 }\r
93                         }\r
94                 }\r
95         }\r
96 }\r
97 #endif\r
98 \r
99 /*******************************************************************************\r
100  * vTraceStoreKernelCall\r
101  *\r
102  * This is the main integration point for storing kernel calls, and\r
103  * is called by the hooks in trcKernelHooks.h (see trcKernelPort.h for event codes).\r
104  ******************************************************************************/\r
105 void vTraceStoreKernelCall(uint32_t ecode, traceObjectClass objectClass, uint32_t objectNumber)\r
106 {\r
107     KernelCall * kse;\r
108     uint16_t dts1;\r
109         \r
110     TRACE_ASSERT(ecode < 0xFF, "vTraceStoreKernelCall: ecode >= 0xFF", );\r
111     TRACE_ASSERT(objectClass < TRACE_NCLASSES, "vTraceStoreKernelCall: objectClass >= TRACE_NCLASSES", );\r
112     TRACE_ASSERT(objectNumber <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectClass], "vTraceStoreKernelCall: Invalid value for objectNumber", );\r
113 \r
114     if (recorder_busy)\r
115     {\r
116         /*************************************************************************\r
117         * This may occur if a high-priority ISR is illegally using a system call,\r
118         * or creates a user event.\r
119         * Only ISRs that are disabled by TRACE_ENTER_CRITICAL_SECTION may use system calls\r
120         * or user events (see TRACE_MAX_SYSCALL_INTERRUPT_PRIORITY).\r
121         *************************************************************************/\r
122 \r
123         vTraceError("Recorder busy - high priority ISR using syscall? (2)");\r
124         return;\r
125     }\r
126 \r
127     if (handle_of_last_logged_task == 0)\r
128     {\r
129         return;\r
130     }\r
131 \r
132     if (RecorderDataPtr->recorderActive)\r
133     {\r
134 \r
135         /* If it is an ISR or NOT an excluded task, this kernel call will be stored in the trace */\r
136         if (nISRactive || !inExcludedTask)\r
137         {\r
138             /* Check if the referenced object or the event code is excluded */\r
139             if (!uiTraceIsObjectExcluded(objectClass, objectNumber) && !TRACE_GET_EVENT_CODE_FLAG_ISEXCLUDED(ecode))\r
140             {\r
141                 trcCRITICAL_SECTION_BEGIN();\r
142                 dts1 = (uint16_t)prvTraceGetDTS(0xFFFF);\r
143 \r
144                 if (RecorderDataPtr->recorderActive) /* Need to repeat this check! */\r
145                 {\r
146                     kse = (KernelCall*) xTraceNextFreeEventBufferSlot();\r
147                     if (kse != NULL)\r
148                     {\r
149                         kse->dts = dts1;\r
150                         kse->type = (uint8_t)ecode;\r
151                         kse->objHandle = (uint8_t)objectNumber;\r
152                         prvTraceUpdateCounters();\r
153                     }\r
154                 }\r
155                 trcCRITICAL_SECTION_END();\r
156             }\r
157         }\r
158     }\r
159 }\r
160 \r
161 /*******************************************************************************\r
162  * vTraceStoreKernelCallWithParam\r
163  *\r
164  * Used for storing kernel calls with a handle and a numeric parameter. This is\r
165  * only used for traceTASK_PRIORITY_SET at the moment.\r
166  ******************************************************************************/\r
167 void vTraceStoreKernelCallWithParam(uint32_t evtcode,\r
168                                     traceObjectClass objectClass,\r
169                                     uint32_t objectNumber,\r
170                                     uint8_t param)\r
171 {\r
172     KernelCallWithParamAndHandle * kse;\r
173     uint8_t dts2;\r
174 \r
175         TRACE_ASSERT(evtcode < 0xFF, "vTraceStoreKernelCall: evtcode >= 0xFF", );\r
176         TRACE_ASSERT(objectClass < TRACE_NCLASSES, "vTraceStoreKernelCallWithParam: objectClass >= TRACE_NCLASSES", );\r
177         TRACE_ASSERT(objectNumber <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectClass], "vTraceStoreKernelCallWithParam: Invalid value for objectNumber", );\r
178 \r
179     if (RecorderDataPtr->recorderActive && handle_of_last_logged_task &&\r
180         (! inExcludedTask || nISRactive))\r
181     {\r
182         if (recorder_busy)\r
183         {\r
184             /*************************************************************************\r
185             * This may occur if a high-priority ISR is illegally using a system call,\r
186             * or creates a user event.\r
187             * Only ISRs that are disabled by TRACE_ENTER_CRITICAL_SECTION may use system calls\r
188                 * or user events (see TRACE_MAX_SYSCALL_INTERRUPT_PRIORITY).\r
189             *************************************************************************/\r
190 \r
191             vTraceError("Recorder busy - high priority ISR using syscall? (3)");\r
192             return;\r
193         }\r
194 \r
195         /* Check if the referenced object or the event code is excluded */\r
196         if (!uiTraceIsObjectExcluded(objectClass, objectNumber) && !TRACE_GET_EVENT_CODE_FLAG_ISEXCLUDED(evtcode))\r
197         {\r
198             trcCRITICAL_SECTION_BEGIN();\r
199             dts2 = (uint8_t)prvTraceGetDTS(0xFF);\r
200 \r
201             if (RecorderDataPtr->recorderActive) /* Need to repeat this check! */\r
202             {\r
203                 kse = (KernelCallWithParamAndHandle*) xTraceNextFreeEventBufferSlot();\r
204                 if (kse != NULL)\r
205                 {\r
206                     kse->dts = dts2;\r
207                     kse->type = (uint8_t)evtcode;\r
208                     kse->objHandle = (uint8_t)objectNumber;\r
209                     kse->param = param;\r
210                     prvTraceUpdateCounters();\r
211                 }\r
212             }\r
213             trcCRITICAL_SECTION_END();\r
214         }\r
215     }\r
216 }\r
217 \r
218 /*******************************************************************************\r
219  * prvTraceGetParam\r
220  *\r
221  * Used for storing extra bytes for kernel calls with numeric parameters.\r
222  ******************************************************************************/\r
223 static uint32_t prvTraceGetParam(uint32_t param_max, uint32_t param)\r
224 {\r
225         XPSEvent* xps;\r
226         \r
227         TRACE_ASSERT(param_max == 0xFF || param_max == 0xFFFF, "prvTraceGetParam: Invalid value for param_max", param);\r
228         \r
229         if (param <= param_max)\r
230         {\r
231                 return param;\r
232         }\r
233         else\r
234         {\r
235                 xps = (XPSEvent*) xTraceNextFreeEventBufferSlot();\r
236                 if (xps != NULL)\r
237                 {\r
238                         xps->type = DIV_XPS;\r
239                         xps->xps_8 = (param & (0xFF00 & ~param_max)) >> 8;\r
240                         xps->xps_16 = (param & (0xFFFF0000 & ~param_max)) >> 16;\r
241                         prvTraceUpdateCounters();\r
242                 }\r
243 \r
244                 return param & param_max;\r
245         }\r
246 }\r
247 \r
248 /*******************************************************************************\r
249  * vTraceStoreKernelCallWithNumericParamOnly\r
250  *\r
251  * Used for storing kernel calls with numeric parameters only. This is\r
252  * only used for traceTASK_DELAY and traceDELAY_UNTIL at the moment.\r
253  ******************************************************************************/\r
254 void vTraceStoreKernelCallWithNumericParamOnly(uint32_t evtcode, uint32_t param)\r
255 {\r
256     KernelCallWithParam16 * kse;\r
257     uint8_t dts6;\r
258         uint16_t restParam = 0;\r
259 \r
260         TRACE_ASSERT(evtcode < 0xFF, "vTraceStoreKernelCallWithNumericParamOnly: Invalid value for evtcode", );\r
261         \r
262     if (RecorderDataPtr->recorderActive && handle_of_last_logged_task\r
263         && (! inExcludedTask || nISRactive))\r
264     {\r
265         /* Check if the event code is excluded */\r
266         if (!TRACE_GET_EVENT_CODE_FLAG_ISEXCLUDED(evtcode))\r
267         {\r
268             if (recorder_busy)\r
269             {\r
270                 /*************************************************************************\r
271                 * This may occur if a high-priority ISR is illegally using a system call,\r
272                 * or creates a user event.\r
273                 * Only ISRs that are disabled by TRACE_ENTER_CRITICAL_SECTION may use system calls\r
274                 * or user events (see TRACE_MAX_SYSCALL_INTERRUPT_PRIORITY).\r
275                 *************************************************************************/\r
276 \r
277                 vTraceError("Recorder busy - high priority ISR using syscall? (4)");\r
278                 return;\r
279             }\r
280 \r
281             trcCRITICAL_SECTION_BEGIN();\r
282             dts6 = (uint8_t)prvTraceGetDTS(0xFF);\r
283 \r
284             if (RecorderDataPtr->recorderActive) /* Need to repeat this check! */\r
285             {\r
286                                 restParam = (uint16_t)prvTraceGetParam(0xFFFF, param);\r
287 \r
288                                 if (RecorderDataPtr->recorderActive) /* Need to repeat this check! */\r
289                                 {\r
290                                         kse = (KernelCallWithParam16*) xTraceNextFreeEventBufferSlot();\r
291                                         if (kse != NULL)\r
292                                         {\r
293                                                 kse->dts = dts6;\r
294                                                 kse->type = (uint8_t)evtcode;\r
295                                                 kse->param = restParam;\r
296                                                 prvTraceUpdateCounters();\r
297                                         }\r
298                                 }\r
299             }\r
300             trcCRITICAL_SECTION_END();\r
301         }\r
302     }\r
303 }\r
304 \r
305 /*******************************************************************************\r
306  * vTraceStoreTaskswitch\r
307  * Called by the scheduler from the SWITCHED_OUT hook, and by uiTraceStart.\r
308  * At this point interrupts are assumed to be disabled!\r
309  ******************************************************************************/\r
310 void vTraceStoreTaskswitch(objectHandleType task_handle)\r
311 {\r
312     uint16_t dts3;\r
313     TSEvent* ts;\r
314     int8_t skipEvent = 0;\r
315 \r
316         TRACE_ASSERT(task_handle <= NTask, "vTraceStoreTaskswitch: Invalid value for task_handle", );\r
317         \r
318     /***************************************************************************\r
319     This is used to detect if a high-priority ISRs is illegally using the\r
320     recorder ISR trace functions (vTraceStoreISRBegin and ...End) while the\r
321     recorder is busy with a task-level event or lower priority ISR event.\r
322 \r
323     If this is detected, it triggers a call to vTraceError with the error\r
324     "Illegal call to vTraceStoreISRBegin/End". If you get this error, it means\r
325     that the macro trcCRITICAL_SECTION_BEGIN does not disable this ISR, as required.\r
326 \r
327     Note: Setting recorder_busy is normally handled in our macros\r
328     trcCRITICAL_SECTION_BEGIN and _END, but is needed explicitly in this\r
329     function since critical sections should not be used in the context switch\r
330     event...)\r
331     ***************************************************************************/\r
332     recorder_busy++;\r
333 \r
334     /* Skip the event if the task has been excluded, using vTraceExcludeTask */\r
335     if (TRACE_GET_TASK_FLAG_ISEXCLUDED(task_handle))\r
336     {\r
337         skipEvent = 1;\r
338         inExcludedTask = 1;\r
339     }\r
340     else\r
341         {\r
342         inExcludedTask = 0;\r
343         }\r
344 \r
345         /* Skip the event if the same task is scheduled */\r
346         if (task_handle == handle_of_last_logged_task)\r
347         {\r
348                 skipEvent = 1;\r
349         }\r
350 \r
351 \r
352     if (!RecorderDataPtr->recorderActive)\r
353     {\r
354         skipEvent = 1;\r
355     }\r
356 \r
357     /* If this event should be logged, log it! */\r
358     if (skipEvent == 0)\r
359     {\r
360         dts3 = (uint16_t)prvTraceGetDTS(0xFFFF);\r
361 \r
362         if (RecorderDataPtr->recorderActive) /* Need to repeat this check! */\r
363         {\r
364             handle_of_last_logged_task = task_handle;\r
365             ts = (TSEvent*)xTraceNextFreeEventBufferSlot();\r
366 \r
367             if (ts != NULL)\r
368             {\r
369                 if (uiTraceGetObjectState(TRACE_CLASS_TASK,\r
370                     handle_of_last_logged_task) == TASK_STATE_INSTANCE_ACTIVE)\r
371                 {\r
372                     ts->type = TS_TASK_RESUME;\r
373                 }\r
374                 else\r
375                 {\r
376                     ts->type = TS_TASK_BEGIN;\r
377                 }\r
378 \r
379                 ts->dts = dts3;\r
380                 ts->objHandle = handle_of_last_logged_task;\r
381 \r
382                 vTraceSetObjectState(TRACE_CLASS_TASK,\r
383                                      handle_of_last_logged_task,\r
384                                      TASK_STATE_INSTANCE_ACTIVE);\r
385 \r
386                 prvTraceUpdateCounters();\r
387             }\r
388         }\r
389     }\r
390 \r
391     /* See comment on recorder_busy++ above. */\r
392     recorder_busy--;\r
393 }\r
394 \r
395 /*******************************************************************************\r
396  * vTraceStoreNameCloseEvent\r
397  *\r
398  * Updates the symbol table with the name of this object from the dynamic\r
399  * objects table and stores a "close" event, holding the mapping between handle\r
400  * and name (a symbol table handle). The stored name-handle mapping is thus the\r
401  * "old" one, valid up until this point.\r
402  ******************************************************************************/\r
403 #if (INCLUDE_OBJECT_DELETE == 1)\r
404 void vTraceStoreObjectNameOnCloseEvent(objectHandleType handle,\r
405                                        traceObjectClass objectclass)\r
406 {\r
407     ObjCloseNameEvent * ce;\r
408     const char * name;\r
409     traceLabel idx;\r
410 \r
411         TRACE_ASSERT(objectclass < TRACE_NCLASSES, "vTraceStoreObjectNameOnCloseEvent: objectclass >= TRACE_NCLASSES", );\r
412         TRACE_ASSERT(handle <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectclass], "vTraceStoreObjectNameOnCloseEvent: Invalid value for handle", );\r
413 \r
414     if (RecorderDataPtr->recorderActive)\r
415         {\r
416                 name = TRACE_PROPERTY_NAME_GET(objectclass, handle);\r
417 \r
418                 idx = prvTraceOpenSymbol(name, 0);\r
419 \r
420                 // Interrupt disable not necessary, already done in trcHooks.h macro\r
421                 ce = (ObjCloseNameEvent*) xTraceNextFreeEventBufferSlot();\r
422                 if (ce != NULL)\r
423                 {\r
424                         ce->type = EVENTGROUP_OBJCLOSE_NAME + objectclass;\r
425                         ce->objHandle = handle;\r
426                         ce->symbolIndex = idx;\r
427                         prvTraceUpdateCounters();\r
428                 }\r
429         }\r
430 }\r
431 \r
432 void vTraceStoreObjectPropertiesOnCloseEvent(objectHandleType handle,\r
433                                              traceObjectClass objectclass)\r
434 {\r
435     ObjClosePropEvent * pe;\r
436         \r
437     TRACE_ASSERT(objectclass < TRACE_NCLASSES, "vTraceStoreObjectPropertiesOnCloseEvent: objectclass >= TRACE_NCLASSES", );\r
438     TRACE_ASSERT(handle <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectclass], "vTraceStoreObjectPropertiesOnCloseEvent: Invalid value for handle", );\r
439 \r
440     if (RecorderDataPtr->recorderActive)\r
441         {\r
442                 // Interrupt disable not necessary, already done in trcHooks.h macro\r
443                 pe = (ObjClosePropEvent*) xTraceNextFreeEventBufferSlot();\r
444                 if (pe != NULL)\r
445                 {\r
446                         if (objectclass == TRACE_CLASS_TASK)\r
447                         {\r
448                                 pe->arg1 = TRACE_PROPERTY_ACTOR_PRIORITY(objectclass, handle);\r
449                                 pe->arg2 = 0; // Legacy - IFE info removed.\r
450                                 pe->arg3 = 0; // Legacy - IFE info removed.\r
451                         }else{\r
452                                 pe->arg1 = TRACE_PROPERTY_OBJECT_STATE(objectclass, handle);\r
453                         }\r
454                         pe->type = EVENTGROUP_OBJCLOSE_PROP + objectclass;\r
455                         prvTraceUpdateCounters();\r
456                 }\r
457         }\r
458 }\r
459 #endif\r
460 \r
461 void vTraceSetPriorityProperty(uint8_t objectclass, uint8_t id, uint8_t value)\r
462 {\r
463         TRACE_ASSERT(objectclass < TRACE_NCLASSES, "vTraceSetPriorityProperty: objectclass >= TRACE_NCLASSES", );\r
464         TRACE_ASSERT(id <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectclass], "vTraceSetPriorityProperty: Invalid value for id", );\r
465 \r
466     TRACE_PROPERTY_ACTOR_PRIORITY(objectclass, id) = value;\r
467 }\r
468 \r
469 uint8_t uiTraceGetPriorityProperty(uint8_t objectclass, uint8_t id)\r
470 {\r
471         TRACE_ASSERT(objectclass < TRACE_NCLASSES, "uiTraceGetPriorityProperty: objectclass >= TRACE_NCLASSES", 0);\r
472         TRACE_ASSERT(id <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectclass], "uiTraceGetPriorityProperty: Invalid value for id", 0);\r
473 \r
474     return TRACE_PROPERTY_ACTOR_PRIORITY(objectclass, id);\r
475 }\r
476 \r
477 void vTraceSetObjectState(uint8_t objectclass, uint8_t id, uint8_t value)\r
478 {\r
479         TRACE_ASSERT(objectclass < TRACE_NCLASSES, "vTraceSetObjectState: objectclass >= TRACE_NCLASSES", );\r
480         TRACE_ASSERT(id <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectclass], "vTraceSetObjectState: Invalid value for id", );\r
481         \r
482     TRACE_PROPERTY_OBJECT_STATE(objectclass, id) = value;\r
483 }\r
484 \r
485 uint8_t uiTraceGetObjectState(uint8_t objectclass, uint8_t id)\r
486 {\r
487         TRACE_ASSERT(objectclass < TRACE_NCLASSES, "uiTraceGetObjectState: objectclass >= TRACE_NCLASSES", 0);\r
488         TRACE_ASSERT(id <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectclass], "uiTraceGetObjectState: Invalid value for id", 0);\r
489         \r
490     return TRACE_PROPERTY_OBJECT_STATE(objectclass, id);\r
491 }\r
492 \r
493 void vTraceSetTaskInstanceFinished(objectHandleType handle)\r
494 {\r
495         TRACE_ASSERT(handle <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[TRACE_CLASS_TASK], "vTraceSetTaskInstanceFinished: Invalid value for handle", );\r
496         \r
497 #if (USE_IMPLICIT_IFE_RULES == 1)\r
498     TRACE_PROPERTY_OBJECT_STATE(TRACE_CLASS_TASK, handle) = 0;    \r
499 #endif\r
500 }\r
501 \r
502 #endif