1    /* --COPYRIGHT--,BSD
     2     * Copyright (c) $(CPYYEAR), Texas Instruments Incorporated
     3     * All rights reserved.
     4     *
     5     * Redistribution and use in source and binary forms, with or without
     6     * modification, are permitted provided that the following conditions
     7     * are met:
     8     *
     9     * *  Redistributions of source code must retain the above copyright
    10     *    notice, this list of conditions and the following disclaimer.
    11     *
    12     * *  Redistributions in binary form must reproduce the above copyright
    13     *    notice, this list of conditions and the following disclaimer in the
    14     *    documentation and/or other materials provided with the distribution.
    15     *
    16     * *  Neither the name of Texas Instruments Incorporated nor the names of
    17     *    its contributors may be used to endorse or promote products derived
    18     *    from this software without specific prior written permission.
    19     *
    20     * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    21     * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
    22     * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
    23     * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
    24     * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
    25     * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
    26     * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
    27     * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
    28     * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
    29     * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
    30     * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    31     * --/COPYRIGHT--*/
    32    
    33    /*
    34     *  ======== LoggerSM.xdc ========
    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      /* Initialize static instances */
   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 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    instance:
   302        /*!
   303         *  ======== create ========
   304         *  Create a `LoggerSM` logger
   305         *
   306         *  @see LoggerSM#Params
   307         */
   308        @DirectCall
   309        create();
   310    
   311        /*!
   312         *  ======== enable ========
   313         *  Enable a log
   314         *
   315         *  @a(returns)
   316         *  The function returns the state of the log (`TRUE` if enabled,
   317         *  `FALSE` if disabled) before the call. That allow clients to restore
   318         *  the previous state.
   319         */
   320        @DirectCall
   321        override Bool enable();
   322    
   323        /*!
   324         *  ======== disable ========
   325         *  Disable a log
   326         *
   327         *  Events written to a disabled log are silently discarded.
   328         *
   329         *  @a(returns)
   330         *  The function returns the state of the log (`TRUE` if enabled,
   331         *  `FALSE` if disabled) before the call. That allow clients to restore
   332         *  the previous state.
   333         */
   334        @DirectCall
   335        override Bool disable();
   336    
   337        /*!
   338         *  ======== write0 ========
   339         *  Process a log event with 0 arguments and the calling address.
   340         *
   341         *  Same as `write4` except with 0 arguments rather than 4.
   342         *  @see #write4()
   343         */
   344        @DirectCall
   345        override Void write0(Log.Event evt, Types.ModuleId mid);
   346    
   347        /*!
   348         *  ======== write1 ========
   349         *  Process a log event with 1 arguments and the calling address.
   350         *
   351         *  Same as `write4` except with 1 arguments rather than 4.
   352         *  @see #write4()
   353         */
   354        @DirectCall
   355        override Void write1(Log.Event evt, Types.ModuleId mid, IArg a1);
   356    
   357        /*!
   358         *  ======== write2 ========
   359         *  Process a log event with 2 arguments and the calling address.
   360         *
   361         *  Same as `write4` except with 2 arguments rather than 4.
   362         *
   363         *  @see #write4()
   364         */
   365        @DirectCall
   366        override Void write2(Log.Event evt, Types.ModuleId mid, IArg a1, IArg a2);
   367    
   368        /*!
   369         *  ======== write4 ========
   370         *  Process a log event with 4 arguments and the calling address.
   371         *
   372         *  @see ILogger#write4()
   373         */
   374        @DirectCall
   375        override Void write4(Log.Event evt, Types.ModuleId mid, IArg a1, IArg a2, 
   376                             IArg a3, IArg a4);
   377    
   378        /*!
   379         *  ======== write8 ========
   380         *  Process a log event with 8 arguments and the calling address.
   381         *
   382         *  Same as `write4` except with 8 arguments rather than 4.
   383         *
   384         *  @see #write4()
   385         */
   386        @DirectCall
   387        override Void write8(Log.Event evt, Types.ModuleId mid, IArg a1, IArg a2, 
   388                             IArg a3, IArg a4, IArg a5, IArg a6, IArg a7, IArg a8);
   389    
   390        /*!
   391         *  ======== setFilterLevel ========
   392         *  Sets the level of detail that instances will log.
   393         *
   394         *  Events with the specified level or higher will be logged, events
   395         *  below the specified level will be dropped.
   396         *
   397         *  Events are filtered first by diags category, then by level. If an
   398         *  event's diags category is disabled in the module's diags mask, then it
   399         *  will be filtered out regardless of level. The event will not even be
   400         *  passed to the logger.
   401         *
   402         *  This API allows for setting the filtering level for more than one
   403         *  diags category at a time. The mask parameter can be a single category
   404         *  or multiple categories combined, and the level will be set for all of
   405         *  those categories.
   406         *
   407         *  @param(mask) The diags categories to set the level for
   408         *  @param(filterLevel) The new filtering level for the specified
   409         *                      categories
   410         */
   411        @DirectCall
   412        override Void setFilterLevel(Diags.Mask mask, Diags.EventLevel filterLevel);
   413    
   414        /*!
   415         *  ======== getFilterLevel ========
   416         *  Returns the mask of diags categories currently set to the specified
   417         *  level.
   418         *
   419         *  See '{@link #setFilterLevel}' for an explanation of level filtering.
   420         */
   421        @DirectCall
   422        override Diags.Mask getFilterLevel(Diags.EventLevel level);
   423        
   424    internal:
   425    
   426        const UInt16 VERSION = 1;
   427    
   428        /*!
   429         *  ======== write ========
   430         */
   431        Void write(Object *obj, Log.Event evt,
   432            Types.ModuleId mid, IArg a1, IArg a2, IArg a3, IArg a4,
   433            IArg a5, IArg a6, IArg a7, IArg a8);
   434            
   435        /*!
   436         *  ======== filterOutEvent ========
   437         */
   438        @DirectCall
   439        Bool filterOutEvent(Diags.Mask mask);
   440        
   441        /*!
   442         *  ======== sharedBuffer ========
   443         */
   444        config Char sharedBuffer[];    
   445    
   446        /*!
   447         *  ======== Module_State ========
   448         */
   449        struct Module_State {
   450            Int partitionId;
   451            Diags.Mask level1;
   452            Diags.Mask level2;
   453            Diags.Mask level3;
   454            SharedObj *sharedObj;
   455            Bits16 serial;
   456            Bool enabled;
   457        };
   458        
   459        /*!
   460         *  ======== SharedObj ========
   461         */
   462        struct SharedObj {
   463            Bits32 headerTag;           
   464            Bits32 version;
   465            Bits32 numPartitions;        
   466            Char *endPtr;
   467            volatile Char *readPtr;
   468            Char *writePtr;
   469            Char *buffer;
   470            Bits32 bufferSize;
   471            Bits32 droppedEvents;        
   472            Bits16 moduleId;    
   473            Bits16 instanceId;         
   474            Bits16 decode;
   475            Bits16 overwrite;        
   476        };
   477    }