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 * -{@link ti.uia.sysbios.LoggingSetup} and {@link ti.uia.runtime.LogSync}
127 * cannot be used with LoggerSM.
128 * @p
129 */
130 @ModuleStartup
131 @Template("./LoggerSM.xdt")
132 module LoggerSM inherits xdc.runtime.IFilterLogger
133 {
134 /*!
135 * @_nodoc
136 * ======== ModuleView ========
137 */
138 metaonly struct ModuleView {
139 Bool isTimestampEnabled;
140 Bool decode;
141 Bool overwrite;
142 }
143
144 /*!
145 * @_nodoc
146 * ======== InstanceView ========
147 */
148 metaonly struct InstanceView {
149 String label;
150 }
151
152 /*!
153 * @_nodoc
154 * ======== rovViewInfo ========
155 */
156 @Facet
157 metaonly config ViewInfo.Instance rovViewInfo =
158 ViewInfo.create({
159 viewMap: [
160 ['Module',
161 {
162 type: ViewInfo.MODULE,
163 viewInitFxn: 'viewInitModule',
164 structName: 'ModuleView'
165 }
166 ],
167 ['Instances',
168 {
169 type: ViewInfo.INSTANCE,
170 viewInitFxn: 'viewInitInstances',
171 structName: 'InstanceView'
172 }
173 ],
174 ]
175 });
176
177 /*! Error raised if get or setFilterLevel receive a bad level value */
178 config Error.Id E_badLevel =
179 {msg: "E_badLevel: Bad filter level value: %d"};
180
181 /*!
182 * ======== isTimestampEnabled ========
183 * Enable or disable logging the 64b local CPU timestamp
184 * at the start of each event
185 */
186 config Bool isTimestampEnabled = true;
187
188 /*!
189 * ======== decode ========
190 * Flag to determine whether to decode the events in shared memory
191 *
192 * If true, all the events will be decoded into ASCII strings
193 * when it is written into shared memory. If false, binary
194 * data is written instead.
195 */
196 config Bool decode = true;
197
198 /*!
199 * ======== overwrite ========
200 * Flag to determine whether to overwrite records when full
201 *
202 * If true and when the buffer is full, the logger will overwrite
203 * the oldest record. Reading the records can only occur when the
204 * targets have been halted.
205 *
206 * If false and when the buffer is full, the logger will discard
207 * the new record.
208 */
209 config Bool overwrite = false;
210
211 /*!
212 * ======== level1Mask ========
213 * Mask of diags categories whose initial filtering level is Diags.LEVEL1
214 *
215 * See '{@link #level4Mask}' for details.
216 */
217 config Diags.Mask level1Mask = 0;
218
219 /*!
220 * ======== level2Mask ========
221 * Mask of diags categories whose initial filtering level is Diags.LEVEL2
222 *
223 * See '{@link #level4Mask}' for details.
224 */
225 config Diags.Mask level2Mask = 0;
226
227 /*!
228 * ======== level3Mask ========
229 * Mask of diags categories whose initial filtering level is Diags.LEVEL3
230 *
231 * See '{@link #level4Mask}' for details.
232 */
233 config Diags.Mask level3Mask = 0;
234
235 /*!
236 * ======== level4Mask ========
237 * Mask of diags categories whose initial filtering level is Diags.LEVEL4
238 *
239 * If 'filterByLevel' is true, then all LoggerBuf instances will filter
240 * incoming events based on their event level.
241 *
242 * The LoggerSM module allows for specifying a different filter level for
243 * every Diags bit. These filtering levels are module wide; LoggerBuf does
244 * not support specifying the levels on a per-instance basis.
245 *
246 * The setFilterLevel API can be used to change the filtering levels at
247 * runtime.
248 *
249 * The default filtering levels are assigned using the 'level1Mask' -
250 * 'level4Mask' config parameters. These are used to specify, for each of
251 * the four event levels, the set of bits which should filter at that
252 * level by default.
253 *
254 * The default filtering configuration sets the filter level to
255 * Diags.LEVEL4 for all logging-related diags bits so that all events are
256 * logged by default.
257 */
258 config Diags.Mask level4Mask = Diags.ALL_LOGGING;
259
260 /*!
261 * ======== partitionId ========
262 * Unique id for each core using the shared memory
263 */
264 metaonly config Int partitionId = 0;
265
266 /*!
267 * ======== numPartitions ========
268 * Number of partitions sharing the shared memory
269 */
270 config Int numPartitions = 3;
271
272 /*!
273 * ======== sharedMemorySize ========
274 * Total size of shared memory in MAU that will be divided by the number
275 * of partitions
276 */
277 config SizeT sharedMemorySize = 0x20000;
278
279 /*!
280 * ======== userTimestamp ========
281 * Use the user configured Timestamp_get64() instead of TCSL/TCSH.
282 *
283 * For C6x devices, LoggerSM defaults to using the built-in hardware
284 * counter, TCSL/TCSH for timestamping. This improves the performance
285 * of Log statements. However, in some cases, the user may want to
286 * provide their own timestamp provider to LoggerSM, instead of using
287 * TCSL/TCSH.
288 * If userTimestamp is set to true, Timestamp_get64() will be used
289 * instead of reading TCSL/TCSH. For non-C6x devices, changing
290 * this configuration parameter has no effect.
291 */
292 metaonly config Bool userTimestamp = false;
293
294 /*!
295 * ======== bufSection ========
296 * Section name for the buffer in shared memory
297 */
298 metaonly config String bufSection = null;
299
300 /*!
301 * ======== setPartitionId ========
302 * Change the partitionId at runtime.
303 *
304 * Must be called early before module startup occurs.
305 * Generally the best place to do this is via the
306 * xdc.runtime.Startup.firstFxns array. If using the {@link #setSharedMemory}
307 * API, make sure that LoggerSM_setPartitionId() is called before
308 * {@link #setSharedMemory}, if changing the partition Id.
309 */
310 Void setPartitionId(Int partitionId);
311
312 /*!
313 * ======== MetaData ========
314 * This data is added to the RTA MetaData file.
315 */
316 @XmlDtd metaonly struct MetaData {
317 Int instanceId;
318 Int priority;
319 }
320
321 /*!
322 * ======== setSharedMemory ========
323 * Specify the shared memory to be used by LoggerSM
324 *
325 * This runtime API can be called once to initialize the shared memory
326 * that all LoggerSM instances use. This API can only be called
327 * if '{@link #sharedMemorySize}' is set to zero. If
328 * '{@link #sharedMemorySize}' is non-zero, the shared memory is
329 * statically defined and initialized instead. Since the memory
330 * is already defined, this API cannot change it.
331 * Also, the {@link #partitionId} must not be changed after calling
332 * this API.
333 *
334 * The Linux host utility that reads the buffer requires it to be
335 * aligned on a page boundary. So make sure that the buffer passed
336 * to setSharedMemory() is page-aligned (e.g. on a 4096 byte boundary).
337 *
338 * @param(sharedMemory) Base address of the shared memory to be used
339 * by LoggerSM.
340 * @param(sharedMemorySize) Size of the shared memory.
341 *
342 * @a(returns)
343 * This function returns TRUE if successful. It returns FALSE if not.
344 * The reasons for failure are either '{@link #sharedMemorySize}' is
345 * non-zero or the API has been called multiple times.
346 */
347 @DirectCall
348 Bool setSharedMemory(Ptr sharedMemory, Bits32 sharedMemorySize);
349
350 instance:
351 /*!
352 * ======== create ========
353 * Create a `LoggerSM` logger
354 *
355 * @see LoggerSM#Params
356 */
357 @DirectCall
358 create();
359
360 /*!
361 * ======== enable ========
362 * Enable a log
363 *
364 * @a(returns)
365 * The function returns the state of the log (`TRUE` if enabled,
366 * `FALSE` if disabled) before the call. That allow clients to restore
367 * the previous state.
368 */
369 @DirectCall
370 override Bool enable();
371
372 /*!
373 * ======== disable ========
374 * Disable a log
375 *
376 * Events written to a disabled log are silently discarded.
377 *
378 * @a(returns)
379 * The function returns the state of the log (`TRUE` if enabled,
380 * `FALSE` if disabled) before the call. That allow clients to restore
381 * the previous state.
382 */
383 @DirectCall
384 override Bool disable();
385
386 /*!
387 * ======== write0 ========
388 * Process a log event with 0 arguments and the calling address.
389 *
390 * Same as `write4` except with 0 arguments rather than 4.
391 * @see #write4()
392 */
393 @DirectCall
394 override Void write0(Log.Event evt, Types.ModuleId mid);
395
396 /*!
397 * ======== write1 ========
398 * Process a log event with 1 arguments and the calling address.
399 *
400 * Same as `write4` except with 1 arguments rather than 4.
401 * @see #write4()
402 */
403 @DirectCall
404 override Void write1(Log.Event evt, Types.ModuleId mid, IArg a1);
405
406 /*!
407 * ======== write2 ========
408 * Process a log event with 2 arguments and the calling address.
409 *
410 * Same as `write4` except with 2 arguments rather than 4.
411 *
412 * @see #write4()
413 */
414 @DirectCall
415 override Void write2(Log.Event evt, Types.ModuleId mid, IArg a1, IArg a2);
416
417 /*!
418 * ======== write4 ========
419 * Process a log event with 4 arguments and the calling address.
420 *
421 * @see ILogger#write4()
422 */
423 @DirectCall
424 override Void write4(Log.Event evt, Types.ModuleId mid, IArg a1, IArg a2,
425 IArg a3, IArg a4);
426
427 /*!
428 * ======== write8 ========
429 * Process a log event with 8 arguments and the calling address.
430 *
431 * Same as `write4` except with 8 arguments rather than 4.
432 *
433 * @see #write4()
434 */
435 @DirectCall
436 override Void write8(Log.Event evt, Types.ModuleId mid, IArg a1, IArg a2,
437 IArg a3, IArg a4, IArg a5, IArg a6, IArg a7, IArg a8);
438
439 /*!
440 * ======== setFilterLevel ========
441 * Sets the level of detail that instances will log.
442 *
443 * Events with the specified level or higher will be logged, events
444 * below the specified level will be dropped.
445 *
446 * Events are filtered first by diags category, then by level. If an
447 * event's diags category is disabled in the module's diags mask, then it
448 * will be filtered out regardless of level. The event will not even be
449 * passed to the logger.
450 *
451 * This API allows for setting the filtering level for more than one
452 * diags category at a time. The mask parameter can be a single category
453 * or multiple categories combined, and the level will be set for all of
454 * those categories.
455 *
456 * @param(mask) The diags categories to set the level for
457 * @param(filterLevel) The new filtering level for the specified
458 * categories
459 */
460 @DirectCall
461 override Void setFilterLevel(Diags.Mask mask, Diags.EventLevel filterLevel);
462
463 /*!
464 * ======== getFilterLevel ========
465 * Returns the mask of diags categories currently set to the specified
466 * level.
467 *
468 * See '{@link #setFilterLevel}' for an explanation of level filtering.
469 */
470 @DirectCall
471 override Diags.Mask getFilterLevel(Diags.EventLevel level);
472
473 internal:
474
475 const UInt16 VERSION = 1;
476
477 /*!
478 * ======== filterOutEvent ========
479 */
480 @DirectCall
481 Bool filterOutEvent(Diags.Mask mask);
482
483 /*!
484 * ======== Module_State ========
485 */
486 struct Module_State {
487 Int partitionId;
488 Diags.Mask level1;
489 Diags.Mask level2;
490 Diags.Mask level3;
491 SharedObj *sharedObj;
492 Char sharedBuffer[];
493 Bits16 serial;
494 Bool enabled;
495 };
496
497 /*!
498 * ======== SharedObj ========
499 */
500 struct SharedObj {
501 Bits32 headerTag;
502 Bits32 version;
503 Bits32 numPartitions;
504 Char *endPtr;
505 volatile Char *readPtr;
506 Char *writePtr;
507 Char *buffer;
508 Bits32 bufferSizeMAU;
509 Bits32 droppedEvents;
510 Bits16 moduleId;
511 Bits16 instanceId;
512 Bits16 decode;
513 Bits16 overwrite;
514 };
515 }