1    /*
     2     * Copyright (c) 2012, 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     *  @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 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    }