1    /*
     2     * Copyright (c) 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     *  ======== HeapMem.xdc ========
    34     *
    35     */
    36    
    37    package ti.sysbios.heaps;
    38    
    39    import xdc.rov.ViewInfo;
    40    import xdc.runtime.Memory;
    41    import xdc.runtime.Error;
    42    
    43    /*!
    44     *  ======== HeapMem ========
    45     *  Variable size buffer heap manager
    46     *
    47     *  HeapMem manager provides functions to allocate and free storage from a
    48     *  heap of type HeapMem which inherits from IHeap.
    49     *
    50     *  In addition to allowing multiple static HeapMem instances to be created
    51     *  who's buffer placements and sizes are defined by their instance
    52     *  configuration parameters,
    53     *  HeapMem allows one Heap instance to be defined who's heap
    54     *  memory is defined by buffer start and end symbols in the linker command
    55     *  file. This singular Heap instance is referred to as the 'Primary Heap'.
    56     *
    57     *  see {@link #primaryHeapBaseAddr}, {@link #primaryHeapEndAddr},
    58     *  and {@link #usePrimaryHeap}
    59     *
    60     *  @p(html)
    61     *  <h3> HeapMem Gate </h3>
    62     *  A HeapMem instance will use the HeapMem module Gate to protect any accesses
    63     *  to its list of free memory blocks. The HeapMem instance will enter and
    64     *  leave the module Gate when allocating blocks, freeing blocks, and
    65     *  retrieving statistics about the HeapMem.
    66     *
    67     *  By default, the Gate is of type GateMutex.
    68     *
    69     *  A different Gate can be specified using the common$.gate parameter.
    70     *  For example, to use a GateTask to protect HeapMem:
    71     *      HeapMem.common$.gate = GateTask.create();
    72     *
    73     *  To save on overhead, HeapMem does not create additional Gate instances on a
    74     *  per-instance basis; there is only one Gate instance shared across all of
    75     *  the HeapMem instances. Therefore, the HeapMem.common$.gateParams parameter
    76     *  (used for configuring per-instance Gates) is ignored.
    77     *
    78     *  The type of Gate used should be chosen based on the type of threads (Hwi,
    79     *  Swi, Task, etc.) using the heap. It should also consider the
    80     *  non-deterministic nature of the HeapMem. A call to alloc or free will
    81     *  traverse a list of free blocks, so a GateHwi, for example, is likely an
    82     *  inappropriate Gate for HeapMem.
    83     *
    84     *  @p(html)
    85     *  <h3> Calling Context </h3>
    86     *  <table border="1" cellpadding="3">
    87     *    <colgroup span="1"></colgroup> <colgroup span="5" align="center">
    88     *    </colgroup>
    89     *
    90     *    <tr><th> Function    </th><th>  Hwi   </th><th>  Swi   </th>
    91     *    <th>  Task  </th><th>  Main  </th><th>  Startup  </th></tr>
    92     *    <!--                                     -->
    93     *    <tr><td> Params_init         </td><td>   Y    </td><td>   Y    </td>
    94     *    <td>   Y    </td><td>   Y    </td><td>   Y    </td></tr>
    95     *    <tr><td> alloc               </td><td>   N**  </td><td>   N**  </td>
    96     *    <td>   Y**  </td><td>   Y    </td><td>   N    </td></tr>
    97     *    <tr><td> construct           </td><td>   Y    </td><td>   Y    </td>
    98     *    <td>   Y    </td><td>   Y    </td><td>   N    </td></tr>
    99     *    <tr><td> create              </td><td>   N*   </td><td>   N*   </td>
   100     *    <td>   Y    </td><td>   Y    </td><td>   N    </td></tr>
   101     *    <tr><td> delete              </td><td>   N*   </td><td>   N*   </td>
   102     *    <td>   Y    </td><td>   Y    </td><td>   N    </td></tr>
   103     *    <tr><td> destruct            </td><td>   Y    </td><td>   Y    </td>
   104     *    <td>   Y    </td><td>   Y    </td><td>   N    </td></tr>
   105     *    <tr><td> free                </td><td>   N**  </td><td>   N**  </td>
   106     *    <td>   Y**  </td><td>   Y    </td><td>   N    </td></tr>
   107     *    <tr><td> getExtendedStats    </td><td>   Y    </td><td>   Y    </td>
   108     *    <td>   Y    </td><td>   Y    </td><td>   N    </td></tr>
   109     *    <tr><td> getStats            </td><td>   N**  </td><td>   N**  </td>
   110     *    <td>   Y**  </td><td>   Y    </td><td>   N    </td></tr>
   111     *    <tr><td> isBlocking          </td><td>   Y    </td><td>   Y    </td>
   112     *    <td>   Y    </td><td>   Y    </td><td>   N    </td></tr>
   113     *    <tr><td> restore             </td><td>   Y+   </td><td>   Y+   </td>
   114     *    <td>   Y+   </td><td>   Y    </td><td>   N    </td></tr>
   115     *    <tr><td colspan="6"> Definitions: <br />
   116     *       <ul>
   117     *         <li> <b>Hwi</b>: API is callable from a Hwi thread. </li>
   118     *         <li> <b>Swi</b>: API is callable from a Swi thread. </li>
   119     *         <li> <b>Task</b>: API is callable from a Task thread. </li>
   120     *         <li> <b>Main</b>: API is callable during any of these phases: </li>
   121     *           <ul>
   122     *             <li> In your module startup after this module is started
   123     *    (e.g. HeapMem_Module_startupDone() returns TRUE). </li>
   124     *             <li> During xdc.runtime.Startup.lastFxns. </li>
   125     *             <li> During main().</li>
   126     *             <li> During BIOS.startupFxns.</li>
   127     *           </ul>
   128     *         <li> <b>Startup</b>: API is callable during any of these phases:</li>
   129     *           <ul>
   130     *             <li> During xdc.runtime.Startup.firstFxns.</li>
   131     *             <li> In your module startup before this module is started
   132     *    (e.g. HeapMem_Module_startupDone() returns FALSE).</li>
   133     *           </ul>
   134     *       <li> <b>*</b> : Assuming blocking Heap is used for creation. </li>
   135     *       <li> <b>**</b>: Assuming GateMutex is used as HeapMem's Gate. </li>
   136     *       <li> <b>+</b> : Cannot use HeapMem object while it is being
   137     *    restored. </li>
   138     *       </ul>
   139     *    </td></tr>
   140     *
   141     *  </table>
   142     *  @p
   143     */
   144    @Gated
   145    module HeapMem inherits xdc.runtime.IHeap {
   146    
   147        /*! @_nodoc */
   148        @XmlDtd
   149        metaonly struct BasicView {
   150            String            label;
   151            Ptr               buf;
   152            SizeT             minBlockAlign;
   153            String            sectionName;
   154        }
   155    
   156        /*! @_nodoc */
   157        @XmlDtd
   158        metaonly struct DetailedView {
   159            String            label;
   160            Ptr               buf;
   161            SizeT             minBlockAlign;
   162            String            sectionName;
   163            Memory.Size       totalSize;
   164            Memory.Size       totalFreeSize;
   165            Memory.Size       largestFreeSize;
   166        }
   167    
   168        /*!
   169         *  ======== FreeBlockView ========
   170         *  @_nodoc
   171         */
   172        metaonly struct FreeBlockView {
   173            String         Address;
   174            String         size;
   175            String  next;
   176            String         status;
   177        }
   178    
   179        /*! @_nodoc */
   180        @Facet
   181        metaonly config ViewInfo.Instance rovViewInfo =
   182            ViewInfo.create({
   183                viewMap: [
   184                [
   185                    'Basic',
   186                    {
   187                        type: ViewInfo.INSTANCE,
   188                        viewInitFxn: 'viewInitBasic',
   189                        structName: 'BasicView'
   190                    }
   191                ],
   192                [
   193                    'Detailed',
   194                    {
   195                        type: ViewInfo.INSTANCE,
   196                        viewInitFxn: 'viewInitDetailed',
   197                        structName: 'DetailedView'
   198                    }
   199                ],
   200                [
   201                    'FreeList',
   202                    {
   203                        type: ViewInfo.INSTANCE_DATA,
   204                        viewInitFxn: 'viewInitData',
   205                        structName: 'FreeBlockView'
   206                    }
   207                ]
   208                ]
   209            });
   210    
   211    
   212        /*!
   213         *  ======== ExtendedStats ========
   214         *  Stat structure for the HeapMem_getExtendedStats function
   215         *
   216         *  @field(buf)           Base address of the internal buffer.
   217         *                        This may be different from the original buf
   218         *                        parameter due to alignment requirements.
   219         *  @field(size)          Size of the internal buffer.
   220         *                        This may be different from the original size
   221         *                        parameter due to alignment requirements.
   222         */
   223        struct ExtendedStats {
   224            Ptr   buf;
   225            SizeT size;
   226        }
   227    
   228        /*!
   229         *  ======== A_zeroBlock ========
   230         *  Assert raised when a block of size 0 is requested
   231         *
   232         *  This error can also be raised if the requested size wraps
   233         *  the contents of a SizeT type when it is adjusted for a minimum 
   234         *  alignment. For example, when SizeT is 16-bits and a size request
   235         *  is made for 0xFFFB.
   236         */
   237        config xdc.runtime.Assert.Id A_zeroBlock =
   238            {msg: "A_zeroBlock: Cannot allocate size 0"};
   239    
   240        /*!
   241         *  ======== A_heapSize ========
   242         *  Assert raised when the requested heap size is too small
   243         */
   244        config xdc.runtime.Assert.Id A_heapSize =
   245            {msg: "A_heapSize: Requested heap size is too small"};
   246    
   247        /*!
   248         *  ======== A_align ========
   249         *  Assert raised when the requested alignment is not a power of 2
   250         */
   251        config xdc.runtime.Assert.Id A_align =
   252            {msg: "A_align: Requested align is not a power of 2"};
   253    
   254        /*!
   255         *  ======== E_memory ========
   256         *  Raised when requested size exceeds largest free block
   257         */
   258        config Error.Id E_memory = {msg: "out of memory: handle=0x%x, size=%u"};
   259    
   260        /*!
   261         *  ======== A_invalidFree ========
   262         *  Assert raised when the free detects that an invalid addr or size
   263         *
   264         *  This could arise when multiple frees are done on the same buffer or
   265         *  if corruption occurred.
   266         *
   267         *  This also could occur when an alloc is made with size N and the
   268         *  free for this buffer specifies size M where M > N. Note: not every
   269         *  case is detectable.
   270         *
   271         *  This assert can also be caused when passing an invalid addr to free
   272         *  or if the size is causing the end of the buffer to be
   273         *  out of the expected range.
   274         */
   275        config xdc.runtime.Assert.Id A_invalidFree =
   276            {msg: "A_invalidFree: Invalid free"};
   277    
   278        /*!
   279         *  ======== primaryHeapBaseAddr ========
   280         *  Base address of the 'Primary Heap' buffer.
   281         *
   282         *  HeapMem allows one Heap instance to be defined who's heap
   283         *  memory is defined by symbols in the linker command file.
   284         *  This singular Heap instance is referred to as the 'Primary Heap'.
   285         *
   286         *  see {@link #primaryHeapEndAddr}
   287         *  see {@link #usePrimaryHeap}
   288         *
   289         *  The following example will create a HeapMem instance whose
   290         *  size and buffer will be determined at runtime based on the
   291         *  values of the symbols `__heap_start__` and
   292         *  `__heap_end__`. It is assumed the user will define these
   293         *  symbols in their linker command file.
   294         *
   295         *  @p(code)
   296         *  var HeapMem = xdc.useModule('ti.sysbios.heaps.HeapMem');
   297         *
   298         *  HeapMem.primaryHeapBaseAddr = "&__heap_start__";
   299         *  HeapMem.primaryHeapEndAddr = "&__heap_end__";
   300         *
   301         *  var heapMemParams = new HeapMem.Params;
   302         *  heapMemParams.usePrimaryHeap = true;
   303         *
   304         *  var heap0 = HeapMem.create(heapMemParams);
   305         *  @p
   306         */
   307        config Char *primaryHeapBaseAddr = null;
   308    
   309        /*!
   310         *  ======== primaryHeapEndAddr ========
   311         *  End address of the 'Primary Heap' buffer, plus one.
   312         *
   313         *  see {@link #primaryHeapBaseAddr}
   314         *  see {@link #usePrimaryHeap}
   315         *
   316         *  @p(code)
   317         *  HeapMem.primaryHeapEndAddr = "&__heap_end__";
   318         *  @p
   319         */
   320        config Char *primaryHeapEndAddr = null;
   321    
   322        /*!
   323         *  ======== enter ========
   324         *  @_nodoc
   325         *  Enter the module's gate. This is needed to support
   326         *  the legacy MEM module. It allows MEM to use the same
   327         *  gate for thread-safety.
   328         */
   329        IArg enter();
   330    
   331        /*!
   332         *  ======== leave ========
   333         *  @_nodoc
   334         *  Leave the module's gate. This is needed to support
   335         *  the legacy MEM module. It allows MEM to use the same
   336         *  gate for thread-safety.
   337         */
   338        Void leave(IArg key);
   339    
   340    instance:
   341    
   342       /*!
   343        *  ======== usePrimaryHeap ========
   344        *  Use {@link #primaryHeapBaseAddr} and {@link #primaryHeapEndAddr}
   345        *  to define the Heap buffer managed by this static instance.
   346        *
   347        *  @a(warning)
   348        *  This instance parameter only exists for statically defined
   349        *  HeapMem objects and can only be set to true in the creation
   350        *  of one static HeapMem object!
   351        */
   352       metaonly config Bool usePrimaryHeap = false;
   353    
   354       /*!
   355        *  ======== align ========
   356        *  Alignment of the buffer being managed by this heap instance
   357        *
   358        *  In the static HeapMem.create() call, the buffer allocated for the
   359        *  HeapMem instance will have the alignment specified by this parameter.
   360        *
   361        *  In the dynamic case, the client must supply the buffer, so it is the
   362        *  client's responsibility to manage the buffer's alignment, and there is
   363        *  no 'align' parameter.
   364        *
   365        *  The specified alignment must be a power of 2.
   366        *
   367        *  HeapMem requires that the buffer be aligned on a target-specific minimum
   368        *  alignment, and will adjust (round up) the requested alignment as
   369        *  necessary to satisfy this requirement.
   370        *
   371        *  The default alignment is 0.
   372        */
   373       metaonly config SizeT align = 0;
   374       
   375       /*!
   376        *  ======== minBlockAlign ========
   377        *  Minimum alignment for each block allocated
   378        *
   379        *  This parameter dictates the minimum alignment for each
   380        *  block that is allocated. If an alignment request of greater than
   381        *  minBlockAlign is made in the alloc, it will be honored. If an
   382        *  alignment request of less than minBlockAlign is made, the request will
   383        *  be ignored and minBlockAlign will be used.
   384        *    
   385        *  @p(code)
   386        *  HeapMem_Params_init(&prms);
   387        *  prms.minBlockAlign = 32;
   388        *  handle = HeapMem_create(&prms, &eb);
   389        *  ...
   390        *  // buf will be aligned on a 32 MAU boundary
   391        *  buf = Memory_alloc(HeapMem_Handle_upCast(handle), SIZE, 8, &eb);
   392        *  
   393        *  // buf will be aligned on a 64 MAU boundary    
   394        *  buf = Memory_alloc(HeapMem_Handle_upCast(handle), SIZE, 64, &eb);
   395        *  @p
   396        *
   397        *  The default alignment is 0 (which means this parameter is ignored).
   398        */
   399       config SizeT minBlockAlign = 0;
   400    
   401       /*!
   402        *  ======== sectionName ========
   403        *  Section name for the buffer managed by the instance
   404        *
   405        *  The default section is the 'dataSection' in the platform.
   406        */
   407       metaonly config String sectionName = null;
   408    
   409       /*!
   410        *  ======== buf ========
   411        *  Buffer being managed by this heap instance
   412        *
   413        *  This parameter is ignored in the static HeapMem.create() call. It is a
   414        *  required parameter in the dynamic HeapMem_create() call.
   415        *
   416        *  HeapMem requires that the buffer be aligned on a target-specific minimum
   417        *  alignment, and will adjust the buffer's start address and size as
   418        *  necessary to satisfy this requirement.
   419        */
   420       config Ptr buf = 0;
   421    
   422       /*!
   423        *  ======== size ========
   424        *  Size of buffer being managed by this heap instance
   425        *
   426        *  The usable size may be smaller depending on alignment requirements.
   427        */
   428       config Memory.Size size = 0;
   429    
   430        /*!
   431         *  ======== alloc ========
   432         *
   433         *  @HeapMem
   434         *  The actual block returned may be larger than requested to satisfy
   435         *  alignment requirements
   436         *
   437         *  HeapMem_alloc() will lock the heap using the HeapMem Gate while it
   438         *  traverses the list of free blocks to find a large enough block for
   439         *  the request.
   440         *
   441         *  HeapMem_alloc() should not be called directly.  Application code
   442         *  should use Memory_alloc() with a HeapMem_Handle as the first
   443         *  parameter.  Among other things, Memory_alloc() makes sure that the
   444         *  alignment parameter is greater than or equal to the maximum alignment
   445         *  required for data structures for a given C compiler (8 bytes in many
   446         *  cases). HeapMem_alloc() may crash if you pass a smaller alignment.
   447         *
   448         *  Guidelines for using large heaps and multiple alloc() calls.
   449         *  @p(blist)
   450         *          - If possible, allocate larger blocks first. Previous
   451         *            allocations of small memory blocks can reduce the size
   452         *            of the blocks available for larger memory allocations.
   453         *          - Realize that alloc() can fail even if the heap contains a
   454         *            sufficient absolute amount of unallocated space. This is
   455         *            because the largest free memory block may be smaller than
   456         *            total amount of unallocated memory.
   457         *  @p
   458         */
   459        override Ptr alloc(SizeT size, SizeT align, xdc.runtime.Error.Block *eb);
   460    
   461        /*!
   462         *  ======== free ========
   463         *
   464         *  @HeapMem
   465         *  free() places the memory block specified by addr and size back into the
   466         *  free pool of the heap specified. The newly freed block is combined with
   467         *  any adjacent free blocks. The space is then available for further
   468         *  allocation by alloc().
   469         *
   470         *  free() will lock the heap using the HeapMem Gate, if one is specified
   471         *  using 'HeapMem.common$.gate'.
   472         */
   473        override Void free(Ptr block, SizeT size);
   474    
   475        /*!
   476         *  ======== isBlocking ========
   477         *
   478         *  @HeapMem
   479         *  This function queries the gate (as specified by 'HeapMem.common$.gate')
   480         *  to determine if the alloc/free can be blocking.
   481         */
   482        override Bool isBlocking();
   483    
   484        /*!
   485         *  ======== getStats ========
   486         *
   487         *  @HeapMem
   488         *  getStats() will lock the heap using the HeapMem Gate while it retrieves
   489         *  the HeapMem's statistics.
   490         *
   491         *  The returned totalSize reflects the usable size of the buffer, not
   492         *  necessarily the size specified during create.
   493         */
   494        override Void getStats(xdc.runtime.Memory.Stats *stats);
   495    
   496    
   497        /*!
   498         *  ======== restore ========
   499         *  Restores an instance to its original created state
   500         *
   501         *  This function restores a static or dynamically created instance to
   502         *  its original created state. Any memory previously allocated from the
   503         *  heap is no longer valid after this API is called. This function
   504         *  does not check whether there is allocated memory or not.
   505         */
   506        Void restore();
   507    
   508        /*!
   509         *  ======== getExtendedStats ========
   510         *  Retrieves the extended statistics for a HeapMem instance
   511         *
   512         *  This function retrieves the extended statistics for a HeapMem instance.
   513         *  It does not retrieve the standard xdc.runtime.Memory.Stats information.
   514         *
   515         *  @param(stats)  Location for the returned extended statistics.
   516         */
   517        Void getExtendedStats(ExtendedStats *stats);
   518    
   519    internal:   /* not for client use */
   520    
   521        /*! 
   522         *  ======== init ========
   523         *  Initialize instance at runtime
   524         *
   525         *  This function is plugged as a Startup.firstFxn so that the
   526         *  HeapMem objects are ready and usable by malloc() and 
   527         *  Memory_alloc() by the time the module startup functions
   528         *  get called so that any calls to atexit(), which in some targets
   529         *  invokes malloc(), will be handled cleanly.
   530         */
   531        Void init();
   532    
   533        /*! 
   534         *  ======== initPrimary ========
   535         *  Initialize instance at runtime
   536         *
   537         *  Same as 'init' but supports the use of 'HeapMem.primaryHeapBaseAddress'.
   538         */
   539        Void initPrimary();
   540    
   541        /* Required alignment. Must be a power of 2 */
   542        config SizeT reqAlign;
   543    
   544        /* Header maintained at the lower address of every free block */
   545        struct Header {
   546            Header *next;
   547            Memory.Size size;
   548        };
   549    
   550        struct Instance_State {
   551            xdc.runtime.Memory.Size align;
   552            Char                    buf[];      /* The heap used by HeapMem. */
   553            Header                  head;       /* First free block pointer.
   554                                                 * The size field will be used
   555                                                 * to store original heap size.
   556                                                 */
   557            SizeT                   minBlockAlign;
   558        };
   559    }
   560