1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
32
33 34 35
36 import xdc.runtime.ITimestampClient;
37 import xdc.runtime.IHeap;
38 import xdc.runtime.Types;
39 import xdc.runtime.Log;
40 import xdc.runtime.ILogger;
41 import xdc.runtime.Error;
42 import xdc.runtime.Diags;
43 import xdc.rov.ViewInfo;
44
45 /*!
46 * ======== LoggerSM ========
47 * Logger implementation that stores Log records into shared memory
48 *
49 * This logger implementation stores xdc.runtime.Log records into shared memory.
50 * This logger is intended to be used for SoC system (e.g. EVMTI816X),
51 * where Linux is running on the host core (e.g. CortexA8) and
52 * SYS/BIOS is running on the targets (e.g. M3 and DSP).
53 *
54 * This logger is used on the targets. The host is then responsible
55 * for reading the shared memory and processing the records. UIA
56 * ships the ti/uia/linux/LoggerSM module that can be used to
57 * process the records. UIA also ships a cmdline app,
58 * ti/uia/examples/evmti816x/loggerSMDump.out, that show
59 * how to use the linux/LoggerSM module.
60 *
61 * @a(Cache management)
62 *
63 * The location of the shared memory that is used by LoggerSM must be
64 * specified by the application. This shared memory must be in a
65 * non-cacheable region. The '{@link #bufSection}' configuration
66 * parameter can be used to help place the Logger's buffer.
67 * Refer to the device specific LoggerSM
68 * examples (e.g. ti/uia/examples/evmti816x/readme.txt) to see how this
69 * was accomplished.
70 *
71 * @a(Partitions)
72 *
73 * The application gets to specify the size of the shared region. This
74 * size is divided between each of the targets. For example, on the evmti816x,
75 * if the '{@link #sharedMemorySize}' was 0x3000, each target,
76 * dsp, videoM3 and vpssM3, would get 0x1000 amount of shared memory for
77 * log records. Each target region is called a partition. Since LoggerSM is a
78 * generic logger that can be used on multiple devices, the number of
79 * partitions (e.g. number of targets using the shared memory) is specified
80 * wtih the '{@link #numPartitions}' configuration option. Each target needs
81 * a unique '{@link #partitionId}' also. For example, on evmti816x examples,
82 * the dsp is assigned 0, videoM3 is assigned 1 and vpssM3 is assigned 2. This
83 * corresponds with the IPC Multicore Ids for simplicity sake. Note: the
84 * partition id can be set during target startup also via the
85 * '{@link #setPartitionId}' API.
86 *
87 * LoggerSM supports multiple instances, but all instances are writing to
88 * the same shared memory (in a thread safe manner). This was done to
89 * simplify the design. Because of this, application really should only
90 * create one LoggerSM instance.
91 *
92 * @a(decode and overwrite)
93 * The LoggerSM module has two key configuration options: '{@link #decode}'
94 * and '{@link #overwrite}'
95 *
96 * The '{@link #decode}' configuration determines whether the target will
97 * decode the Log record during the Log call. If '{@link #decode}' is true,
98 * the Log record is converted to an ASCII string and then written into the
99 * shared memory. This approach is expensive from a performance standpoint.
100 * Its value is that it is easy to manage and view on the host
101 * (e.g. ti/uia/examples/evmti816x/loggerSMDump.out prints the ASCII strings
102 * to the console on the CortexA8).
103 *
104 * If '{@link #decode}' is false, the Log records are not decoded. Instead
105 * they are stored in the shared memory as binary data. This allows the
106 * Log calls to be much faster. The burden for decoding is on the readers side.
107 * For example, ti/uia/examples/evmti816x/loggerSMDump.out dumps the encoded
108 * records into a binary file that can be post-processed in
109 * CCS' System Analyzer.
110 *
111 * The '{@link #overwrite}' configuration determines whether the target
112 * will overwrite old records
113 * when the shared memory is full. The default setting is false, so when the
114 * logger is full, new records are dropped. This mode allows the reader
115 * (e.g. ti/uia/examples/evmti816x/loggerSMDump.out) to read the records
116 * while the target is running.
117 *
118 * When '{@link #overwrite}', old records are overwritten when the logger is
119 * full. However, the reader should only run when the targets are halted (or
120 * crashed).
121 *
122 * @a(caveats)
123 * @p(blist)
124 * -Currently LoggerSM assumes the endianness and word size of the host
125 * and targets are the same.
126 * @p
127 */
128 @ModuleStartup
129 module LoggerSM inherits xdc.runtime.IFilterLogger
130 {
131 /*!
132 * @_nodoc
133 * ======== ModuleView ========
134 */
135 metaonly struct ModuleView {
136 Bool isTimestampEnabled;
137 Bool decode;
138 Bool overwrite;
139 }
140
141 /*!
142 * @_nodoc
143 * ======== InstanceView ========
144 */
145 metaonly struct InstanceView {
146 String label;
147 }
148
149 /*!
150 * @_nodoc
151 * ======== rovViewInfo ========
152 */
153 @Facet
154 metaonly config ViewInfo.Instance rovViewInfo =
155 ViewInfo.create({
156 viewMap: [
157 ['Module',
158 {
159 type: ViewInfo.MODULE,
160 viewInitFxn: 'viewInitModule',
161 structName: 'ModuleView'
162 }
163 ],
164 ['Instances',
165 {
166 type: ViewInfo.INSTANCE,
167 viewInitFxn: 'viewInitInstances',
168 structName: 'InstanceView'
169 }
170 ],
171 ]
172 });
173
174 /*! Error raised if get or setFilterLevel receive a bad level value */
175 config Error.Id E_badLevel =
176 {msg: "E_badLevel: Bad filter level value: %d"};
177
178 /*!
179 * ======== isTimestampEnabled ========
180 * Enable or disable logging the 64b local CPU timestamp
181 * at the start of each event
182 */
183 config Bool isTimestampEnabled = true;
184
185 /*!
186 * ======== decode ========
187 * Flag to determine whether to decode the events in shared memory
188 *
189 * If true, all the events will be decoded into ASCII strings
190 * when it is written into shared memory. If false, binary
191 * data is written instead.
192 */
193 config Bool decode = true;
194
195 /*!
196 * ======== overwrite ========
197 * Flag to determine whether to overwrite records when full
198 *
199 * If true and when the buffer is full, the logger will overwrite
200 * the oldest record. Reading the records can only occur when the
201 * targets have been halted.
202 *
203 * If false and when the buffer is full, the logger will discard
204 * the new record.
205 */
206 config Bool overwrite = false;
207
208 /*!
209 * ======== level1Mask ========
210 * Mask of diags categories whose initial filtering level is Diags.LEVEL1
211 *
212 * See '{@link #level4Mask}' for details.
213 */
214 config Diags.Mask level1Mask = 0;
215
216 /*!
217 * ======== level2Mask ========
218 * Mask of diags categories whose initial filtering level is Diags.LEVEL2
219 *
220 * See '{@link #level4Mask}' for details.
221 */
222 config Diags.Mask level2Mask = 0;
223
224 /*!
225 * ======== level3Mask ========
226 * Mask of diags categories whose initial filtering level is Diags.LEVEL3
227 *
228 * See '{@link #level4Mask}' for details.
229 */
230 config Diags.Mask level3Mask = 0;
231
232 /*!
233 * ======== level4Mask ========
234 * Mask of diags categories whose initial filtering level is Diags.LEVEL4
235 *
236 * If 'filterByLevel' is true, then all LoggerBuf instances will filter
237 * incoming events based on their event level.
238 *
239 * The LoggerSM module allows for specifying a different filter level for
240 * every Diags bit. These filtering levels are module wide; LoggerBuf does
241 * not support specifying the levels on a per-instance basis.
242 *
243 * The setFilterLevel API can be used to change the filtering levels at
244 * runtime.
245 *
246 * The default filtering levels are assigned using the 'level1Mask' -
247 * 'level4Mask' config parameters. These are used to specify, for each of
248 * the four event levels, the set of bits which should filter at that
249 * level by default.
250 *
251 * The default filtering configuration sets the filter level to
252 * Diags.LEVEL4 for all logging-related diags bits so that all events are
253 * logged by default.
254 */
255 config Diags.Mask level4Mask = Diags.ALL_LOGGING;
256
257 /*!
258 * ======== partitionId ========
259 * Unique id for each core using the shared memory
260 */
261 metaonly config Int partitionId = 0;
262
263 /*!
264 * ======== numPartitions ========
265 * Number of partitions sharing the shared memory
266 */
267 config Int numPartitions = 3;
268
269 /*!
270 * ======== sharedMemorySize ========
271 * Total size of shared memory in MAU that will be divided by the number
272 * of partitions
273 */
274 config SizeT sharedMemorySize = 0x20000;
275
276 /*!
277 * ======== bufSection ========
278 * Section name for the buffer in shared memory
279 */
280 metaonly config String bufSection = null;
281
282 /*!
283 * ======== setPartitionId ========
284 * Change the partitionId at runtime.
285 *
286 * Must be called early before module startup occurs.
287 * Generally the best place to do this is via the
288 * xdc.runtime.Startup.firstFxns array.
289 */
290 Void setPartitionId(Int partitionId);
291
292 /*!
293 * ======== MetaData ========
294 * This data is added to the RTA MetaData file.
295 */
296 @XmlDtd metaonly struct MetaData {
297 Int instanceId;
298 Int priority;
299 }
300
301 /*!
302 * ======== setSharedMemory ========
303 * Specify the shared memory to be used by LoggerSM
304 *
305 * This runtime API can be called once to initialize the shared memory
306 * that the all LoggerSM instances use. This API can only be called
307 * if '{@link #sharedMemorySize}' is set to zero. If
308 * '{@link #sharedMemorySize}' is non-zero, the shared memory is
309 * statically defined and initialized instead. Since the memory
310 * is already defined, this API cannot change it.
311 *
312 * @param(sharedMemory) Base address of the shared memory to be used
313 * by LoggerSM.
314 * @param(sharedMemorySize) Size of the shared memory.
315 *
316 * @a(returns)
317 * This function returns TRUE if successful. It returns FALSE if not.
318 * The reasons for failure are either '{@link #sharedMemorySize}' is
319 * non-zero or the API has been called multiple times.
320 */
321 @DirectCall
322 Bool setSharedMemory(Ptr sharedMemory, Bits32 sharedMemorySize);
323
324 instance:
325 /*!
326 * ======== create ========
327 * Create a `LoggerSM` logger
328 *
329 * @see LoggerSM#Params
330 */
331 @DirectCall
332 create();
333
334 /*!
335 * ======== enable ========
336 * Enable a log
337 *
338 * @a(returns)
339 * The function returns the state of the log (`TRUE` if enabled,
340 * `FALSE` if disabled) before the call. That allow clients to restore
341 * the previous state.
342 */
343 @DirectCall
344 override Bool enable();
345
346 /*!
347 * ======== disable ========
348 * Disable a log
349 *
350 * Events written to a disabled log are silently discarded.
351 *
352 * @a(returns)
353 * The function returns the state of the log (`TRUE` if enabled,
354 * `FALSE` if disabled) before the call. That allow clients to restore
355 * the previous state.
356 */
357 @DirectCall
358 override Bool disable();
359
360 /*!
361 * ======== write0 ========
362 * Process a log event with 0 arguments and the calling address.
363 *
364 * Same as `write4` except with 0 arguments rather than 4.
365 * @see #write4()
366 */
367 @DirectCall
368 override Void write0(Log.Event evt, Types.ModuleId mid);
369
370 /*!
371 * ======== write1 ========
372 * Process a log event with 1 arguments and the calling address.
373 *
374 * Same as `write4` except with 1 arguments rather than 4.
375 * @see #write4()
376 */
377 @DirectCall
378 override Void write1(Log.Event evt, Types.ModuleId mid, IArg a1);
379
380 /*!
381 * ======== write2 ========
382 * Process a log event with 2 arguments and the calling address.
383 *
384 * Same as `write4` except with 2 arguments rather than 4.
385 *
386 * @see #write4()
387 */
388 @DirectCall
389 override Void write2(Log.Event evt, Types.ModuleId mid, IArg a1, IArg a2);
390
391 /*!
392 * ======== write4 ========
393 * Process a log event with 4 arguments and the calling address.
394 *
395 * @see ILogger#write4()
396 */
397 @DirectCall
398 override Void write4(Log.Event evt, Types.ModuleId mid, IArg a1, IArg a2,
399 IArg a3, IArg a4);
400
401 /*!
402 * ======== write8 ========
403 * Process a log event with 8 arguments and the calling address.
404 *
405 * Same as `write4` except with 8 arguments rather than 4.
406 *
407 * @see #write4()
408 */
409 @DirectCall
410 override Void write8(Log.Event evt, Types.ModuleId mid, IArg a1, IArg a2,
411 IArg a3, IArg a4, IArg a5, IArg a6, IArg a7, IArg a8);
412
413 /*!
414 * ======== setFilterLevel ========
415 * Sets the level of detail that instances will log.
416 *
417 * Events with the specified level or higher will be logged, events
418 * below the specified level will be dropped.
419 *
420 * Events are filtered first by diags category, then by level. If an
421 * event's diags category is disabled in the module's diags mask, then it
422 * will be filtered out regardless of level. The event will not even be
423 * passed to the logger.
424 *
425 * This API allows for setting the filtering level for more than one
426 * diags category at a time. The mask parameter can be a single category
427 * or multiple categories combined, and the level will be set for all of
428 * those categories.
429 *
430 * @param(mask) The diags categories to set the level for
431 * @param(filterLevel) The new filtering level for the specified
432 * categories
433 */
434 @DirectCall
435 override Void setFilterLevel(Diags.Mask mask, Diags.EventLevel filterLevel);
436
437 /*!
438 * ======== getFilterLevel ========
439 * Returns the mask of diags categories currently set to the specified
440 * level.
441 *
442 * See '{@link #setFilterLevel}' for an explanation of level filtering.
443 */
444 @DirectCall
445 override Diags.Mask getFilterLevel(Diags.EventLevel level);
446
447 internal:
448
449 const UInt16 VERSION = 1;
450
451 /*!
452 * ======== write ========
453 */
454 Void write(Object *obj, Log.Event evt,
455 Types.ModuleId mid, IArg a1, IArg a2, IArg a3, IArg a4,
456 IArg a5, IArg a6, IArg a7, IArg a8);
457
458 /*!
459 * ======== filterOutEvent ========
460 */
461 @DirectCall
462 Bool filterOutEvent(Diags.Mask mask);
463
464
465
466 /*!
467 * ======== Module_State ========
468 */
469 struct Module_State {
470 Int partitionId;
471 Diags.Mask level1;
472 Diags.Mask level2;
473 Diags.Mask level3;
474 SharedObj *sharedObj;
475 Char sharedBuffer[];
476 Bits16 serial;
477 Bool enabled;
478 };
479
480 /*!
481 * ======== SharedObj ========
482 */
483 struct SharedObj {
484 Bits32 headerTag;
485 Bits32 version;
486 Bits32 numPartitions;
487 Char *endPtr;
488 volatile Char *readPtr;
489 Char *writePtr;
490 Char *buffer;
491 Bits32 bufferSizeMAU;
492 Bits32 droppedEvents;
493 Bits16 moduleId;
494 Bits16 instanceId;
495 Bits16 decode;
496 Bits16 overwrite;
497 };
498 }