1    /*
     2     * Copyright (c) 2012-2015, 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     * */
    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     *  -{@link ti.uia.sysbios.LoggingSetup} and {@link ti.uia.runtime.LogSync}
   127     *  cannot be used with LoggerSM.
   128     *  @p
   129     */
   130    @ModuleStartup      /* Initialize static instances */
   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    }